Merge branch 'CHERI' into pdr32-wip
This commit is contained in:
10
README.md
10
README.md
@@ -126,11 +126,17 @@ Inc. for more information.
|
||||
----------------------------------------------------------------
|
||||
## Build Instructions
|
||||
|
||||
First clone this repository and then inside the repository initialize the submodules:
|
||||
|
||||
$ git clone git@github.com:CTSRD-CHERI/Toooba.git
|
||||
$ cd Toooba
|
||||
$ git submodule update --init --recursive
|
||||
|
||||
### Dependencies
|
||||
|
||||
Build the Bluespec Compiler `bsc` from [this repository](https://github.com/B-Lang-org/bsc)
|
||||
Build the Bluespec Compiler `bsc` from [this repository](https://github.com/B-Lang-org/bsc). You will also need set the `$BLUESPECDIR` to the `lib` folder of your `bsc` install. By default this is located in `inst/lib` directory inside your bsc repo. Also, make sure to add the `inst/bin` directory to your `$PATH` environment variable.
|
||||
|
||||
You need Verilator with version 3.922 or later. You can build any version of Verilator from [this repository](https://github.com/verilator/verilator/releases).
|
||||
You need Verilator with version 3.922 or later. You can build any version of Verilator from [this repository](https://github.com/verilator/verilator/releases) and follow the build instructions [on the official website](https://www.veripool.org/projects/verilator/wiki/Installing).
|
||||
|
||||
$ verilator --version
|
||||
Verilator 3.922 2018-03-17 rev verilator_3_920-32-gdf3d1a4
|
||||
|
||||
Submodule libs/cheri-cap-lib updated: dd24b7672b...3bb13f1c87
@@ -1025,6 +1025,10 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
default: return 0;
|
||||
endcase);
|
||||
end
|
||||
tagged CapException .ce: begin
|
||||
cause_code = pack(CHERIFault);
|
||||
// populate CHERI cause register.
|
||||
end
|
||||
tagged Interrupt .i: begin
|
||||
cause_code = zeroExtend(pack(i));
|
||||
cause_interrupt = 1;
|
||||
|
||||
@@ -53,7 +53,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
Bits#(childT, b__),
|
||||
FShow#(ToMemMsg#(idT, childT)),
|
||||
FShow#(MemRsMsg#(idT, childT)),
|
||||
Add#(SizeOf#(Line), 0, 512)); // assert Line sz = 512
|
||||
Add#(SizeOf#(Line), 0, TAdd#(512, 4))); // assert Line sz = 512 + 4 tags
|
||||
|
||||
// Verbosity: 0: quiet; 1: LLC transactions; 2: loop detail
|
||||
Integer verbosity = 0;
|
||||
@@ -141,7 +141,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
Reg #(Bit #(3)) rg_rd_rsp_beat <- mkReg (0);
|
||||
|
||||
FIFOF #(LdMemRq #(idT, childT)) f_pending_reads <- mkFIFOF;
|
||||
Reg #(Bit #(512)) rg_cline <- mkRegU;
|
||||
Reg #(CLine) rg_cline <- mkRegU;
|
||||
|
||||
rule rl_handle_read_req (llc.toM.first matches tagged Ld .ld
|
||||
&&& (ctr_wr_rsps_pending.value == 0));
|
||||
@@ -180,11 +180,14 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
end
|
||||
|
||||
// Shift next 64 bits from fabric into the cache line being assembled
|
||||
let new_cline = { mem_rsp.rdata, rg_cline [511:64] };
|
||||
let new_cline_tag = { mem_rsp.ruser, pack(rg_cline.tag) [3:1] };
|
||||
let new_cline_data = { mem_rsp.rdata, pack(rg_cline.data) [511:64] };
|
||||
let new_cline = CLine { tag: rg_rd_rsp_beat[0] == 0 ? unpack(new_cline_tag) : rg_cline.tag
|
||||
, data: unpack(new_cline_data) };
|
||||
|
||||
if (rg_rd_rsp_beat == 7) begin
|
||||
let ldreq <- pop (f_pending_reads);
|
||||
MemRsMsg #(idT, childT) resp = MemRsMsg {data: unpack (new_cline),
|
||||
MemRsMsg #(idT, childT) resp = MemRsMsg {data: new_cline,
|
||||
child: ldreq.child,
|
||||
id: ldreq.id};
|
||||
|
||||
@@ -214,11 +217,11 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
end
|
||||
|
||||
Addr line_addr = { wb.addr [63:6], 6'h0 }; // Addr of containing cache line
|
||||
Line line_data = wb.data;
|
||||
Vector #(8, Bit #(8)) line_bes = unpack (pack (wb.byteEn));
|
||||
Vector #(8, Bit #(64)) line_data = unpack(pack(wb.data.data));
|
||||
|
||||
Addr offset = zeroExtend ( { rg_wr_req_beat, 3'b_000 } ); // Addr offset of 64b word for this beat
|
||||
Bit #(64) data64 = line_data [rg_wr_req_beat];
|
||||
Bit #(64) data64 = line_data[rg_wr_req_beat];
|
||||
Bit #(8) strb8 = line_bes [rg_wr_req_beat];
|
||||
fa_fabric_send_write_req (line_addr | offset, strb8, data64);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
// Copyright (c) 2018 Massachusetts Institute of Technology
|
||||
// Portions (c) 2019-2020 Bluespec, Inc.
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -9,10 +9,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
|
||||
@@ -171,7 +171,6 @@ function Bit #(64) fn_amo_op (Bit #(2) sz, // encodes data size (.W or
|
||||
Bit #(64) w1 = fn_extract_and_extend_bytes (sz, addr, ld_val);
|
||||
Bit #(64) w2 = fn_extract_and_extend_bytes (sz, addr, st_val);
|
||||
|
||||
|
||||
// Do AMO op
|
||||
Int #(64) i1 = unpack (w1); // Signed, for signed ops
|
||||
Int #(64) i2 = unpack (w2); // Signed, for signed ops
|
||||
@@ -257,13 +256,13 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
Reg #(CoreId) reqCore <- mkRegU;
|
||||
Reg #(MMIOFunc) reqFunc <- mkRegU;
|
||||
Reg #(AmoFunc) reqAmofunc <- mkRegU;
|
||||
Reg #(ByteEn) reqBE <- mkRegU;
|
||||
Reg #(MemDataByteEn) reqBE <- mkRegU;
|
||||
Reg #(Bit #(2)) reqSz <- mkRegU;
|
||||
Reg #(Data) reqData <- mkRegU;
|
||||
Reg #(MemTaggedData) reqData <- mkRegU;
|
||||
|
||||
// For inst fetch, we need more bookkeepings
|
||||
// offset of the requested inst within a Data
|
||||
Reg#(DataInstOffset) instSel <- mkRegU;
|
||||
Reg#(MemDataInstOffset) instSel <- mkRegU;
|
||||
// the current superscaler way being fetched
|
||||
Reg#(SupWaySel) fetchingWay <- mkRegU;
|
||||
// the already fetched insts
|
||||
@@ -280,7 +279,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
|
||||
// in case of AMO on mtime and mtimecmp, resp may be sent after waiting for
|
||||
// CRs, we record the AMO resp at processing time
|
||||
Reg#(Data) amoResp <- mkRegU;
|
||||
Reg#(MemTaggedData) amoResp <- mkRegU;
|
||||
|
||||
// we increment mtime periodically
|
||||
Reg#(Bit#(TLog#(CyclesPerTimeInc))) cycle <- mkReg(0);
|
||||
@@ -474,7 +473,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
cores[lower_core].pRq.enq(MMIOPRq {
|
||||
target: MSIP,
|
||||
func: reqFunc,
|
||||
data: truncate(reqData)
|
||||
data: fromMemTaggedData(reqData)
|
||||
});
|
||||
waitLowerMSIPCRs <= Valid (lower_core);
|
||||
waitUpperMSIPCRs <= Invalid;
|
||||
@@ -484,7 +483,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
cores[upper_core].pRq.enq(MMIOPRq {
|
||||
target: MSIP,
|
||||
func: reqFunc,
|
||||
data: truncate(reqData)
|
||||
data: fromMemTaggedData(reqData)
|
||||
});
|
||||
waitLowerMSIPCRs <= Valid (upper_core);
|
||||
waitUpperMSIPCRs <= Invalid;
|
||||
@@ -507,14 +506,14 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
cores[lower_core].pRq.enq(MMIOPRq {
|
||||
target: MSIP,
|
||||
func: reqFunc,
|
||||
data: zeroExtend(reqData[0])
|
||||
data: zeroExtend(pack(reqData.data)[0])
|
||||
});
|
||||
end
|
||||
if(upper_en) begin
|
||||
cores[upper_core].pRq.enq(MMIOPRq {
|
||||
target: MSIP,
|
||||
func: reqFunc,
|
||||
data: zeroExtend(reqData[32])
|
||||
data: zeroExtend(pack(reqData.data)[32])
|
||||
});
|
||||
end
|
||||
state <= WaitResp;
|
||||
@@ -542,11 +541,11 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
end
|
||||
state <= SelectReq;
|
||||
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
|
||||
valid: True,
|
||||
// for AMO, resp data should be signExtend(lower_data). However,
|
||||
// lower_data is just 1 or 0, and upper_data is always 0, so we
|
||||
// don't need to do signExtend.
|
||||
data: {upper_data, lower_data}
|
||||
valid: True,
|
||||
// for AMO, resp data should be signExtend(lower_data). However,
|
||||
// lower_data is just 1 or 0, and upper_data is always 0, so we
|
||||
// don't need to do signExtend.
|
||||
data: toMemTaggedData({upper_data, lower_data})
|
||||
}));
|
||||
if(verbosity > 0) begin
|
||||
$display("[Platform - msip done] lower %x, upper %x",
|
||||
@@ -557,21 +556,21 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
function Data getWriteData(Data orig);
|
||||
if(reqFunc matches tagged Amo .amoFunc) begin
|
||||
// amo
|
||||
Bool doubleWord = reqBE[4] && reqBE[0];
|
||||
Bool upper32 = reqBE[4] && !reqBE[0];
|
||||
let amoInst = AmoInst {
|
||||
func: amoFunc,
|
||||
doubleWord: doubleWord,
|
||||
width: reqBE[4] && reqBE[0] ? DWord : Word,
|
||||
aq: False,
|
||||
rl: False
|
||||
};
|
||||
return amoExec(amoInst, orig, reqData, upper32);
|
||||
let res = amoExec(amoInst, {0, pack(reqBE[4] && !reqBE[0])},
|
||||
toMemTaggedData(orig), reqData);
|
||||
return res.data[0];
|
||||
end
|
||||
else begin
|
||||
// normal store
|
||||
Vector#(NumBytes, Bit#(8)) data = unpack(orig);
|
||||
Vector#(NumBytes, Bit#(8)) wrVec = unpack(reqData);
|
||||
for(Integer i = 0; i < valueof(NumBytes); i = i+1) begin
|
||||
Vector#(DataBytes, Bit#(8)) data = unpack(orig);
|
||||
Vector#(DataBytes, Bit#(8)) wrVec = fromMemTaggedData(reqData);
|
||||
for(Integer i = 0; i < valueof(DataBytes); i = i+1) begin
|
||||
if(reqBE[i]) begin
|
||||
data[i] = wrVec[i];
|
||||
end
|
||||
@@ -621,7 +620,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
if(reqFunc == Ld) begin
|
||||
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
|
||||
valid: True,
|
||||
data: oldMTimeCmp
|
||||
data: toMemTaggedData(oldMTimeCmp)
|
||||
}));
|
||||
state <= SelectReq;
|
||||
if(verbosity > 0) begin
|
||||
@@ -634,7 +633,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
let newData = getWriteData(oldMTimeCmp);
|
||||
mtimecmp[offset] <= newData;
|
||||
// get and record amo resp
|
||||
let respData = getAmoResp(oldMTimeCmp);
|
||||
let respData = toMemTaggedData(getAmoResp(oldMTimeCmp));
|
||||
amoResp <= respData;
|
||||
// check changes to MTIP
|
||||
if(newData <= mtime && !mtip[offset]) begin
|
||||
@@ -707,7 +706,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
end
|
||||
else if(reqFunc == Ld) begin
|
||||
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
|
||||
valid: True, data: mtime
|
||||
valid: True, data: toMemTaggedData(mtime)
|
||||
}));
|
||||
state <= SelectReq;
|
||||
if(verbosity > 0) begin
|
||||
@@ -720,7 +719,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
let newData = getWriteData(mtime);
|
||||
mtime <= newData;
|
||||
// get and record AMO resp
|
||||
let respData = getAmoResp(mtime);
|
||||
let respData = toMemTaggedData(getAmoResp(mtime));
|
||||
amoResp <= respData;
|
||||
// check change in MTIP
|
||||
Vector#(CoreNum, Bool) changeMTIP = replicate(False);
|
||||
@@ -809,7 +808,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
else if(reqFunc == Ld) begin
|
||||
resp.valid = True;
|
||||
if(toHostQ.notEmpty) begin
|
||||
resp.data = toHostQ.first;
|
||||
resp.data = toMemTaggedData(toHostQ.first);
|
||||
end
|
||||
else begin
|
||||
resp.data = 0;
|
||||
@@ -860,7 +859,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
else if(reqFunc == Ld) begin
|
||||
resp.valid = True;
|
||||
if(fromHostQ.notEmpty) begin
|
||||
resp.data = fromHostQ.first;
|
||||
resp.data = toMemTaggedData(fromHostQ.first);
|
||||
end
|
||||
else begin
|
||||
resp.data = 0;
|
||||
@@ -950,10 +949,12 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
else begin
|
||||
// Do the AMO op on the loaded value and the store value
|
||||
let ld_val = dprs.data;
|
||||
let new_st_val = fn_amo_op (reqSz, reqAmofunc, addr, ld_val, reqData);
|
||||
let new_st_val = fn_amo_op ( reqSz, reqAmofunc, addr
|
||||
, fromMemTaggedData(ld_val)
|
||||
, fromMemTaggedData(reqData));
|
||||
|
||||
// Write back new st_val to fabric
|
||||
let req = MMIOCRq {addr:addr, func:tagged St, byteEn:reqBE, data:new_st_val};
|
||||
let req = MMIOCRq {addr:addr, func:tagged St, byteEn:reqBE, data:toMemTaggedData(new_st_val)};
|
||||
mmio_fabric_adapter_core_side.request.put (req);
|
||||
|
||||
let prs = tagged DataAccess (MMIODataPRs { valid: True, data: ld_val });
|
||||
@@ -1020,7 +1021,6 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
|
||||
else begin
|
||||
// No access fault
|
||||
let data = dprs.data;
|
||||
|
||||
SupWaySel maxWay = 0;
|
||||
if(reqFunc matches tagged Inst .w) begin
|
||||
@@ -1028,7 +1028,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
end
|
||||
|
||||
// View Data as a vector of instructions
|
||||
Vector#(DataSzInst, Instruction) instVec = unpack(data);
|
||||
Vector#(MemDataSzInst, Instruction) instVec = fromMemTaggedData(dprs.data);
|
||||
// extract inst from resp data
|
||||
Instruction inst = instVec[instSel];
|
||||
// check whether we are done or not
|
||||
|
||||
@@ -32,6 +32,7 @@ import CreditCounter :: *;
|
||||
// ----------------
|
||||
// From MIT RISCY-OOO
|
||||
|
||||
import Types :: *;
|
||||
import ProcTypes :: *;
|
||||
|
||||
// ----------------
|
||||
@@ -68,6 +69,7 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
|
||||
FIFOF #(MMIOCRq) f_reqs_from_core <- mkFIFOF;
|
||||
FIFOF #(MMIODataPRs) f_rsps_to_core <- mkFIFOF;
|
||||
Reg#(Fabric_Addr) read_req_addr <- mkRegU;
|
||||
|
||||
SoC_Map_IFC soc_map <- mkSoC_Map; // for m_is_IO_addr
|
||||
|
||||
@@ -99,6 +101,7 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
aruser: fabric_default_aruser};
|
||||
|
||||
master_xactor.slave.ar.put(mem_req_rd_addr);
|
||||
read_req_addr <= addr;
|
||||
|
||||
// Debugging
|
||||
if (cfg_verbosity > 0) begin
|
||||
@@ -180,7 +183,7 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
fa_fabric_send_read_req (req.addr);
|
||||
else begin
|
||||
let rsp = MMIODataPRs {valid: False,
|
||||
data: req.addr}; // For debugging convenience only
|
||||
data: toMemTaggedData(req.addr)}; // For debugging convenience only
|
||||
f_rsps_to_core.enq (rsp);
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_handle_read_req: unmapped IO address; returning error response",
|
||||
@@ -194,6 +197,7 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
|
||||
rule rl_handle_read_rsps;
|
||||
let mem_rsp <- get(master_xactor.slave.r);
|
||||
dynamicAssert(mem_rsp.rlast, "TODO, implement multi-flit transactions");
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_handle_read_rsps ", cur_cycle);
|
||||
@@ -205,8 +209,10 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
$display (" ", fshow (mem_rsp));
|
||||
end
|
||||
|
||||
let newData = MemTaggedData { tag: False
|
||||
, data: unpack(zeroExtend(mem_rsp.rdata) << ((read_req_addr[3] == 1) ? 64 : 0))};
|
||||
let rsp = MMIODataPRs {valid: (mem_rsp.rresp == OKAY),
|
||||
data: mem_rsp.rdata};
|
||||
data: newData };
|
||||
f_rsps_to_core.enq (rsp);
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
@@ -227,11 +233,12 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
// Technically the following check for legal IO addrs is not
|
||||
// necessary; the AXI4 fabric should return a DECERR for illegal
|
||||
// addrs; but not all AXI4 fabrics do the right thing.
|
||||
dynamicAssert(pack(req.byteEn)[15:8] == 0, "TODO, handle multiflit transactions");
|
||||
if (soc_map.m_is_IO_addr (req.addr))
|
||||
fa_fabric_send_write_req (req.addr, pack (req.byteEn), req.data);
|
||||
fa_fabric_send_write_req (req.addr, truncate(pack(req.byteEn)), fromMemTaggedData(req.data));
|
||||
else begin
|
||||
let rsp = MMIODataPRs {valid: False,
|
||||
data: req.addr}; // For debugging convenience only
|
||||
data: toMemTaggedData(req.addr)}; // For debugging convenience only
|
||||
f_rsps_to_core.enq (rsp);
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_handle_write_req: unmapped IO address; returning error response",
|
||||
|
||||
@@ -65,7 +65,7 @@ typedef enum {
|
||||
typedef struct {
|
||||
Bit #(6) cheri_exc_reg;
|
||||
CHERIException cheri_exc_code;
|
||||
} CSR_XCapCause deriving(Bits, FShow);
|
||||
} CSR_XCapCause deriving(Bits, Eq, FShow);
|
||||
|
||||
CSR_XCapCause noCapCause = CSR_XCapCause {cheri_exc_code: None,
|
||||
cheri_exc_reg: unpack(0)};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +8,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
|
||||
@@ -32,9 +32,9 @@ import GetPut::*;
|
||||
import ClientServer::*;
|
||||
|
||||
typedef enum {
|
||||
I = 2'd0,
|
||||
S = 2'd1,
|
||||
E = 2'd2,
|
||||
I = 2'd0,
|
||||
S = 2'd1,
|
||||
E = 2'd2,
|
||||
M = 2'd3
|
||||
} MESI deriving(Bits, Eq, FShow);
|
||||
typedef MESI Msi;
|
||||
@@ -79,54 +79,59 @@ typedef TDiv#(DataSz, 8) DataSzBytes;
|
||||
typedef TLog#(DataSzBytes) LgDataSzBytes;
|
||||
typedef Bit#(LgDataSzBytes) DataBytesOffset;
|
||||
|
||||
typedef TDiv#(MemDataSz, 8) MemDataSzBytes;
|
||||
typedef TLog#(MemDataSzBytes) LgMemDataSzBytes;
|
||||
typedef Bit#(LgMemDataSzBytes) MemDataBytesOffset;
|
||||
|
||||
typedef TDiv#(InstSz, 8) InstSzBytes;
|
||||
typedef TLog#(InstSzBytes) LgInstSzBytes;
|
||||
|
||||
// 64B cache line -- XXX same with parameters in CacheUtils.bsv
|
||||
typedef CacheUtils::LogCLineNumData LgLineSzData;
|
||||
typedef CacheUtils::LogCLineNumBytes LgLineSzBytes;
|
||||
typedef CacheUtils::LogCLineNumMemTaggedData LgLineSzData;
|
||||
typedef CacheUtils::LogCLineNumMemDataBytes LgLineSzBytes;
|
||||
typedef CacheUtils::CLineAddrSz LineAddrSz;
|
||||
typedef CacheUtils::CLineAddr LineAddr;
|
||||
|
||||
typedef CacheUtils::CLineNumData LineSzData;
|
||||
typedef CacheUtils::CLine Line;
|
||||
typedef CacheUtils::CLineDataSel LineDataOffset;
|
||||
typedef CacheUtils::CLineMemTaggedDataSel LineMemDataOffset;
|
||||
|
||||
typedef CacheUtils::CLineNumBytes LineSzBytes;
|
||||
typedef CacheUtils::CLineByteEn LineByteEn;
|
||||
typedef CacheUtils::CLineDataNumBytes LineSzBytes;
|
||||
typedef CacheUtils::CLineMemDataByteEn LineByteEn;
|
||||
typedef CacheUtils::CLineDataByteEn LineDataByteEn;
|
||||
|
||||
typedef TDiv#(LineSzBytes, InstSzBytes) LineSzInst;
|
||||
typedef Bit#(TLog#(LineSzInst)) LineInstOffset;
|
||||
|
||||
typedef Vector#(LineSzData, Data) Line;
|
||||
|
||||
function LineAddr getLineAddr(Addr addr) = truncateLSB(addr);
|
||||
|
||||
function LineDataOffset getLineDataOffset(Addr a);
|
||||
return truncate(a >> valueOf(LgDataSzBytes));
|
||||
endfunction
|
||||
|
||||
function LineMemDataOffset getLineMemDataOffset(Addr a);
|
||||
return truncate(a >> valueOf(LgMemDataSzBytes));
|
||||
endfunction
|
||||
|
||||
function LineInstOffset getLineInstOffset(Addr a);
|
||||
return truncate(a >> valueof(LgInstSzBytes));
|
||||
endfunction
|
||||
|
||||
function Line getUpdatedLine(Line curLine, LineByteEn wrBE, Line wrLine);
|
||||
Vector#(LineSzBytes, Bit#(8)) curVec = unpack(pack(curLine));
|
||||
Vector#(LineSzBytes, Bit#(8)) wrVec = unpack(pack(wrLine));
|
||||
function Bit#(8) getNewByte(Integer i);
|
||||
return wrBE[i] ? wrVec[i] : curVec[i];
|
||||
// handle data merge
|
||||
Vector#(LineSzBytes, Bit#(8)) newDataVec = mergeDataBE(curLine.data, wrLine.data, wrBE);
|
||||
// handle tag merge
|
||||
Vector#(CLineNumMemTaggedData, MemTag) curTagVec = curLine.tag;
|
||||
Vector#(CLineNumMemTaggedData, MemTag) wrTagVec = wrLine.tag;
|
||||
function MemTag getNewTag(Integer i);
|
||||
let res = curTagVec[i];
|
||||
if (pack(wrBE[i]) == ~0) res = wrTagVec[i];
|
||||
return res;
|
||||
endfunction
|
||||
Vector#(LineSzBytes, Bit#(8)) newVec = map(getNewByte, genVector);
|
||||
return unpack(pack(newVec));
|
||||
endfunction
|
||||
|
||||
function Data getUpdatedData(Data curData, ByteEn wrBE, Data wrData);
|
||||
Vector#(DataSzBytes, Bit#(8)) curVec = unpack(pack(curData));
|
||||
Vector#(DataSzBytes, Bit#(8)) wrVec = unpack(pack(wrData));
|
||||
function Bit#(8) getNewByte(Integer i);
|
||||
return wrBE[i] ? wrVec[i] : curVec[i];
|
||||
endfunction
|
||||
Vector#(DataSzBytes, Bit#(8)) newVec = map(getNewByte, genVector);
|
||||
return pack(newVec);
|
||||
Vector#(CLineNumMemTaggedData, MemTag) newTagVec = genWith(getNewTag);
|
||||
// compose updated line
|
||||
return CLine { tag: newTagVec
|
||||
, data: unpack(pack(newDataVec)) };
|
||||
endfunction
|
||||
|
||||
// calculate tag
|
||||
@@ -191,8 +196,8 @@ typedef struct {
|
||||
Msi toState;
|
||||
// below are detailed mem op
|
||||
MemOp op; // Ld, St, Lr, Sc, Amo
|
||||
ByteEn byteEn; // valid when op == Sc
|
||||
Data data; // valid when op == Sc/Amo
|
||||
MemDataByteEn byteEn; // valid when op == Sc
|
||||
MemTaggedData data; // valid when op == Sc/Amo
|
||||
AmoInst amoInst; // valid when op == Amo
|
||||
} ProcRq#(type idT) deriving(Bits, Eq, FShow);
|
||||
|
||||
@@ -201,8 +206,8 @@ interface L1ProcReq#(type idT);
|
||||
endinterface
|
||||
|
||||
interface L1ProcResp#(type idT);
|
||||
method Action respLd(idT id, Data resp);
|
||||
method Action respLrScAmo(idT id, Data resp);
|
||||
method Action respLd(idT id, MemTaggedData resp);
|
||||
method Action respLrScAmo(idT id, MemTaggedData resp);
|
||||
method ActionValue#(Tuple2#(LineByteEn, Line)) respSt(idT id);
|
||||
method Action evict(LineAddr a); // called when cache line is evicted
|
||||
endinterface
|
||||
@@ -371,7 +376,7 @@ endinterface
|
||||
|
||||
instance Connectable#(MemFifoServer#(idT, childT), MemFifoClient#(idT, childT));
|
||||
module mkConnection#(
|
||||
MemFifoServer#(idT, childT) server,
|
||||
MemFifoServer#(idT, childT) server,
|
||||
MemFifoClient#(idT, childT) client
|
||||
)(Empty);
|
||||
rule doCToM;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -392,7 +391,7 @@ module mkIBank#(
|
||||
|
||||
// function to get superscaler inst read result
|
||||
function resultT readInst(Line line, Addr addr);
|
||||
Vector#(LineSzInst, Instruction) instVec = unpack(pack(line));
|
||||
Vector#(LineSzInst, Instruction) instVec = unpack(pack(line.data));
|
||||
// the start offset for reading inst
|
||||
LineInstOffset startSel = getLineInstOffset(addr);
|
||||
// calculate the maximum inst count that could be read from line
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -189,7 +188,7 @@ 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);
|
||||
@@ -244,8 +243,8 @@ module mkL1Bank#(
|
||||
mshrIdx: n
|
||||
}));
|
||||
if (verbose)
|
||||
$display("%t L1 %m cRqTransfer_retry: ", $time,
|
||||
fshow(n), " ; ",
|
||||
$display("%t L1 %m cRqTransfer_retry: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req)
|
||||
);
|
||||
endrule
|
||||
@@ -258,7 +257,7 @@ module mkL1Bank#(
|
||||
cRqIdxT n <- cRqMshr.cRqTransfer.getEmptyEntryInit(r);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (L1PipeRqIn {
|
||||
addr: r.addr,
|
||||
addr: r.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
`ifdef PERF_COUNT
|
||||
@@ -266,7 +265,7 @@ module mkL1Bank#(
|
||||
incrReqCnt(r.op);
|
||||
`endif
|
||||
if (verbose)
|
||||
$display("%t L1 %m cRqTransfer_new: ", $time,
|
||||
$display("%t L1 %m cRqTransfer_new: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(r)
|
||||
);
|
||||
@@ -282,8 +281,8 @@ module mkL1Bank#(
|
||||
mshrIdx: n
|
||||
}));
|
||||
if (verbose)
|
||||
$display("%t L1 %m pRqTransfer: ", $time,
|
||||
fshow(n), " ; ",
|
||||
$display("%t L1 %m pRqTransfer: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req)
|
||||
);
|
||||
endrule
|
||||
@@ -348,8 +347,8 @@ module mkL1Bank#(
|
||||
cRqSlotT slot = cRqMshr.sendRsToP_cRq.getSlot(n);
|
||||
Maybe#(Line) data = cRqMshr.sendRsToP_cRq.getData(n);
|
||||
L1CRqState state = cRqMshr.sendRsToP_cRq.getState(n);
|
||||
doAssert(state == WaitNewTag,
|
||||
"send replacement resp to parent, state should be WaitNewTag"
|
||||
doAssert(state == WaitNewTag,
|
||||
"send replacement resp to parent, state should be WaitNewTag"
|
||||
);
|
||||
// send resp to parent
|
||||
cRsToPT resp = CRsMsg {
|
||||
@@ -370,9 +369,9 @@ module mkL1Bank#(
|
||||
// inform processor of line eviction
|
||||
procResp.evict(getLineAddr(resp.addr));
|
||||
if (verbose)
|
||||
$display("%t L1 %m sendRsToP: ", $time,
|
||||
fshow(rsToPIndexQ.first)," ; ",
|
||||
fshow(req), " ; ",
|
||||
$display("%t L1 %m sendRsToP: ", $time,
|
||||
fshow(rsToPIndexQ.first)," ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(resp)
|
||||
);
|
||||
endrule
|
||||
@@ -393,9 +392,9 @@ module mkL1Bank#(
|
||||
// inform processor of line eviction
|
||||
procResp.evict(getLineAddr(resp.addr));
|
||||
if (verbose)
|
||||
$display("%t L1 %m sendRsToP: ", $time,
|
||||
fshow(rsToPIndexQ.first), " ; ",
|
||||
fshow(req), " ; ",
|
||||
$display("%t L1 %m sendRsToP: ", $time,
|
||||
fshow(rsToPIndexQ.first), " ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(resp)
|
||||
);
|
||||
endrule
|
||||
@@ -415,10 +414,10 @@ module mkL1Bank#(
|
||||
};
|
||||
rqToPQ.enq(cRqToP);
|
||||
if (verbose)
|
||||
$display("%t L1 %m sendRqToP: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(slot), " ; ",
|
||||
$display("%t L1 %m sendRqToP: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(slot), " ; ",
|
||||
fshow(cRqToP)
|
||||
);
|
||||
`ifdef PERF_COUNT
|
||||
@@ -466,13 +465,13 @@ module mkL1Bank#(
|
||||
// TODO when we have MESI, cache state may also need update
|
||||
Line curLine = ram.line;
|
||||
Line newLine = curLine;
|
||||
LineDataOffset dataSel = getLineDataOffset(req.addr);
|
||||
LineMemDataOffset dataSel = getLineMemDataOffset(req.addr);
|
||||
case(req.op) matches
|
||||
Ld: begin
|
||||
procResp.respLd(req.id, curLine[dataSel]);
|
||||
procResp.respLd(req.id, getTaggedDataAt(curLine, dataSel));
|
||||
end
|
||||
Lr: begin
|
||||
procResp.respLrScAmo(req.id, curLine[dataSel]);
|
||||
procResp.respLrScAmo(req.id, getTaggedDataAt(curLine, dataSel));
|
||||
// set link addr
|
||||
linkAddr <= Valid (getLineAddr(req.addr));
|
||||
end
|
||||
@@ -483,11 +482,14 @@ module mkL1Bank#(
|
||||
// check Sc succeeds or not
|
||||
Bool succeed = linkAddr == Valid (getLineAddr(req.addr));
|
||||
// resp to proc
|
||||
Data respVal = succeed ? fromInteger(valueof(ScSuccVal)) : fromInteger(valueof(ScFailVal));
|
||||
MemTaggedData respVal = succeed ? fromInteger(valueof(ScSuccVal)) : fromInteger(valueof(ScFailVal));
|
||||
procResp.respLrScAmo(req.id, respVal);
|
||||
// calculate new data to write
|
||||
if(succeed) begin
|
||||
newLine[dataSel] = getUpdatedData(curLine[dataSel], req.byteEn, req.data);
|
||||
let taggedData = getTaggedDataAt(curLine, dataSel);
|
||||
let newTaggedData =
|
||||
mergeMemTaggedDataBE(taggedData, req.data, zeroExtend(pack(req.byteEn)));
|
||||
newLine = setTaggedDataAt( newLine, dataSel, newTaggedData);
|
||||
end
|
||||
// reset link addr
|
||||
linkAddr <= Invalid;
|
||||
@@ -548,16 +550,28 @@ module mkL1Bank#(
|
||||
// get line and sel
|
||||
Line curLine = ram.line;
|
||||
Line newLine = curLine;
|
||||
LineDataOffset dataSel = getLineDataOffset(req.addr);
|
||||
Bool upper32 = req.addr[2] == 1;
|
||||
Data curData = curLine[dataSel];
|
||||
LineMemDataOffset dataSel = getLineMemDataOffset(req.addr);
|
||||
MemTaggedData current = getTaggedDataAt(curLine, dataSel);
|
||||
Vector#(2, Bit#(64)) dwordData = current.data;
|
||||
Vector#(4, Bit#(32)) wordData = unpack(pack(current.data));
|
||||
Bit#(1) dwordIdx = req.addr[3];
|
||||
Bit#(2) wordIdx = req.addr[3:2];
|
||||
// resp processor
|
||||
Data resp = req.amoInst.doubleWord ? curData : signExtend(
|
||||
upper32 ? curData[63:32] : curData[31:0]
|
||||
);
|
||||
MemTaggedData resp = case (req.amoInst.width)
|
||||
QWord: current;
|
||||
DWord: MemTaggedData {
|
||||
tag: False,
|
||||
data: unpack(signExtend(dwordData[dwordIdx]))
|
||||
};
|
||||
Word: MemTaggedData {
|
||||
tag: False,
|
||||
data: unpack(signExtend(wordData[wordIdx]))
|
||||
};
|
||||
endcase;
|
||||
procResp.respLrScAmo(req.id, resp);
|
||||
// calculate new data to write
|
||||
newLine[dataSel] = amoExec(req.amoInst, curData, req.data, upper32);
|
||||
let newData = amoExec(req.amoInst, wordIdx, current, req.data);
|
||||
newLine = setTaggedDataAt(newLine, dataSel, newData);
|
||||
// deq pipeline or swap in successor
|
||||
pipeline.deqWrite(succ, RamData {
|
||||
info: CacheInfo {
|
||||
@@ -588,7 +602,7 @@ module mkL1Bank#(
|
||||
procRqT procRq = pipeOutCRq;
|
||||
if (verbose)
|
||||
$display("%t L1 %m pipelineResp: cRq: ", $time, fshow(n), " ; ", fshow(procRq));
|
||||
|
||||
|
||||
// find end of dependency chain
|
||||
Maybe#(cRqIdxT) cRqEOC = cRqMshr.pipelineResp.searchEndOfChain(procRq.addr);
|
||||
|
||||
@@ -634,10 +648,10 @@ module mkL1Bank#(
|
||||
// because cRq is not set to Depend when pRq invalidates it (pRq just directly resp)
|
||||
// and this func is only called when cs < toState (otherwise will hit)
|
||||
// because L1 has no children to wait for
|
||||
doAssert(!cSlot.waitP && !enoughCacheState(ram.info.cs, procRq.toState),
|
||||
doAssert(!cSlot.waitP && !enoughCacheState(ram.info.cs, procRq.toState),
|
||||
"waitP must be false and cs must not be enough"
|
||||
);
|
||||
// Thus we must send req to parent
|
||||
// Thus we must send req to parent
|
||||
// XXX first send to a temp indexQ to avoid conflict, then merge to rqToPIndexQ later
|
||||
rqToPIndexQ_pipelineResp.enq(n);
|
||||
// update mshr
|
||||
@@ -692,7 +706,7 @@ module mkL1Bank#(
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
|
||||
// function to set cRq to Depend, and make no further change to cache
|
||||
function Action cRqSetDepNoCacheChange;
|
||||
action
|
||||
@@ -1024,7 +1038,7 @@ module mkL1Bank#(
|
||||
};
|
||||
endmethod
|
||||
endinterface
|
||||
|
||||
|
||||
interface pRqStuck = pRqMshr.stuck;
|
||||
|
||||
`ifdef SECURITY
|
||||
@@ -1043,7 +1057,7 @@ module mkL1Bank#(
|
||||
`else
|
||||
noAction;
|
||||
`endif
|
||||
endmethod
|
||||
endmethod
|
||||
|
||||
method Data getPerfData(L1DPerfType t);
|
||||
return (case(t)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -47,7 +46,7 @@ export mkLLBank;
|
||||
// this also ensures that cache pipeline is never blocked
|
||||
// so we do not need to buffer mem resp that needs to refill cache
|
||||
|
||||
// XXX we need to maintain the invariant that
|
||||
// XXX we need to maintain the invariant that
|
||||
// at most 1 pRq sent to a child for an addr
|
||||
// and we have to wait for resp before sending anthoer one
|
||||
|
||||
@@ -220,7 +219,7 @@ 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);
|
||||
@@ -303,8 +302,8 @@ module mkLLBank#(
|
||||
mshrIdx: n
|
||||
}));
|
||||
if (verbose)
|
||||
$display("%t LL %m cRqTransfer_retry: ", $time,
|
||||
fshow(n), " ; ",
|
||||
$display("%t LL %m cRqTransfer_retry: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req)
|
||||
);
|
||||
endrule
|
||||
@@ -355,15 +354,15 @@ module mkLLBank#(
|
||||
cRqIndexT n <- cRqMshr.transfer.getEmptyEntryInit(cRq, Invalid);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (LLPipeCRqIn {
|
||||
addr: cRq.addr,
|
||||
addr: cRq.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
// change round robin
|
||||
flipPriorNewCRqSrc;
|
||||
if (verbose)
|
||||
$display("%t LL %m cRqTransfer_new_child: ", $time,
|
||||
$display("%t LL %m cRqTransfer_new_child: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(r), " ; ",
|
||||
fshow(r), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
endrule
|
||||
@@ -393,7 +392,7 @@ module mkLLBank#(
|
||||
rule cRqTransfer_new_dma(!cRqRetryIndexQ.notEmpty && newCRqSrc == Valid (Dma));
|
||||
rqFromDmaQ.deq;
|
||||
dmaRqT r = rqFromDmaQ.first;
|
||||
Bool write = r.byteEn != replicate(False);
|
||||
Bool write = r.byteEn != replicate(replicate(False));
|
||||
cRqT cRq = LLRq {
|
||||
addr: r.addr,
|
||||
fromState: I,
|
||||
@@ -407,15 +406,15 @@ module mkLLBank#(
|
||||
cRqIndexT n <- cRqMshr.transfer.getEmptyEntryInit(cRq, write ? Valid (r.data) : Invalid);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (LLPipeCRqIn {
|
||||
addr: cRq.addr,
|
||||
addr: cRq.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
// change round robin
|
||||
flipPriorNewCRqSrc;
|
||||
if (verbose)
|
||||
$display("%t LL %m cRqTransfer_new_dma: ", $time,
|
||||
$display("%t LL %m cRqTransfer_new_dma: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(r), " ; ",
|
||||
fshow(r), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
`ifdef PERF_COUNT
|
||||
@@ -468,7 +467,7 @@ module mkLLBank#(
|
||||
end
|
||||
`endif
|
||||
endrule
|
||||
|
||||
|
||||
// mem resp for child req, will refill cache, send it to pipeline
|
||||
(* descending_urgency = "mRsTransfer, cRsTransfer, cRqTransfer_retry, cRqTransfer_new_child, cRqTransfer_new_dma" *)
|
||||
`ifdef PERF_COUNT
|
||||
@@ -534,7 +533,7 @@ module mkLLBank#(
|
||||
cRqSlotT cSlot = cRqMshr.sendToM.getSlot(n);
|
||||
Maybe#(Line) data = cRqMshr.sendToM.getData(n);
|
||||
if (verbose)
|
||||
$display("%t LL %m sendToM: ", $time,
|
||||
$display("%t LL %m sendToM: ", $time,
|
||||
fshow(toMInfoQ.first), " ; ",
|
||||
fshow(cRq), " ; ",
|
||||
fshow(cSlot), " ; ",
|
||||
@@ -614,7 +613,7 @@ module mkLLBank#(
|
||||
else begin // do write back part
|
||||
toMemT msg = Wb (WbMemRs {
|
||||
addr: {cSlot.repTag, truncate(cRq.addr)},
|
||||
byteEn: replicate(True),
|
||||
byteEn: replicate(replicate(True)),
|
||||
data: validValue(data)
|
||||
});
|
||||
toMQ.enq(msg);
|
||||
@@ -646,7 +645,7 @@ module mkLLBank#(
|
||||
doAssert(isValid(data), "dma read req always has valid data");
|
||||
// send DMA resp
|
||||
doAssert(isRqFromDma(cRq.id), "cRq should be DMA req");
|
||||
doAssert(cRq.byteEn == replicate(False) && cRq.toState == S,
|
||||
doAssert(cRq.byteEn == replicate(replicate(False)) && cRq.toState == S,
|
||||
"cRq should be DMA read"
|
||||
);
|
||||
dmaRqIdT dmaId = getIdFromDma(cRq.id);
|
||||
@@ -669,7 +668,7 @@ module mkLLBank#(
|
||||
);
|
||||
// send DMA resp
|
||||
doAssert(isRqFromDma(cRq.id), "cRq should be DMA req");
|
||||
doAssert(cRq.byteEn != replicate(False) && cRq.toState == M,
|
||||
doAssert(cRq.byteEn != replicate(replicate(False)) && cRq.toState == M,
|
||||
"cRq should be DMA write"
|
||||
);
|
||||
dmaRqIdT dmaId = getIdFromDma(cRq.id);
|
||||
@@ -687,9 +686,9 @@ module mkLLBank#(
|
||||
cRqT cRq = cRqMshr.sendRsToDmaC.getRq(n);
|
||||
Maybe#(Line) rsData = cRqMshr.sendRsToDmaC.getData(n);
|
||||
if (verbose)
|
||||
$display("%t LL %m sendRsToC: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq), " ; ",
|
||||
$display("%t LL %m sendRsToC: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq), " ; ",
|
||||
fshow(rsData), " ; ",
|
||||
fshow(toState)
|
||||
);
|
||||
@@ -719,7 +718,7 @@ module mkLLBank#(
|
||||
// round robin select cRq to downgrade child
|
||||
// but downgrade must wait for all upgrade resp
|
||||
Reg#(cRqIndexT) whichCRq <- mkReg(0);
|
||||
|
||||
|
||||
// we don't perform sending downgrade to child for a cRq processing by pipelineResp_cRs
|
||||
// otherwise atomicity issue may arise
|
||||
// for safety, we check cRq processed by all pipelineResp_xxx rules
|
||||
@@ -757,7 +756,7 @@ module mkLLBank#(
|
||||
cRqT cRq = cRqMshr.sendRqToC.getRq(n);
|
||||
cRqSlotT cSlot = cRqMshr.sendRqToC.getSlot(n);
|
||||
LLCRqState cState = cRqMshr.sendRqToC.getState(n);
|
||||
doAssert(cState == WaitSt || cState == WaitOldTag,
|
||||
doAssert(cState == WaitSt || cState == WaitOldTag,
|
||||
"only WaitSt and WaitOldTag needs req child"
|
||||
);
|
||||
// find a child to downgrade
|
||||
@@ -828,7 +827,7 @@ module mkLLBank#(
|
||||
function Action cRqFromCHit(cRqIndexT n, cRqT cRq, Bool isMRs);
|
||||
action
|
||||
if (verbose)
|
||||
$display("%t LL %m pipelineResp: cRq from child Hit func: ", $time,
|
||||
$display("%t LL %m pipelineResp: cRq from child Hit func: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
@@ -836,7 +835,7 @@ module mkLLBank#(
|
||||
doAssert(isRqFromC(cRq.id), "should be cRq from child");
|
||||
doAssert(ram.info.tag == getTag(cRq.addr) && ram.info.cs > I,
|
||||
// this function is called by mRs, cRq, cRs
|
||||
// tag should match even for mRs, because
|
||||
// tag should match even for mRs, because
|
||||
// tag has been written into cache before sending req to parent
|
||||
("cRqHit but tag or cs incorrect")
|
||||
);
|
||||
@@ -886,7 +885,7 @@ module mkLLBank#(
|
||||
function Action cRqFromDmaHit(cRqIndexT n, cRqT cRq);
|
||||
action
|
||||
if (verbose)
|
||||
$display("%t LL %m pipelineResp: cRq from dma Hit func: ", $time,
|
||||
$display("%t LL %m pipelineResp: cRq from dma Hit func: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
@@ -895,7 +894,7 @@ module mkLLBank#(
|
||||
doAssert(ram.info.tag == getTag(cRq.addr) && ram.info.cs > I,
|
||||
"cRqHit but tag or cs incorrect"
|
||||
);
|
||||
doAssert((cRq.byteEn != replicate(False)) == (cRq.toState == M), "toState should match byteEn");
|
||||
doAssert((cRq.byteEn != replicate(replicate(False))) == (cRq.toState == M), "toState should match byteEn");
|
||||
// update cs (may have E -> M)
|
||||
Msi newCs = ram.info.cs;
|
||||
if(cRq.toState == M) begin
|
||||
@@ -903,7 +902,7 @@ module mkLLBank#(
|
||||
end
|
||||
// update cache line
|
||||
Maybe#(Line) wrData = cRqMshr.pipelineResp.getData(n);
|
||||
doAssert(isValid(wrData) == (cRq.byteEn != replicate(False)),
|
||||
doAssert(isValid(wrData) == (cRq.byteEn != replicate(replicate(False))),
|
||||
"dma write should carry valid data"
|
||||
);
|
||||
Line newLine = getUpdatedLine(ram.line, cRq.byteEn, validValue(wrData));
|
||||
@@ -999,7 +998,7 @@ module mkLLBank#(
|
||||
cRqT cRq = pipeOutCRq;
|
||||
if (verbose)
|
||||
$display("%t LL %m pipelineResp: cRq: ", $time, fshow(n), " ; ", fshow(cRq));
|
||||
|
||||
|
||||
// find end of dependency chain
|
||||
Maybe#(cRqIndexT) cRqEOC = cRqMshr.pipelineResp.searchEndOfChain(cRq.addr);
|
||||
|
||||
@@ -1141,7 +1140,7 @@ module mkLLBank#(
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
|
||||
// function to set cRq to Depend, and make no further change to cache
|
||||
function Action cRqSetDepNoCacheChange;
|
||||
action
|
||||
@@ -1156,7 +1155,7 @@ module mkLLBank#(
|
||||
LLCRqState cState = pipeOutCState;
|
||||
doAssert(cState == Init, "owner is other, must first time go through tag match");
|
||||
// tag match must be hit (because replacement algo won't give a way with owner)
|
||||
doAssert(ram.info.cs > I && ram.info.tag == getTag(cRq.addr),
|
||||
doAssert(ram.info.cs > I && ram.info.tag == getTag(cRq.addr),
|
||||
("cRq should hit in tag match")
|
||||
);
|
||||
// could be two cases:
|
||||
@@ -1239,7 +1238,7 @@ module mkLLBank#(
|
||||
if(cRqEOC matches tagged Valid .m &&& cState == Init) begin
|
||||
if (verbose)
|
||||
$display("%t LL %m pipelineResp: cRq: no owner, depend on cRq ", $time,
|
||||
fshow(cState), " ; ",
|
||||
fshow(cState), " ; ",
|
||||
fshow(cRqEOC)
|
||||
);
|
||||
cRqMshr.pipelineResp.setAddrSucc(m, Valid (n));
|
||||
@@ -1497,7 +1496,7 @@ module mkLLBank#(
|
||||
`else
|
||||
noAction;
|
||||
`endif
|
||||
endmethod
|
||||
endmethod
|
||||
|
||||
method Data getPerfData(LLCPerfType t);
|
||||
return (case(t)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -281,7 +280,7 @@ module mkSelfInvIBank#(
|
||||
|
||||
// function to get superscaler inst read result
|
||||
function resultT readInst(Line line, Addr addr);
|
||||
Vector#(LineSzInst, Instruction) instVec = unpack(pack(line));
|
||||
Vector#(LineSzInst, Instruction) instVec = unpack(pack(line.data));
|
||||
// the start offset for reading inst
|
||||
LineInstOffset startSel = getLineInstOffset(addr);
|
||||
// calculate the maximum inst count that could be read from line
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -453,13 +452,13 @@ module mkSelfInvL1Bank#(
|
||||
// The silent E->M update is already done in pipeline
|
||||
Line curLine = ram.line;
|
||||
Line newLine = curLine;
|
||||
LineDataOffset dataSel = getLineDataOffset(req.addr);
|
||||
LineMemDataOffset dataSel = getLineMemDataOffset(req.addr);
|
||||
case(req.op) matches
|
||||
Ld: begin
|
||||
procResp.respLd(req.id, curLine[dataSel]);
|
||||
procResp.respLd(req.id, getTaggedDataAt(curLine, dataSel));
|
||||
end
|
||||
Lr: begin
|
||||
procResp.respLrScAmo(req.id, curLine[dataSel]);
|
||||
procResp.respLrScAmo(req.id, getTaggedDataAt(curLine, dataSel));
|
||||
// set link addr
|
||||
linkAddr <= Valid (getLineAddr(req.addr));
|
||||
end
|
||||
@@ -470,11 +469,14 @@ module mkSelfInvL1Bank#(
|
||||
// check Sc succeeds or not
|
||||
Bool succeed = linkAddr == Valid (getLineAddr(req.addr));
|
||||
// resp to proc
|
||||
Data respVal = succeed ? fromInteger(valueof(ScSuccVal)) : fromInteger(valueof(ScFailVal));
|
||||
MemTaggedData respVal = succeed ? fromInteger(valueof(ScSuccVal)) : fromInteger(valueof(ScFailVal));
|
||||
procResp.respLrScAmo(req.id, respVal);
|
||||
// calculate new data to write
|
||||
if(succeed) begin
|
||||
newLine[dataSel] = getUpdatedData(curLine[dataSel], req.byteEn, req.data);
|
||||
let taggedData = getTaggedDataAt(curLine, dataSel);
|
||||
let newTaggedData =
|
||||
mergeMemTaggedDataBE(taggedData, req.data, zeroExtend(pack(req.byteEn)));
|
||||
newLine = setTaggedDataAt( newLine, dataSel, newTaggedData);
|
||||
end
|
||||
// reset link addr
|
||||
linkAddr <= Invalid;
|
||||
@@ -559,16 +561,28 @@ module mkSelfInvL1Bank#(
|
||||
// get line and sel
|
||||
Line curLine = ram.line;
|
||||
Line newLine = curLine;
|
||||
LineDataOffset dataSel = getLineDataOffset(req.addr);
|
||||
Bool upper32 = req.addr[2] == 1;
|
||||
Data curData = curLine[dataSel];
|
||||
LineMemDataOffset dataSel = getLineMemDataOffset(req.addr);
|
||||
MemTaggedData current = getTaggedDataAt(curLine, dataSel);
|
||||
Vector#(2, Bit#(64)) dwordData = current.data;
|
||||
Vector#(4, Bit#(32)) wordData = unpack(pack(current.data));
|
||||
Bit#(1) dwordIdx = req.addr[3];
|
||||
Bit#(2) wordIdx = req.addr[3:2];
|
||||
// resp processor
|
||||
Data resp = req.amoInst.doubleWord ? curData : signExtend(
|
||||
upper32 ? curData[63:32] : curData[31:0]
|
||||
);
|
||||
MemTaggedData resp = case (req.amoInst.width)
|
||||
QWord: current;
|
||||
DWord: MemTaggedData {
|
||||
tag: False,
|
||||
data: unpack(signExtend(dwordData[dwordIdx]))
|
||||
};
|
||||
Word: MemTaggedData {
|
||||
tag: False,
|
||||
data: unpack(signExtend(wordData[wordIdx]))
|
||||
};
|
||||
endcase;
|
||||
procResp.respLrScAmo(req.id, resp);
|
||||
// calculate new data to write
|
||||
newLine[dataSel] = amoExec(req.amoInst, curData, req.data, upper32);
|
||||
let newData = amoExec(req.amoInst, wordIdx, current, req.data);
|
||||
newLine = setTaggedDataAt(newLine, dataSel, newData);
|
||||
// deq pipeline or swap in successor
|
||||
// Since AMO always hits in M, hit count is 0 and never self inv
|
||||
pipeline.deqWrite(succ, RamData {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -42,7 +41,7 @@ import RandomReplace::*;
|
||||
// this also ensures that cache pipeline is never blocked
|
||||
// so we do not need to buffer mem resp that needs to refill cache
|
||||
|
||||
// XXX we need to maintain the invariant that
|
||||
// XXX we need to maintain the invariant that
|
||||
// at most 1 pRq sent to a child for an addr
|
||||
// and we have to wait for resp before sending anthoer one
|
||||
|
||||
@@ -213,7 +212,7 @@ module mkSelfInvLLBank#(
|
||||
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);
|
||||
@@ -295,8 +294,8 @@ module mkSelfInvLLBank#(
|
||||
addr: req.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
$display("%t LL %m cRqTransfer_retry: ", $time,
|
||||
fshow(n), " ; ",
|
||||
$display("%t LL %m cRqTransfer_retry: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req)
|
||||
);
|
||||
endrule
|
||||
@@ -347,14 +346,14 @@ module mkSelfInvLLBank#(
|
||||
cRqIndexT n <- cRqMshr.transfer.getEmptyEntryInit(cRq, Invalid);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (SelfInvLLPipeCRqIn {
|
||||
addr: cRq.addr,
|
||||
addr: cRq.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
// change round robin
|
||||
flipPriorNewCRqSrc;
|
||||
$display("%t LL %m cRqTransfer_new_child: ", $time,
|
||||
$display("%t LL %m cRqTransfer_new_child: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(r), " ; ",
|
||||
fshow(r), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
endrule
|
||||
@@ -384,7 +383,7 @@ module mkSelfInvLLBank#(
|
||||
rule cRqTransfer_new_dma(!cRqRetryIndexQ.notEmpty && newCRqSrc == Valid (Dma));
|
||||
rqFromDmaQ.deq;
|
||||
dmaRqT r = rqFromDmaQ.first;
|
||||
Bool write = r.byteEn != replicate(False);
|
||||
Bool write = r.byteEn != replicate(replicate(False));
|
||||
cRqT cRq = LLRq {
|
||||
addr: r.addr,
|
||||
fromState: I,
|
||||
@@ -398,14 +397,14 @@ module mkSelfInvLLBank#(
|
||||
cRqIndexT n <- cRqMshr.transfer.getEmptyEntryInit(cRq, write ? Valid (r.data) : Invalid);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (SelfInvLLPipeCRqIn {
|
||||
addr: cRq.addr,
|
||||
addr: cRq.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
// change round robin
|
||||
flipPriorNewCRqSrc;
|
||||
$display("%t LL %m cRqTransfer_new_dma: ", $time,
|
||||
$display("%t LL %m cRqTransfer_new_dma: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(r), " ; ",
|
||||
fshow(r), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
`ifdef PERF_COUNT
|
||||
@@ -457,7 +456,7 @@ module mkSelfInvLLBank#(
|
||||
end
|
||||
`endif
|
||||
endrule
|
||||
|
||||
|
||||
// mem resp for child req, will refill cache, send it to pipeline
|
||||
(* descending_urgency = "mRsTransfer, cRsTransfer, cRqTransfer_retry, cRqTransfer_new_child, cRqTransfer_new_dma" *)
|
||||
`ifdef PERF_COUNT
|
||||
@@ -520,7 +519,7 @@ module mkSelfInvLLBank#(
|
||||
cRqT cRq = cRqMshr.sendToM.getRq(n);
|
||||
cRqSlotT cSlot = cRqMshr.sendToM.getSlot(n);
|
||||
Maybe#(Line) data = cRqMshr.sendToM.getData(n);
|
||||
$display("%t LL %m sendToM: ", $time,
|
||||
$display("%t LL %m sendToM: ", $time,
|
||||
fshow(toMInfoQ.first), " ; ",
|
||||
fshow(cRq), " ; ",
|
||||
fshow(cSlot), " ; ",
|
||||
@@ -597,7 +596,7 @@ module mkSelfInvLLBank#(
|
||||
else begin // do write back part
|
||||
toMemT msg = Wb (WbMemRs {
|
||||
addr: {cSlot.repTag, truncate(cRq.addr)},
|
||||
byteEn: replicate(True),
|
||||
byteEn: replicate(replicate(True)),
|
||||
data: validValue(data)
|
||||
});
|
||||
toMQ.enq(msg);
|
||||
@@ -627,7 +626,7 @@ module mkSelfInvLLBank#(
|
||||
doAssert(isValid(data), "dma read req always has valid data");
|
||||
// send DMA resp
|
||||
doAssert(isRqFromDma(cRq.id), "cRq should be DMA req");
|
||||
doAssert(cRq.byteEn == replicate(False) && cRq.toState == S,
|
||||
doAssert(cRq.byteEn == replicate(replicate(False)) && cRq.toState == S,
|
||||
"cRq should be DMA read"
|
||||
);
|
||||
dmaRqIdT dmaId = getIdFromDma(cRq.id);
|
||||
@@ -649,7 +648,7 @@ module mkSelfInvLLBank#(
|
||||
);
|
||||
// send DMA resp
|
||||
doAssert(isRqFromDma(cRq.id), "cRq should be DMA req");
|
||||
doAssert(cRq.byteEn != replicate(False) && cRq.toState == M,
|
||||
doAssert(cRq.byteEn != replicate(replicate(False)) && cRq.toState == M,
|
||||
"cRq should be DMA write"
|
||||
);
|
||||
dmaRqIdT dmaId = getIdFromDma(cRq.id);
|
||||
@@ -666,9 +665,9 @@ module mkSelfInvLLBank#(
|
||||
Msi toState = rsToCIndexQ.first.toState;
|
||||
cRqT cRq = cRqMshr.sendRsToDmaC.getRq(n);
|
||||
Maybe#(Line) rsData = cRqMshr.sendRsToDmaC.getData(n);
|
||||
$display("%t LL %m sendRsToC: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq), " ; ",
|
||||
$display("%t LL %m sendRsToC: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq), " ; ",
|
||||
fshow(rsData), " ; ",
|
||||
fshow(toState)
|
||||
);
|
||||
@@ -698,7 +697,7 @@ module mkSelfInvLLBank#(
|
||||
// round robin select cRq to downgrade child
|
||||
// but downgrade must wait for all upgrade resp
|
||||
Reg#(cRqIndexT) whichCRq <- mkReg(0);
|
||||
|
||||
|
||||
// we don't perform sending downgrade to child for a cRq processing by pipelineResp_cRs
|
||||
// otherwise atomicity issue may arise
|
||||
// for safety, we check cRq processed by all pipelineResp_xxx rules
|
||||
@@ -736,7 +735,7 @@ module mkSelfInvLLBank#(
|
||||
cRqT cRq = cRqMshr.sendRqToC.getRq(n);
|
||||
cRqSlotT cSlot = cRqMshr.sendRqToC.getSlot(n);
|
||||
LLCRqState cState = cRqMshr.sendRqToC.getState(n);
|
||||
doAssert(cState == WaitSt || cState == WaitOldTag,
|
||||
doAssert(cState == WaitSt || cState == WaitOldTag,
|
||||
"only WaitSt and WaitOldTag needs req child"
|
||||
);
|
||||
// find the child to downgrade
|
||||
@@ -797,7 +796,7 @@ module mkSelfInvLLBank#(
|
||||
// function to process cRq hit (MSHR slot may have garbage)
|
||||
function Action cRqFromCHit(cRqIndexT n, cRqT cRq);
|
||||
action
|
||||
$display("%t LL %m pipelineResp: cRq from child Hit func: ", $time,
|
||||
$display("%t LL %m pipelineResp: cRq from child Hit func: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
@@ -805,7 +804,7 @@ module mkSelfInvLLBank#(
|
||||
doAssert(isRqFromC(cRq.id), "should be cRq from child");
|
||||
doAssert(ram.info.tag == getTag(cRq.addr) && ram.info.cs > I,
|
||||
// this function is called by mRs, cRq, cRs
|
||||
// tag should match even for mRs, because
|
||||
// tag should match even for mRs, because
|
||||
// tag has been written into cache before sending req to parent
|
||||
("cRqHit but tag or cs incorrect")
|
||||
);
|
||||
@@ -858,7 +857,7 @@ module mkSelfInvLLBank#(
|
||||
// function to process DMA req hit (MSHR slot may have garbage)
|
||||
function Action cRqFromDmaHit(cRqIndexT n, cRqT cRq);
|
||||
action
|
||||
$display("%t LL %m pipelineResp: cRq from dma Hit func: ", $time,
|
||||
$display("%t LL %m pipelineResp: cRq from dma Hit func: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
@@ -867,7 +866,7 @@ module mkSelfInvLLBank#(
|
||||
doAssert(ram.info.tag == getTag(cRq.addr) && ram.info.cs > I,
|
||||
"cRqHit but tag or cs incorrect"
|
||||
);
|
||||
doAssert((cRq.byteEn != replicate(False)) == (cRq.toState == M), "toState should match byteEn");
|
||||
doAssert((cRq.byteEn != replicate(replicate(False))) == (cRq.toState == M), "toState should match byteEn");
|
||||
// update cs (may have E -> M)
|
||||
Msi newCs = ram.info.cs;
|
||||
if(cRq.toState == M) begin
|
||||
@@ -875,7 +874,7 @@ module mkSelfInvLLBank#(
|
||||
end
|
||||
// update cache line
|
||||
Maybe#(Line) wrData = cRqMshr.pipelineResp.getData(n);
|
||||
doAssert(isValid(wrData) == (cRq.byteEn != replicate(False)),
|
||||
doAssert(isValid(wrData) == (cRq.byteEn != replicate(replicate(False))),
|
||||
"dma write should carry valid data"
|
||||
);
|
||||
Line newLine = getUpdatedLine(ram.line, cRq.byteEn, validValue(wrData));
|
||||
@@ -969,7 +968,7 @@ module mkSelfInvLLBank#(
|
||||
|
||||
cRqT cRq = pipeOutCRq;
|
||||
$display("%t LL %m pipelineResp: cRq: ", $time, fshow(n), " ; ", fshow(cRq));
|
||||
|
||||
|
||||
// find end of dependency chain
|
||||
Maybe#(cRqIndexT) cRqEOC = cRqMshr.pipelineResp.searchEndOfChain(cRq.addr);
|
||||
|
||||
@@ -1112,7 +1111,7 @@ module mkSelfInvLLBank#(
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
|
||||
// function to set cRq to Depend, and make no further change to cache
|
||||
function Action cRqSetDepNoCacheChange;
|
||||
action
|
||||
@@ -1127,7 +1126,7 @@ module mkSelfInvLLBank#(
|
||||
LLCRqState cState = pipeOutCState;
|
||||
doAssert(cState == Init, "owner is other, must first time go through tag match");
|
||||
// tag match must be hit (because replacement algo won't give a way with owner)
|
||||
doAssert(ram.info.cs > I && ram.info.tag == getTag(cRq.addr),
|
||||
doAssert(ram.info.cs > I && ram.info.tag == getTag(cRq.addr),
|
||||
("cRq should hit in tag match")
|
||||
);
|
||||
// could be two cases:
|
||||
@@ -1203,7 +1202,7 @@ module mkSelfInvLLBank#(
|
||||
// only check for cRqEOC to append to dependency chain when firt time go through tag match
|
||||
if(cRqEOC matches tagged Valid .m &&& cState == Init) begin
|
||||
$display("%t LL %m pipelineResp: cRq: no owner, depend on cRq ", $time,
|
||||
fshow(cState), " ; ",
|
||||
fshow(cState), " ; ",
|
||||
fshow(cRqEOC)
|
||||
);
|
||||
cRqMshr.pipelineResp.setAddrSucc(m, Valid (n));
|
||||
@@ -1408,7 +1407,7 @@ module mkSelfInvLLBank#(
|
||||
`else
|
||||
noAction;
|
||||
`endif
|
||||
endmethod
|
||||
endmethod
|
||||
|
||||
method Data getPerfData(LLCPerfType t);
|
||||
return (case(t)
|
||||
|
||||
@@ -192,7 +192,7 @@ endinterface
|
||||
|
||||
module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
|
||||
Bool verbose = False;
|
||||
Integer verbosity = 1;
|
||||
Integer verbosity = 0;
|
||||
|
||||
// alu reservation station
|
||||
ReservationStationAlu rsAlu <- mkReservationStationAlu;
|
||||
|
||||
@@ -204,6 +204,7 @@ function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot,
|
||||
tagged CSRData .csrdata: data = csrdata;
|
||||
endcase
|
||||
end
|
||||
CapPipe pipePc = cast(rot.pc);
|
||||
return tagged Valid RVFI_DII_Execution {
|
||||
rvfi_order: zeroExtend(pack(traceCnt)),
|
||||
rvfi_trap: isValid(rot.trap),
|
||||
@@ -214,7 +215,7 @@ function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot,
|
||||
rvfi_rs2_addr: rot.orig_inst[24:20],
|
||||
rvfi_rs1_data: ?,
|
||||
rvfi_rs2_data: ?,
|
||||
rvfi_pc_rdata: getAddr(rot.pc),
|
||||
rvfi_pc_rdata: getOffset(pipePc),
|
||||
rvfi_pc_wdata: next_pc,
|
||||
rvfi_mem_wdata: wdata,
|
||||
rvfi_rd_addr: rd,
|
||||
@@ -238,7 +239,7 @@ deriving (Eq, FShow, Bits);
|
||||
`endif
|
||||
|
||||
module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
Bool verbose = True;
|
||||
Bool verbose = False;
|
||||
|
||||
Integer verbosity = 2; // Bluespec: for lightweight verbosity trace
|
||||
|
||||
@@ -622,15 +623,15 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
|
||||
// record trap info
|
||||
Addr vaddr = ?;
|
||||
if ( (trap.trap == tagged Exception InstAccessFault)
|
||||
|| (trap.trap == tagged Exception InstPageFault)) begin
|
||||
if ( (trap == tagged Exception InstAccessFault)
|
||||
|| (trap == tagged Exception InstPageFault)) begin
|
||||
vaddr = x.tval;
|
||||
end
|
||||
else if(x.ppc_vaddr_csrData matches tagged VAddr .va) begin
|
||||
vaddr = getAddr(va);
|
||||
end
|
||||
let commitTrap_val = Valid (CommitTrap {
|
||||
trap: trap.trap,
|
||||
trap: trap,
|
||||
pc: x.pc,
|
||||
addr: vaddr,
|
||||
orig_inst: x.orig_inst
|
||||
@@ -1067,7 +1068,8 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
else begin
|
||||
if (verbose) $display("[doCommitNormalInst - %d] ", i, fshow(inst_tag), " ; ", fshow(x));
|
||||
`ifdef RVFI
|
||||
rvfis[i] = genRVFI(x, traceCnt + zeroExtend(whichTrace), getTSB(), getAddr(x.pc) + (is_16b_inst(x.orig_inst) ? 2:4));
|
||||
CapPipe pipePc = cast(x.pc);
|
||||
rvfis[i] = genRVFI(x, traceCnt + zeroExtend(whichTrace), getTSB(), getOffset(pipePc) + (is_16b_inst(x.orig_inst) ? 2:4));
|
||||
whichTrace = whichTrace + 1;
|
||||
`endif
|
||||
|
||||
|
||||
@@ -897,7 +897,7 @@ module mkFetchStage(FetchStage);
|
||||
if (in.decode_epoch == decode_epoch_local) begin
|
||||
doAssert(in.main_epoch == f_main_epoch, "main epoch must match");
|
||||
|
||||
let decode_result = decode(in.inst); // Decode 32b inst, or 32b expansion of 16b inst
|
||||
let decode_result = decode(in.inst, getFlags(inst_data[i].pc)==1); // Decode 32b inst, or 32b expansion of 16b inst
|
||||
|
||||
// update cause and tval if decode exception and no earlier (TLB) exception
|
||||
if (!isValid(cause)) begin
|
||||
|
||||
@@ -63,6 +63,7 @@ typedef struct {
|
||||
PhyRegs regs;
|
||||
InstTag tag;
|
||||
LdStQTag ldstq_tag;
|
||||
CapChecks cap_checks;
|
||||
} MemDispatchToRegRead deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
@@ -74,6 +75,7 @@ typedef struct {
|
||||
// src reg vals
|
||||
CapPipe rVal1;
|
||||
CapPipe rVal2;
|
||||
CapChecks cap_checks;
|
||||
} MemRegReadToExe deriving(Bits, FShow);
|
||||
|
||||
typedef struct {
|
||||
@@ -82,7 +84,7 @@ typedef struct {
|
||||
InstTag tag;
|
||||
LdStQTag ldstq_tag;
|
||||
// result
|
||||
ByteEn shiftedBE;
|
||||
MemDataByteEn shiftedBE;
|
||||
CapPipe vaddr; // virtual addr
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
// for those mem instrs that store data
|
||||
@@ -90,6 +92,8 @@ typedef struct {
|
||||
ByteEn store_data_BE;
|
||||
`endif
|
||||
Bool misaligned;
|
||||
Maybe#(CSR_XCapCause) capException;
|
||||
Maybe#(BoundsCheck) check;
|
||||
} MemExeToFinish deriving(Bits, FShow);
|
||||
|
||||
// bookkeeping when waiting for MMIO resp which may cause exception
|
||||
@@ -161,7 +165,7 @@ interface MemExeInput;
|
||||
CapPipe vaddr,
|
||||
Data store_data, ByteEn store_data_BE,
|
||||
Bool access_at_commit, Bool non_mmio_st_done,
|
||||
Maybe#(Exception) cause
|
||||
Maybe#(CSR_XCapCause) cause
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle tb
|
||||
`endif
|
||||
@@ -207,7 +211,7 @@ interface MemExePipeline;
|
||||
endinterface
|
||||
|
||||
module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
Bool verbose = False;
|
||||
Bool verbose = True;
|
||||
|
||||
// we change cache request in case of single core, becaues our MSI protocol
|
||||
// is not good with single core
|
||||
@@ -288,7 +292,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
Fifo#(1, MemResp) respLrScAmoQ <- mkCFFifo;
|
||||
// resp ifc to D$
|
||||
L1ProcResp#(DProcReqId) procRespIfc = (interface L1ProcResp;
|
||||
method Action respLd(DProcReqId id, Data d);
|
||||
method Action respLd(DProcReqId id, MemTaggedData d);
|
||||
LdQTag tag = truncate(id);
|
||||
memRespLdQ.enq(tuple2(tag, d));
|
||||
// early wake up RS and set SB
|
||||
@@ -308,7 +312,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
end
|
||||
`endif
|
||||
endmethod
|
||||
method Action respLrScAmo(DProcReqId id, Data d);
|
||||
method Action respLrScAmo(DProcReqId id, MemTaggedData d);
|
||||
respLrScAmoQ.enq(d);
|
||||
if(verbose) begin
|
||||
$display("[Lr/Sc/Amo resp] ", fshow(id), "; ", fshow(d));
|
||||
@@ -349,7 +353,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
exeStMemLat.incr(zeroExtend(lat));
|
||||
end
|
||||
`endif
|
||||
return tuple2(e.byteEn, unpack(e.data)); // return SB entry
|
||||
return tuple2(unpack(pack(e.byteEn)), e.line); // return SB entry
|
||||
endmethod
|
||||
`endif
|
||||
method Action evict(LineAddr lineAddr);
|
||||
@@ -396,7 +400,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
imm: x.data.imm,
|
||||
regs: x.regs,
|
||||
tag: x.tag,
|
||||
ldstq_tag: x.data.ldstq_tag
|
||||
ldstq_tag: x.data.ldstq_tag,
|
||||
cap_checks: x.data.cap_checks
|
||||
},
|
||||
spec_bits: x.spec_bits
|
||||
});
|
||||
@@ -438,7 +443,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
tag: x.tag,
|
||||
ldstq_tag: x.ldstq_tag,
|
||||
rVal1: rVal1,
|
||||
rVal2: rVal2
|
||||
rVal2: rVal2,
|
||||
cap_checks: x.cap_checks
|
||||
},
|
||||
spec_bits: dispToReg.spec_bits
|
||||
});
|
||||
@@ -457,6 +463,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
// get virtual addr & St/Sc/Amo data
|
||||
CapPipe vaddr = modifyOffset(x.rVal1, signExtend(x.imm), True).value;
|
||||
CapPipe data = x.rVal2;
|
||||
MemTaggedData toMemData = unpack(pack(toMem(data)));
|
||||
|
||||
`ifdef RVFI_DII
|
||||
memData[pack(x.ldstq_tag)] <= getAddr(data);
|
||||
@@ -465,19 +472,24 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
|
||||
// get shifted data and BE
|
||||
// we can use virtual addr to shift, since page size > dword size
|
||||
ByteEn origBE = lsq.getOrigBE(x.ldstq_tag);
|
||||
function Tuple2#(ByteEn, Data) getShiftedBEData(Addr addr, ByteEn be, Data d);
|
||||
Bit#(TLog#(NumBytes)) byteOffset = truncate(addr);
|
||||
return tuple2(unpack(pack(be) << byteOffset), d << {byteOffset, 3'b0});
|
||||
MemDataByteEn origBE = lsq.getOrigBE(x.ldstq_tag);
|
||||
function Tuple2#(MemDataByteEn, MemTaggedData) getShiftedBEData(
|
||||
Addr addr, MemDataByteEn be, MemTaggedData d);
|
||||
Bit#(TLog#(MemDataBytes)) byteOffset = truncate(addr);
|
||||
return tuple2(unpack(pack(be) << byteOffset), MemTaggedData {
|
||||
tag: (byteOffset == 0) ? d.tag : False
|
||||
, data: unpack(pack(d.data) << {byteOffset, 3'b0})});
|
||||
endfunction
|
||||
let {shiftBE, shiftData} = getShiftedBEData(getAddr(vaddr), origBE, getAddr(data));
|
||||
let {shiftBE, shiftData} = getShiftedBEData(getAddr(vaddr), origBE, toMemData);
|
||||
|
||||
// update LSQ data now
|
||||
if(x.ldstq_tag matches tagged St .stTag) begin
|
||||
Data d = x.mem_func == Amo ? getAddr(data) : shiftData; // XXX don't shift for AMO
|
||||
MemTaggedData d = x.mem_func == Amo ? toMemData : shiftData; // XXX don't shift for AMO
|
||||
lsq.updateData(stTag, d);
|
||||
end
|
||||
|
||||
CapPipe ddc = cast(inIfc.scaprf_rd(SCR_DDC)); // ToDo: feed DDC into the prepareBoundsCheck function below somehow.
|
||||
|
||||
// go to next stage by sending to TLB
|
||||
dTlb.procReq(DTlbReq {
|
||||
inst: MemExeToFinish {
|
||||
@@ -490,7 +502,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
store_data: data,
|
||||
store_data_BE: origBE,
|
||||
`endif
|
||||
misaligned: memAddrMisaligned(getAddr(vaddr), origBE)
|
||||
misaligned: memAddrMisaligned(getAddr(vaddr), origBE),
|
||||
capException: capChecks(x.rVal1, x.rVal2, ddc, x.cap_checks),
|
||||
check: prepareBoundsCheck(x.rVal1, x.rVal2, almightyCap/*ToDo: pcc*/,
|
||||
ddc, getAddr(vaddr), pack(countOnes(pack(origBE))), x.cap_checks)
|
||||
},
|
||||
specBits: regToExe.spec_bits
|
||||
});
|
||||
@@ -560,17 +575,19 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
endcase);
|
||||
Bool access_at_commit = !isValid(cause) && (isMMIO || isLrScAmo);
|
||||
Bool non_mmio_st_done = !isValid(cause) && !isMMIO && x.mem_func == St;
|
||||
CapPipe pcc = cast(inIfc.rob_getPC(x.tag));
|
||||
CapPipe ddc = cast(inIfc.scaprf_rd(SCR_DDC));
|
||||
Bool ddc_out_of_bounds = !isInBounds(modifyOffset(ddc,getAddr(x.vaddr),True).value,True);
|
||||
Bool out_of_bounds = (getFlags(pcc) == 1'b1) ? isInBounds(x.vaddr, False):ddc_out_of_bounds;
|
||||
if (x.check matches tagged Valid .check &&& x.capException matches tagged Invalid) begin
|
||||
if (!( (check.check_low >= check.authority_base) &&
|
||||
(check.check_inclusive ? (check.check_high <= check.authority_top )
|
||||
: (check.check_high < check.authority_top ))))
|
||||
x.capException = Valid(CSR_XCapCause{cheri_exc_reg: check.authority_idx, cheri_exc_code: LengthViolation});
|
||||
end
|
||||
inIfc.rob_setExecuted_doFinishMem(x.tag, x.vaddr, store_data, store_data_BE,
|
||||
access_at_commit, non_mmio_st_done,
|
||||
(out_of_bounds) ? Valid(CHERIFault):Invalid
|
||||
x.capException
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle{
|
||||
regWriteData: memData[pack(x.ldstq_tag)],
|
||||
memByteEn: unpack(pack(x.shiftedBE) >> getAddr(x.vaddr)[2:0])
|
||||
memByteEn: unpack(truncate(pack(x.shiftedBE) >> getAddr(x.vaddr)[3:0]))
|
||||
}
|
||||
`endif
|
||||
);
|
||||
@@ -697,12 +714,12 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
endrule
|
||||
|
||||
// handle load resp
|
||||
function Action doRespLd(LdQTag tag, Data data, String rule_name);
|
||||
function Action doRespLd(LdQTag tag, MemTaggedData data, String rule_name);
|
||||
action
|
||||
LSQRespLdResult res <- lsq.respLd(tag, data);
|
||||
if(verbose) $display("%t : ", $time, rule_name, " ", fshow(tag), "; ", fshow(data), "; ", fshow(res));
|
||||
if(res.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, nullWithAddr(res.data));
|
||||
inIfc.writeRegFile(dst.indx, fromMem(unpack(pack(res.data))));
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (res.instTag, res.data);
|
||||
@@ -718,7 +735,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
`endif
|
||||
`ifdef RVFI
|
||||
LdStQTag idx = tagged Ld tag;
|
||||
memData[pack(idx)] <= res.data;
|
||||
memData[pack(idx)] <= truncate(pack(res.data)); // TODO use fromMem?
|
||||
$display("%t : memData[%x] <= %x", $time(), pack(idx), res.data);
|
||||
`endif
|
||||
end
|
||||
@@ -862,10 +879,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
waitLrScAmoMMIOResp <= Invalid;
|
||||
// get resp data (need shifting)
|
||||
let d <- toGet(respLrScAmoQ).get;
|
||||
Data resp = gatherLoad(lsqDeqLd.paddr, lsqDeqLd.byteEn, lsqDeqLd.unsignedLd, d);
|
||||
MemTaggedData resp = gatherLoad(lsqDeqLd.paddr, lsqDeqLd.byteEn, lsqDeqLd.unsignedLd, d);
|
||||
// write reg file & set ROB as Executed & wakeup rs
|
||||
if(lsqDeqLd.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, nullWithAddr(resp));
|
||||
inIfc.writeRegFile(dst.indx, fromMem(unpack(pack(resp))));
|
||||
inIfc.setRegReadyAggr_mem(dst.indx);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqLd.instTag, resp);
|
||||
@@ -877,7 +894,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
Invalid
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle{
|
||||
regWriteData: resp,
|
||||
regWriteData: truncate(pack(resp)), // TODO use fromMem?
|
||||
memByteEn: replicate(False)
|
||||
}
|
||||
`endif
|
||||
@@ -950,10 +967,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
waitLrScAmoMMIOResp <= Invalid;
|
||||
// get resp (need to shift data)
|
||||
let d = inIfc.mmioRespVal.data;
|
||||
Data resp = gatherLoad(lsqDeqLd.paddr, lsqDeqLd.byteEn, lsqDeqLd.unsignedLd, d);
|
||||
MemTaggedData resp = gatherLoad(lsqDeqLd.paddr, lsqDeqLd.byteEn, lsqDeqLd.unsignedLd, d);
|
||||
// write reg file & wakeup rs (this wakeup is late but MMIO is rare) & set ROB as Executed
|
||||
if(lsqDeqLd.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, nullWithAddr(resp));
|
||||
inIfc.writeRegFile(dst.indx, fromMem(tuple2(resp.tag,unpack(pack(resp.data)))));
|
||||
inIfc.setRegReadyAggr_mem(dst.indx);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqLd.instTag, resp);
|
||||
@@ -962,7 +979,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
inIfc.rob_setExecuted_deqLSQ(lsqDeqLd.instTag, Invalid, Invalid
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle{
|
||||
regWriteData: resp,
|
||||
regWriteData: truncate(pack(resp)), // TODO use fromMem?
|
||||
memByteEn: replicate(False)
|
||||
}
|
||||
`endif
|
||||
@@ -1014,7 +1031,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
inIfc.rob_setExecuted_deqLSQ(lsqDeqSt.instTag, lsqDeqSt.fault, Invalid
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle{
|
||||
regWriteData: lsqDeqSt.stData,
|
||||
regWriteData: truncate(pack(lsqDeqSt.stData)), // TODO use fromMem?
|
||||
memByteEn: replicate(False)
|
||||
}
|
||||
`endif
|
||||
@@ -1110,7 +1127,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
inIfc.rob_setExecuted_deqLSQ(lsqDeqSt.instTag, Invalid, Invalid
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle{
|
||||
regWriteData: lsqDeqSt.stData,
|
||||
regWriteData: truncate(pack(lsqDeqSt.stData)), // TODO use fromMem ?
|
||||
memByteEn: replicate(False)
|
||||
}
|
||||
`endif
|
||||
@@ -1158,7 +1175,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
data: lsqDeqSt.stData,
|
||||
amoInst: AmoInst {
|
||||
func: lsqDeqSt.amoFunc,
|
||||
doubleWord: lsqDeqSt.shiftedBE == replicate(True),
|
||||
width: (pack(lsqDeqSt.shiftedBE) == ~0) ? QWord :
|
||||
(pack(lsqDeqSt.shiftedBE)[15:8] == ~0) ? DWord :
|
||||
(pack(lsqDeqSt.shiftedBE)[7:0] == ~0) ? DWord : Word,
|
||||
aq: lsqDeqSt.acq,
|
||||
rl: lsqDeqSt.rel
|
||||
}
|
||||
@@ -1201,10 +1220,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
lsq.deqSt;
|
||||
waitLrScAmoMMIOResp <= Invalid;
|
||||
// get resp data (no need to shift for Sc and Amo)
|
||||
Data resp <- toGet(respLrScAmoQ).get;
|
||||
MemTaggedData resp <- toGet(respLrScAmoQ).get;
|
||||
// write reg file & set ROB as Executed & wake up rs
|
||||
if(lsqDeqSt.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, nullWithAddr(resp));
|
||||
inIfc.writeRegFile(dst.indx, fromMem(tuple2(resp.tag, pack(resp.data))));
|
||||
inIfc.setRegReadyAggr_mem(dst.indx);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqSt.instTag, resp);
|
||||
@@ -1213,7 +1232,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
inIfc.rob_setExecuted_deqLSQ(lsqDeqSt.instTag, Invalid, Invalid
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle{
|
||||
regWriteData: resp,
|
||||
regWriteData: fromMemTaggedData(resp),
|
||||
memByteEn: replicate(False)
|
||||
}
|
||||
`endif
|
||||
@@ -1307,10 +1326,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
lsq.deqSt;
|
||||
waitLrScAmoMMIOResp <= Invalid;
|
||||
// get resp (no need to shift for AMO)
|
||||
Data resp = inIfc.mmioRespVal.data;
|
||||
MemTaggedData resp = inIfc.mmioRespVal.data;
|
||||
// write reg file & wakeup rs (this wakeup is late but MMIO is rare) & set ROB as Executed
|
||||
if(lsqDeqSt.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, nullWithAddr(resp));
|
||||
inIfc.writeRegFile(dst.indx, fromMem(tuple2(resp.tag, pack(resp.data))));
|
||||
inIfc.setRegReadyAggr_mem(dst.indx);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqSt.instTag, resp);
|
||||
@@ -1319,7 +1338,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
inIfc.rob_setExecuted_deqLSQ(lsqDeqSt.instTag, Invalid, Invalid
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle{
|
||||
regWriteData: resp,
|
||||
regWriteData: fromMemTaggedData(resp),
|
||||
memByteEn: replicate(False)
|
||||
}
|
||||
`endif
|
||||
@@ -1351,7 +1370,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
inIfc.rob_setExecuted_deqLSQ(lsqDeqSt.instTag, Valid (StoreAccessFault), Invalid
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle{
|
||||
regWriteData: lsqDeqSt.stData,
|
||||
regWriteData: fromMemTaggedData(lsqDeqSt.stData),
|
||||
memByteEn: replicate(False)
|
||||
}
|
||||
`endif
|
||||
|
||||
@@ -228,7 +228,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
Maybe#(Trap) trap = tagged Invalid;
|
||||
let csr_state = csrf.decodeInfo;
|
||||
let pending_interrupt = csrf.pending_interrupt;
|
||||
let new_exception = checkForException(x.dInst, x.regs, csr_state);
|
||||
let new_exception = checkForException(x.dInst, x.regs, csr_state, x.pc, x.orig_inst[1:0]==2'b11);
|
||||
|
||||
// If Fpu regs are accessed, trap if mstatus_fs is "Off" (2'b00)
|
||||
Bool fpr_access = ( fn_ArchReg_is_FpuReg (x.regs.src1)
|
||||
@@ -266,7 +266,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
trap = tagged Valid (tagged Interrupt fromMaybe(?, pending_interrupt));
|
||||
end else if (isValid(new_exception)) begin
|
||||
// newly found exception
|
||||
trap = tagged Valid (tagged Exception fromMaybe(?, new_exception));
|
||||
trap = new_exception;
|
||||
end
|
||||
else if (fs_trap || wfi_trap) begin
|
||||
trap = tagged Valid (tagged Exception IllegalInst);
|
||||
@@ -331,8 +331,6 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
// Flip epoch without redirecting
|
||||
// This avoids doing incorrect work
|
||||
incrEpochStallFetch;
|
||||
Maybe#(TrapWithCap) trapWithCap = Invalid;
|
||||
if (firstTrap matches tagged Valid .trap) trapWithCap = tagged Valid TrapWithCap{trap: trap, capExp: noCapCause};
|
||||
// just place it in the reorder buffer
|
||||
let y = ToReorderBuffer{pc: cast(pc),
|
||||
orig_inst: orig_inst,
|
||||
@@ -346,7 +344,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
csr: dInst.csr,
|
||||
scr: dInst.scr,
|
||||
claimed_phy_reg: False, // no renaming is done
|
||||
trap: trapWithCap,
|
||||
trap: firstTrap,
|
||||
tval: tval,
|
||||
// default values of FullResult
|
||||
ppc_vaddr_csrData: PPC (cast(pc)), // default use PPC
|
||||
@@ -675,7 +673,8 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
data: MemRSData {
|
||||
mem_func: mem_inst.mem_func,
|
||||
imm: validValue(dInst.imm),
|
||||
ldstq_tag: lsqTag
|
||||
ldstq_tag: lsqTag,
|
||||
cap_checks: dInst.capChecks
|
||||
},
|
||||
regs: phy_regs,
|
||||
tag: inst_tag,
|
||||
@@ -1013,7 +1012,8 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
data: MemRSData {
|
||||
mem_func: mem_inst.mem_func,
|
||||
imm: validValue(dInst.imm),
|
||||
ldstq_tag: lsqTag
|
||||
ldstq_tag: lsqTag,
|
||||
cap_checks: dInst.capChecks
|
||||
},
|
||||
regs: phy_regs,
|
||||
tag: inst_tag,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +8,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
|
||||
@@ -31,6 +31,7 @@ typedef struct {
|
||||
MemFunc mem_func;
|
||||
ImmData imm;
|
||||
LdStQTag ldstq_tag;
|
||||
CapChecks cap_checks;
|
||||
} MemRSData deriving(Bits, Eq, FShow);
|
||||
|
||||
// MEM pipeline is aggressive, i.e. it recv bypass and early RS wakeup
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -23,47 +22,46 @@
|
||||
|
||||
import Types::*;
|
||||
import ProcTypes::*;
|
||||
import Vector::*;
|
||||
|
||||
(* noinline *)
|
||||
function Data amoExec(AmoInst amo_inst, Data current_data, Data in_data, Bool upper_32_bits);
|
||||
// upper_32_bits is true if the operation is a 32-bit operation and the
|
||||
// address is the upper 32-bits of a 64-bit region.
|
||||
Data new_data = 0;
|
||||
Data old_data = current_data;
|
||||
function MemTaggedData amoExec( AmoInst amo_inst, Bit#(2) wordIdx
|
||||
, MemTaggedData current, MemTaggedData inpt );
|
||||
|
||||
if (!amo_inst.doubleWord) begin
|
||||
if (!upper_32_bits) begin
|
||||
current_data = (amo_inst.func == Min || amo_inst.func == Max) ? signExtend(current_data[31:0]) : zeroExtend(current_data[31:0]);
|
||||
in_data = (amo_inst.func == Min || amo_inst.func == Max) ? signExtend(in_data[31:0]) : zeroExtend(in_data[31:0]);
|
||||
end else begin
|
||||
// use upper 32-bits instead
|
||||
current_data = (amo_inst.func == Min || amo_inst.func == Max) ? signExtend(current_data[63:32]) : zeroExtend(current_data[63:32]);
|
||||
in_data = (amo_inst.func == Min || amo_inst.func == Max) ? signExtend(in_data[31:0]) : zeroExtend(in_data[31:0]);
|
||||
Vector#(2, Bit#(64)) dwordOld = current.data;
|
||||
Vector#(4, Bit#(32)) wordOld = unpack(pack(current.data));
|
||||
|
||||
function doOp (vOld, vIn) = case (amo_inst.func)
|
||||
Swap: return vIn;
|
||||
Add: return vOld + vIn;
|
||||
Xor: return vOld ^ vIn;
|
||||
And: return vOld & vIn;
|
||||
Or: return vOld | vIn;
|
||||
Min: return sMin(vOld, vIn);
|
||||
Max: return sMax(vOld, vIn);
|
||||
Minu: return uMin(vOld, vIn);
|
||||
Maxu: return uMax(vOld, vIn);
|
||||
endcase;
|
||||
|
||||
Bit#(128) tmpData = pack(doOp(pack(current.data), pack(inpt.data)));
|
||||
Bit#(128) mask = ~0;
|
||||
Bit#(8) shftAmnt = 0;
|
||||
case (amo_inst.width)
|
||||
DWord: begin
|
||||
tmpData = zeroExtend(doOp(dwordOld[wordIdx[1]], truncate(pack(inpt.data))));
|
||||
mask = zeroExtend(64'hffffffffffffffff);
|
||||
shftAmnt = zeroExtend(wordIdx[1]) << 6;
|
||||
end
|
||||
Word: begin
|
||||
tmpData = zeroExtend(doOp(wordOld[wordIdx], truncate(pack(inpt.data))));
|
||||
mask = zeroExtend(32'hffffffff);
|
||||
shftAmnt = zeroExtend(wordIdx) << 5;
|
||||
end
|
||||
end
|
||||
|
||||
case (amo_inst.func)
|
||||
Swap: new_data = in_data;
|
||||
Add: new_data = current_data + in_data;
|
||||
Xor: new_data = current_data ^ in_data;
|
||||
And: new_data = current_data & in_data;
|
||||
Or: new_data = current_data | in_data;
|
||||
Min: new_data = sMin(current_data, in_data);
|
||||
Max: new_data = sMax(current_data, in_data);
|
||||
Minu: new_data = uMin(current_data, in_data);
|
||||
Maxu: new_data = uMax(current_data, in_data);
|
||||
endcase
|
||||
Bit#(128) newData = (pack(current.data) & ~(mask << shftAmnt)) | (tmpData << shftAmnt);
|
||||
|
||||
if (!amo_inst.doubleWord) begin
|
||||
if (!upper_32_bits) begin
|
||||
return {old_data[63:32], new_data[31:0]};
|
||||
end else begin
|
||||
// change upper 32-bits instead
|
||||
return {new_data[31:0], old_data[31:0]};
|
||||
end
|
||||
end else begin
|
||||
return new_data;
|
||||
end
|
||||
Bool newTag = (amo_inst.func == Swap && amo_inst.width == QWord) ? inpt.tag : False;
|
||||
return MemTaggedData { tag: newTag, data: unpack(newData) };
|
||||
endfunction
|
||||
|
||||
function Bit#(t) sMax( Bit#(t) a, Bit#(t) b );
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +8,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
|
||||
@@ -38,32 +38,66 @@ import FShow::*;
|
||||
import MsgFifo::*;
|
||||
|
||||
// 64B cache line
|
||||
typedef 8 CLineNumData;
|
||||
typedef 4 CLineNumMemTaggedData;
|
||||
typedef TMul#(CLineNumMemTaggedData, 2) CLineNumData;
|
||||
typedef TLog#(CLineNumMemTaggedData) LogCLineNumMemTaggedData;
|
||||
typedef TLog#(CLineNumData) LogCLineNumData;
|
||||
typedef Bit#(LogCLineNumData) CLineDataSel;
|
||||
|
||||
function CLineDataSel getCLineDataSel(Addr a);
|
||||
return truncate(a >> valueOf(TLog#(NumBytes)));
|
||||
typedef Bit#(LogCLineNumMemTaggedData) CLineMemTaggedDataSel;
|
||||
function CLineMemTaggedDataSel getCLineMemTaggedDataSel(Addr a) =
|
||||
truncate(a >> valueOf(TLog#(MemDataBytes)));
|
||||
function CLineDataSel getCLineDataSel(Addr a) =
|
||||
truncate(a >> valueOf(TLog#(DataBytes)));
|
||||
typedef struct {
|
||||
Vector#(CLineNumMemTaggedData, MemTag) tag;
|
||||
Vector#(CLineNumMemTaggedData, MemData) data;
|
||||
} CLine deriving (Bits, Eq, FShow);
|
||||
function Data getDataAt(CLine line, CLineDataSel sel);
|
||||
Vector#(CLineNumData, Data) data = unpack(pack(line.data));
|
||||
return data[sel];
|
||||
endfunction
|
||||
function CLine setDataAt(CLine line, CLineDataSel sel, Data data);
|
||||
Vector#(CLineNumData, Data) newData = unpack(pack(line.data));
|
||||
newData[sel] = data;
|
||||
CLineMemTaggedDataSel bigSel = truncateLSB(sel);
|
||||
let newLine = line;
|
||||
newLine.tag[bigSel] = False;
|
||||
newLine.data = unpack(pack(newData));
|
||||
return newLine;
|
||||
endfunction
|
||||
function CLine setDataAtBE(CLine line, CLineDataSel sel, Data data, ByteEn be);
|
||||
let oldData = getDataAt(line, sel);
|
||||
return setDataAt(line, sel, mergeDataBE(oldData, data, be));
|
||||
endfunction
|
||||
function MemTaggedData getTaggedDataAt(CLine line, CLineMemTaggedDataSel sel) =
|
||||
MemTaggedData { tag: line.tag[sel], data: line.data[sel] };
|
||||
function CLine setTaggedDataAt(CLine line, CLineMemTaggedDataSel sel, MemTaggedData data);
|
||||
let newLine = line;
|
||||
newLine.tag[sel] = data.tag;
|
||||
newLine.data[sel] = data.data;
|
||||
return newLine;
|
||||
endfunction
|
||||
typedef TMul#(CLineNumMemTaggedData, MemDataSz) CLineDataSz;
|
||||
typedef TDiv#(CLineDataSz, 8) CLineDataNumBytes;
|
||||
typedef TLog#(CLineDataNumBytes) LogCLineDataNumBytes;
|
||||
|
||||
typedef TMul#(CLineNumData, DataSz) CacheLineSz;
|
||||
typedef Bit#(CacheLineSz) CacheLine;
|
||||
|
||||
typedef TMul#(CLineNumData, NumBytes) CLineNumBytes;
|
||||
typedef TLog#(CLineNumBytes) LogCLineNumBytes;
|
||||
typedef Vector#(CLineNumBytes, Bool) CLineByteEn;
|
||||
typedef TMul#(CLineNumMemTaggedData, MemDataSz) CLineMemDataSz;
|
||||
typedef TMul#(CLineNumMemTaggedData, MemDataBytes) CLineNumMemDataBytes;
|
||||
typedef TLog#(CLineNumMemDataBytes) LogCLineNumMemDataBytes;
|
||||
typedef Vector#(CLineNumMemTaggedData, Vector#(MemDataBytes, Bool)) CLineMemDataByteEn;
|
||||
typedef Vector#(CLineNumData, Vector#(DataBytes, Bool)) CLineDataByteEn;
|
||||
|
||||
function Bool isCLineAlignAddr(Addr a);
|
||||
Bit#(LogCLineNumBytes) offset = truncate(a);
|
||||
Bit#(LogCLineNumMemDataBytes) offset = truncate(a);
|
||||
return offset == 0;
|
||||
endfunction
|
||||
|
||||
// cache line addr (drop the offset within cache line)
|
||||
typedef TSub#(AddrSz, LogCLineNumBytes) CLineAddrSz;
|
||||
typedef TSub#(AddrSz, LogCLineNumMemDataBytes) CLineAddrSz;
|
||||
typedef Bit#(CLineAddrSz) CLineAddr;
|
||||
|
||||
// cache line v.s. instruction
|
||||
typedef TDiv#(CacheLineSz, InstSz) CLineNumInst;
|
||||
typedef TDiv#(CLineMemDataSz, InstSz) CLineNumInst;
|
||||
typedef Bit#(TLog#(CLineNumInst)) CLineInstSel;
|
||||
|
||||
function CLineInstSel getCLineInstSel(Addr a);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
`CAP_CHECK_FIELD(ddc_tag,"ddc_tag")
|
||||
`CAP_CHECK_FIELD(src1_tag,"src1_tag")
|
||||
`CAP_CHECK_FIELD(src2_tag,"src2_tag")
|
||||
`CAP_CHECK_FIELD(src1_sealed_with_type,"src1_sealed_with_type")
|
||||
`CAP_CHECK_FIELD(ddc_unsealed,"ddc_unsealed")
|
||||
`CAP_CHECK_FIELD(src1_unsealed,"src1_unsealed")
|
||||
`CAP_CHECK_FIELD(src2_unsealed,"src2_unsealed")
|
||||
`CAP_CHECK_FIELD(src1_sealed,"src1_sealed")
|
||||
|
||||
@@ -34,12 +34,6 @@ Bit#(3) memWU = 3'b110;
|
||||
|
||||
// Smaller decode functions
|
||||
function Maybe#(MemInst) decodeMemInst(Instruction inst);
|
||||
MemInst mem_inst = MemInst{ mem_func: ?,
|
||||
amo_func: None,
|
||||
unsignedLd: False,
|
||||
byteEn: replicate(False),
|
||||
aq: False,
|
||||
rl: False };
|
||||
Bool illegalInst = False;
|
||||
Opcode opcode = unpackOpcode(inst[6:0]);
|
||||
let funct5 = inst[31:27];
|
||||
@@ -48,7 +42,7 @@ function Maybe#(MemInst) decodeMemInst(Instruction inst);
|
||||
// mem_func + amo_func
|
||||
MemFunc mem_func = Ld;
|
||||
AmoFunc amo_func = None;
|
||||
if (opcode == Load || opcode == LoadFp) begin
|
||||
if (opcode == Load || opcode == LoadFp || opcode == MiscMem) begin
|
||||
mem_func = Ld;
|
||||
end else if (opcode == Store || opcode == StoreFp) begin
|
||||
mem_func = St;
|
||||
@@ -100,25 +94,39 @@ function Maybe#(MemInst) decodeMemInst(Instruction inst);
|
||||
unsignedLd = True;
|
||||
end
|
||||
|
||||
Bool capWidth = (mem_func == St && funct3 == 3'b100)
|
||||
|| (opcode == MiscMem && funct3 == 3'b010);
|
||||
|
||||
// byteEn
|
||||
// TODO: Some combinations of operations and byteEn's are illegal.
|
||||
// They should be detected here.
|
||||
ByteEn byteEn = replicate(False);
|
||||
case (funct3)
|
||||
memB, memBU : byteEn[0] = True;
|
||||
memH, memHU : begin
|
||||
byteEn[0] = True;
|
||||
byteEn[1] = True;
|
||||
end
|
||||
memW, memWU : begin
|
||||
byteEn[0] = True;
|
||||
byteEn[1] = True;
|
||||
byteEn[2] = True;
|
||||
byteEn[3] = True;
|
||||
end
|
||||
memD : byteEn = replicate(True);
|
||||
default : illegalInst = True;
|
||||
endcase
|
||||
MemDataByteEn byteEn = (capWidth) ? replicate(True):replicate(False);
|
||||
if (!capWidth) begin
|
||||
case (funct3)
|
||||
memB, memBU : byteEn[0] = True;
|
||||
memH, memHU : begin
|
||||
byteEn[0] = True;
|
||||
byteEn[1] = True;
|
||||
end
|
||||
memW, memWU : begin
|
||||
byteEn[0] = True;
|
||||
byteEn[1] = True;
|
||||
byteEn[2] = True;
|
||||
byteEn[3] = True;
|
||||
end
|
||||
memD : begin
|
||||
byteEn[0] = True;
|
||||
byteEn[1] = True;
|
||||
byteEn[2] = True;
|
||||
byteEn[3] = True;
|
||||
byteEn[4] = True;
|
||||
byteEn[5] = True;
|
||||
byteEn[6] = True;
|
||||
byteEn[7] = True;
|
||||
end
|
||||
default : illegalInst = True;
|
||||
endcase
|
||||
end
|
||||
|
||||
// aq + rl
|
||||
Bool aq = False;
|
||||
@@ -138,12 +146,109 @@ function Maybe#(MemInst) decodeMemInst(Instruction inst);
|
||||
unsignedLd: unsignedLd,
|
||||
byteEn: byteEn,
|
||||
aq: aq,
|
||||
rl: rl } );
|
||||
rl: rl,
|
||||
reg_bounds: False } );
|
||||
end
|
||||
endfunction
|
||||
|
||||
function Maybe#(MemInst) decodeCapMemInst(Instruction inst);
|
||||
// This function trusts that its result will only be used by
|
||||
// explicit capability instructions as identified by the primary
|
||||
// decode case, and therefore does not attempt to return sensible
|
||||
// defaults when the instruction is not a capability memory operation.
|
||||
Bool illegalInst = False;
|
||||
Bit#(7) funct7 = inst[31:25];
|
||||
Bit#(5) mem_code = (funct7==f7_cap_Loads) ? inst[24:20]:inst[11:7];
|
||||
Bool amo = unpack(mem_code[4]);
|
||||
Bool bounds_from_register = unpack(mem_code[3]);
|
||||
Bool unsind = unpack(mem_code[2]);
|
||||
Bit#(2) width = mem_code[1:0];
|
||||
|
||||
Bool capWidth = (funct7 == f7_cap_Stores && unsind && width == 0);
|
||||
if (funct7 == f7_cap_Loads && amo && width == 3) begin
|
||||
capWidth = True;
|
||||
amo = False;
|
||||
end
|
||||
|
||||
// mem_func + amo_func
|
||||
MemFunc mem_func = Ld;
|
||||
AmoFunc amo_func = None;
|
||||
if (funct7 == f7_cap_Loads) begin
|
||||
mem_func = (amo) ? Lr:Ld;
|
||||
end else if (funct7 == f7_cap_Stores) begin
|
||||
mem_func = (amo) ? Sc:St;
|
||||
end
|
||||
|
||||
// unsignedLd
|
||||
// it doesn't matter if this is set to True for stores
|
||||
Bool unsignedLd = unsind;
|
||||
|
||||
// byteEn
|
||||
// TODO: Some combinations of operations and byteEn's are illegal.
|
||||
// They should be detected here.
|
||||
MemDataByteEn byteEn = (capWidth) ? replicate(True):replicate(False);
|
||||
if (!capWidth) begin
|
||||
case (width)
|
||||
0 : byteEn[0] = True;
|
||||
1 : begin
|
||||
byteEn[0] = True;
|
||||
byteEn[1] = True;
|
||||
end
|
||||
2 : begin
|
||||
byteEn[0] = True;
|
||||
byteEn[1] = True;
|
||||
byteEn[2] = True;
|
||||
byteEn[3] = True;
|
||||
end
|
||||
3 : begin
|
||||
byteEn[0] = True;
|
||||
byteEn[1] = True;
|
||||
byteEn[2] = True;
|
||||
byteEn[3] = True;
|
||||
byteEn[4] = True;
|
||||
byteEn[5] = True;
|
||||
byteEn[6] = True;
|
||||
byteEn[7] = True;
|
||||
// In RV64 we don't allow unsigned double operations!
|
||||
if (unsind) illegalInst = True;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (illegalInst) begin
|
||||
return tagged Invalid;
|
||||
end else begin
|
||||
return tagged Valid ( MemInst{
|
||||
mem_func: mem_func,
|
||||
amo_func: amo_func,
|
||||
unsignedLd: unsignedLd,
|
||||
byteEn: byteEn,
|
||||
aq: amo,
|
||||
rl: amo,
|
||||
reg_bounds: bounds_from_register} );
|
||||
end
|
||||
endfunction
|
||||
|
||||
function CapChecks memCapChecks(Bool cap_mode);
|
||||
CapChecks capChecks = unpack(0);
|
||||
capChecks.check_enable = True;
|
||||
capChecks.check_low_src = Vaddr;
|
||||
capChecks.check_high_src = VaddrPlusSize; // Should add the access size somehow...
|
||||
capChecks.check_inclusive = True;
|
||||
if (cap_mode) begin
|
||||
capChecks.check_authority_src = Src1;
|
||||
capChecks.src1_tag = True;
|
||||
capChecks.src1_unsealed = True;
|
||||
end else begin
|
||||
capChecks.check_authority_src = Ddc;
|
||||
capChecks.ddc_tag = True;
|
||||
capChecks.ddc_unsealed = True;
|
||||
end
|
||||
return capChecks;
|
||||
endfunction
|
||||
|
||||
(* noinline *)
|
||||
function DecodeResult decode(Instruction inst);
|
||||
function DecodeResult decode(Instruction inst, Bool cap_mode);
|
||||
RiscVISASubset isa = defaultValue;
|
||||
|
||||
// initialize dInst with default values
|
||||
@@ -190,6 +295,7 @@ function DecodeResult decode(Instruction inst);
|
||||
|
||||
// Results of mini-decoders
|
||||
Maybe#(MemInst) mem_inst = decodeMemInst(inst);
|
||||
Maybe#(MemInst) cap_mem_inst = decodeCapMemInst(inst);
|
||||
|
||||
// TODO better detection of illegal insts
|
||||
case (opcode)
|
||||
@@ -372,6 +478,11 @@ function DecodeResult decode(Instruction inst);
|
||||
dInst.imm = Valid(immJ);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.execFunc = tagged Br AT;
|
||||
dInst.capChecks.check_enable = True;
|
||||
dInst.capChecks.check_authority_src = Pcc;
|
||||
dInst.capChecks.check_low_src = Src1Addr;
|
||||
dInst.capChecks.check_high_src = Src1AddrPlus2;
|
||||
dInst.capChecks.check_inclusive = True;
|
||||
end
|
||||
|
||||
Jalr: begin
|
||||
@@ -382,6 +493,11 @@ function DecodeResult decode(Instruction inst);
|
||||
dInst.imm = Valid(immI);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.execFunc = tagged Br AT;
|
||||
dInst.capChecks.check_enable = True;
|
||||
dInst.capChecks.check_authority_src = Pcc;
|
||||
dInst.capChecks.check_low_src = Src1Addr;
|
||||
dInst.capChecks.check_high_src = Src1AddrPlus2;
|
||||
dInst.capChecks.check_inclusive = True;
|
||||
end
|
||||
|
||||
Branch: begin
|
||||
@@ -399,6 +515,11 @@ function DecodeResult decode(Instruction inst);
|
||||
regs.src2 = Valid(tagged Gpr rs2);
|
||||
dInst.imm = Valid(immB);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks.check_enable = True;
|
||||
dInst.capChecks.check_authority_src = Pcc;
|
||||
dInst.capChecks.check_low_src = Src1Addr;
|
||||
dInst.capChecks.check_high_src = Src1AddrPlus2;
|
||||
dInst.capChecks.check_inclusive = True;
|
||||
end
|
||||
|
||||
Load: begin
|
||||
@@ -413,6 +534,7 @@ function DecodeResult decode(Instruction inst);
|
||||
regs.src2 = Invalid;
|
||||
dInst.imm = Valid(immI);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks = memCapChecks(cap_mode);
|
||||
end
|
||||
|
||||
Store: begin
|
||||
@@ -427,6 +549,7 @@ function DecodeResult decode(Instruction inst);
|
||||
regs.src2 = Valid(tagged Gpr rs2);
|
||||
dInst.imm = Valid(immS);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks = memCapChecks(cap_mode);
|
||||
end
|
||||
|
||||
Amo: begin
|
||||
@@ -582,6 +705,7 @@ function DecodeResult decode(Instruction inst);
|
||||
regs.src2 = Invalid;
|
||||
dInst.imm = Valid(immI);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks = memCapChecks(cap_mode);
|
||||
end
|
||||
end
|
||||
StoreFp: begin
|
||||
@@ -602,6 +726,7 @@ function DecodeResult decode(Instruction inst);
|
||||
regs.src2 = Valid(tagged Fpu rs2);
|
||||
dInst.imm = Valid(immS);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks = memCapChecks(cap_mode);
|
||||
end
|
||||
end
|
||||
Fmadd, Fmsub, Fnmsub, Fnmadd: begin
|
||||
@@ -637,6 +762,11 @@ function DecodeResult decode(Instruction inst);
|
||||
end
|
||||
|
||||
MiscMem: begin
|
||||
regs.dst = Invalid;
|
||||
regs.src1 = Invalid;
|
||||
regs.src2 = Invalid;
|
||||
dInst.imm = Invalid;
|
||||
dInst.csr = Invalid;
|
||||
case (funct3)
|
||||
fnFENCEI: begin
|
||||
dInst.iType = FenceI;
|
||||
@@ -672,7 +802,8 @@ function DecodeResult decode(Instruction inst);
|
||||
unsignedLd: False,
|
||||
byteEn: replicate(False),
|
||||
aq: reconcile,
|
||||
rl: commit
|
||||
rl: commit,
|
||||
reg_bounds: False // unused
|
||||
});
|
||||
end
|
||||
else begin
|
||||
@@ -680,13 +811,22 @@ function DecodeResult decode(Instruction inst);
|
||||
dInst.execFunc = tagged Other;
|
||||
end
|
||||
end
|
||||
fnLC: begin
|
||||
dInst.iType = Ld;
|
||||
if (isValid(mem_inst)) begin
|
||||
dInst.execFunc = tagged Mem fromMaybe(?, mem_inst);
|
||||
end else begin
|
||||
illegalInst = True;
|
||||
end
|
||||
regs.dst = Valid(tagged Gpr rd);
|
||||
regs.src1 = Valid(tagged Gpr rs1);
|
||||
regs.src2 = Invalid;
|
||||
dInst.imm = Valid(immI);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks = memCapChecks(cap_mode);
|
||||
end
|
||||
default: illegalInst = True;
|
||||
endcase
|
||||
regs.dst = Invalid;
|
||||
regs.src1 = Invalid;
|
||||
regs.src2 = Invalid;
|
||||
dInst.imm = Invalid;
|
||||
dInst.csr = Invalid;
|
||||
end
|
||||
|
||||
System: begin
|
||||
@@ -1029,12 +1169,28 @@ function DecodeResult decode(Instruction inst);
|
||||
dInst.capFunc = CapModify (BuildCap);
|
||||
end
|
||||
f7_cap_Loads: begin
|
||||
illegalInst = True;
|
||||
//TODO
|
||||
dInst.iType = Ld;
|
||||
MemInst mi = cap_mem_inst.Valid;
|
||||
if (isValid(cap_mem_inst)) dInst.execFunc = tagged Mem mi;
|
||||
else illegalInst = True;
|
||||
regs.dst = Valid(tagged Gpr rd);
|
||||
regs.src1 = Valid(tagged Gpr rs1);
|
||||
regs.src2 = Invalid;
|
||||
dInst.imm = Valid (0);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks = memCapChecks(mi.reg_bounds);
|
||||
end
|
||||
f7_cap_Stores: begin
|
||||
illegalInst = True;
|
||||
//TODO
|
||||
dInst.iType = St;
|
||||
MemInst mi = cap_mem_inst.Valid;
|
||||
if (isValid(cap_mem_inst)) dInst.execFunc = tagged Mem mi;
|
||||
else illegalInst = True;
|
||||
regs.dst = Invalid;
|
||||
regs.src1 = Valid(tagged Gpr rs1);
|
||||
regs.src2 = Valid(tagged Gpr rs2);
|
||||
dInst.imm = Valid (0);
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks = memCapChecks(mi.reg_bounds);
|
||||
end
|
||||
f7_cap_TwoOp: begin
|
||||
case (funct5rs2)
|
||||
@@ -1133,7 +1289,7 @@ function DecodeResult decode(Instruction inst);
|
||||
dInst.capChecks.check_authority_src = Src1;
|
||||
dInst.capChecks.check_low_src = Src1Addr;
|
||||
dInst.capChecks.check_high_src = Src1AddrPlus2;
|
||||
dInst.capChecks.check_inclusive = False;
|
||||
dInst.capChecks.check_inclusive = True;
|
||||
|
||||
dInst.iType = CJALR;
|
||||
dInst.execFunc = tagged Br AT;
|
||||
@@ -1163,14 +1319,15 @@ function DecodeResult decode(Instruction inst);
|
||||
illegalInst = True;
|
||||
end
|
||||
endcase
|
||||
dInst.capChecks.rn1 = {1'b0, regs.src1.Valid.Gpr};
|
||||
dInst.capChecks.rn2 = {1'b0, regs.src2.Valid.Gpr};
|
||||
end
|
||||
default: begin
|
||||
illegalInst = True;
|
||||
end
|
||||
endcase
|
||||
|
||||
dInst.capChecks.rn1 = {1'b0, regs.src1.Valid.Gpr};
|
||||
dInst.capChecks.rn2 = {1'b0, regs.src2.Valid.Gpr};
|
||||
|
||||
// XXX to ensure renaming + phy regs works correctly, must remove any write
|
||||
// to x0
|
||||
if(regs.dst matches tagged Valid .dst &&& dst == tagged Gpr 0) begin
|
||||
|
||||
@@ -30,18 +30,21 @@ import CHERICC_Fat::*;
|
||||
import ISA_Decls_CHERI::*;
|
||||
|
||||
(* noinline *)
|
||||
function Maybe#(CapException) capChecks(CapPipe a, CapPipe b, CapChecks toCheck, CapPipe pcc_end);
|
||||
function Maybe#(CapException) e1(CHERIException e) = Valid(CapException{cheri_exc_reg: toCheck.rn1, cheri_exc_code: e});
|
||||
function Maybe#(CapException) e2(CHERIException e) = Valid(CapException{cheri_exc_reg: toCheck.rn2, cheri_exc_code: e});
|
||||
Maybe#(CapException) result = Invalid;
|
||||
if (!isInBounds(pcc_end, True))
|
||||
result = Valid(CapException{cheri_exc_reg: {1'b1,pack(SCR_PCC)}, cheri_exc_code: LengthViolation});
|
||||
function Maybe#(CSR_XCapCause) capChecks(CapPipe a, CapPipe b, CapPipe ddc, CapChecks toCheck);
|
||||
function Maybe#(CSR_XCapCause) e1(CHERIException e) = Valid(CSR_XCapCause{cheri_exc_reg: toCheck.rn1, cheri_exc_code: e});
|
||||
function Maybe#(CSR_XCapCause) e2(CHERIException e) = Valid(CSR_XCapCause{cheri_exc_reg: toCheck.rn2, cheri_exc_code: e});
|
||||
function Maybe#(CSR_XCapCause) eDDC(CHERIException e) = Valid(CSR_XCapCause{cheri_exc_reg: 6'b100001, cheri_exc_code: e}); // Not sure where the proper reg number of DDC is stored...
|
||||
Maybe#(CSR_XCapCause) result = Invalid;
|
||||
if (toCheck.ddc_tag && !isValidCap(ddc))
|
||||
result = eDDC(TagViolation);
|
||||
else if (toCheck.src1_tag && !isValidCap(a))
|
||||
result = e1(TagViolation);
|
||||
else if (toCheck.src2_tag && !isValidCap(b))
|
||||
result = e2(TagViolation);
|
||||
else if (toCheck.src1_sealed_with_type && getKind(a) != SEALED_WITH_TYPE)
|
||||
result = e1(SealViolation);
|
||||
else if (toCheck.ddc_unsealed && isValidCap(ddc) && isSealed(ddc))
|
||||
result = eDDC(SealViolation);
|
||||
else if (toCheck.src1_unsealed && isValidCap(a) && isSealed(a))
|
||||
result = e1(SealViolation);
|
||||
else if (toCheck.src2_unsealed && isValidCap(b) && isSealed(b))
|
||||
@@ -73,12 +76,14 @@ function Maybe#(CapException) capChecks(CapPipe a, CapPipe b, CapChecks toCheck,
|
||||
else if (toCheck.src1_derivable && !isDerivable(a))
|
||||
result = e1(LengthViolation);
|
||||
else if (toCheck.scr_read_only && (toCheck.rn1 != 0))
|
||||
result = Valid(CapException{cheri_exc_reg: {1,pack(SCR_PCC)}, cheri_exc_code: PermitASRViolation});
|
||||
result = Valid(CSR_XCapCause{cheri_exc_reg: {1,pack(SCR_PCC)}, cheri_exc_code: PermitASRViolation});
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
(* noinline *)
|
||||
function Maybe#(BoundsCheck) prepareBoundsCheck(CapPipe a, CapPipe b, CapChecks toCheck);
|
||||
function Maybe#(BoundsCheck) prepareBoundsCheck(CapPipe a, CapPipe b, CapPipe pcc,
|
||||
CapPipe ddc, Data vaddr, Bit#(5) size, // These two are only used in the memory pipe. May factor into two functions later.
|
||||
CapChecks toCheck);
|
||||
BoundsCheck ret = ?;
|
||||
CapPipe authority = ?;
|
||||
case(toCheck.check_authority_src)
|
||||
@@ -90,6 +95,14 @@ function Maybe#(BoundsCheck) prepareBoundsCheck(CapPipe a, CapPipe b, CapChecks
|
||||
authority = b;
|
||||
ret.authority_idx = toCheck.rn2;
|
||||
end
|
||||
Pcc: begin
|
||||
authority = pcc;
|
||||
ret.authority_idx = 6'b100000; // Not sure where the register number of PCC is defined...
|
||||
end
|
||||
Ddc: begin
|
||||
authority = ddc;
|
||||
ret.authority_idx = 6'b100001; // Not sure where the register number of PCC is defined...
|
||||
end
|
||||
endcase
|
||||
ret.authority_base = getBase(authority);
|
||||
ret.authority_top = getTop(authority);
|
||||
@@ -99,6 +112,7 @@ function Maybe#(BoundsCheck) prepareBoundsCheck(CapPipe a, CapPipe b, CapChecks
|
||||
Src1Base: ret.check_low = getBase(a);
|
||||
Src2Addr: ret.check_low = getAddr(b);
|
||||
Src2Type: ret.check_low = zeroExtend(getType(b));
|
||||
Vaddr: ret.check_low = vaddr;
|
||||
endcase
|
||||
|
||||
case(toCheck.check_high_src)
|
||||
@@ -107,6 +121,7 @@ function Maybe#(BoundsCheck) prepareBoundsCheck(CapPipe a, CapPipe b, CapChecks
|
||||
Src2Addr: ret.check_high = {1'b0,getAddr(b)};
|
||||
Src2Type: ret.check_high = zeroExtend(getType(b));
|
||||
ResultTop: ret.check_high = {1'b0,getAddr(a)} + {1'b0,getAddr(b)};
|
||||
VaddrPlusSize: ret.check_high = {1'b0,vaddr} + zeroExtend(size);
|
||||
endcase
|
||||
|
||||
ret.check_inclusive = toCheck.check_inclusive;
|
||||
@@ -267,7 +282,7 @@ function CapPipe brAddrCalc(CapPipe pc, CapPipe val, IType iType, Data imm, Bool
|
||||
Br : (taken? branchTarget : pcPlusN);
|
||||
default : pcPlusN;
|
||||
endcase);
|
||||
return targetAddr;
|
||||
return setType(targetAddr, -1);
|
||||
endfunction
|
||||
/*
|
||||
(* noinline *)
|
||||
@@ -304,15 +319,22 @@ function ExecResult basicExec(DecodedInst dInst, CapPipe rVal1, CapPipe rVal2, C
|
||||
|
||||
CapPipe cap_alu_result = capALU(rVal1, aluVal2, dInst.capFunc);
|
||||
CapPipe link_pcc = addPc(pcc, ((orig_inst [1:0] == 2'b11) ? 4 : 2));
|
||||
Maybe#(CapException) capException = capChecks(rVal1, aluVal2, dInst.capChecks, link_pcc);
|
||||
Maybe#(BoundsCheck) boundsCheck = prepareBoundsCheck(rVal1, aluVal2, dInst.capChecks);
|
||||
|
||||
// Default branch function is not taken
|
||||
BrFunc br_f = dInst.execFunc matches tagged Br .br_f ? br_f : NT;
|
||||
cf.taken = aluBr(getAddr(rVal1), getAddr(rVal2), br_f);
|
||||
cf.nextPc = brAddrCalc(pcc, rVal1, dInst.iType, fromMaybe(0,getDInstImm(dInst)), cf.taken, orig_inst, newPcc);
|
||||
if (dInst.execFunc matches tagged Br .unused) begin
|
||||
rVal1 = cf.nextPc;
|
||||
if (!cf.taken) dInst.capChecks.check_enable = False;
|
||||
end
|
||||
cf.mispredict = cf.nextPc != ppc;
|
||||
|
||||
Maybe#(CSR_XCapCause) capException = capChecks(rVal1, aluVal2, nullCap, dInst.capChecks);
|
||||
Maybe#(BoundsCheck) boundsCheck = prepareBoundsCheck(rVal1, aluVal2, pcc,
|
||||
nullCap, 0, 0, // These three are only used in the memory pipe
|
||||
dInst.capChecks);
|
||||
|
||||
data = (case (dInst.iType) matches
|
||||
St : rVal2;
|
||||
Sc : rVal2;
|
||||
@@ -339,10 +361,12 @@ function ExecResult basicExec(DecodedInst dInst, CapPipe rVal1, CapPipe rVal2, C
|
||||
endfunction
|
||||
|
||||
(* noinline *)
|
||||
function Maybe#(Exception) checkForException(
|
||||
function Maybe#(Trap) checkForException(
|
||||
DecodedInst dInst,
|
||||
ArchRegs regs,
|
||||
CsrDecodeInfo csrState
|
||||
CsrDecodeInfo csrState,
|
||||
CapMem pcc,
|
||||
Bool fourByteInst
|
||||
); // regs needed to check if x0 is a src
|
||||
Maybe#(Exception) exception = Invalid;
|
||||
let prv = csrState.prv;
|
||||
@@ -425,12 +449,24 @@ function Maybe#(Exception) checkForException(
|
||||
end
|
||||
end
|
||||
|
||||
return exception;
|
||||
// Check that the end of the instruction is in bounds of PCC.
|
||||
CapPipe pcc_end = cast(addPc(pcc, (fourByteInst?4:2)));
|
||||
Maybe#(CSR_XCapCause) capException = Invalid;
|
||||
if (!isInBounds(pcc_end, True)) capException = Valid(CSR_XCapCause{cheri_exc_reg: {1'b1,pack(SCR_PCC)}, cheri_exc_code: LengthViolation});
|
||||
|
||||
Maybe#(Trap) retval = Invalid;
|
||||
if (capException matches tagged Valid .ce) retval = Valid(CapException(ce));
|
||||
else if (exception matches tagged Valid .e) retval = Valid(Exception(e));
|
||||
|
||||
return retval;
|
||||
endfunction
|
||||
|
||||
// check mem access misaligned: byteEn is unshifted (just from Decode)
|
||||
function Bool memAddrMisaligned(Addr addr, ByteEn byteEn);
|
||||
if(byteEn[7]) begin
|
||||
function Bool memAddrMisaligned(Addr addr, MemDataByteEn byteEn);
|
||||
if(byteEn[15]) begin
|
||||
return addr[3:0] != 0;
|
||||
end
|
||||
else if(byteEn[7]) begin
|
||||
return addr[2:0] != 0;
|
||||
end
|
||||
else if(byteEn[3]) begin
|
||||
@@ -444,21 +480,24 @@ function Bool memAddrMisaligned(Addr addr, ByteEn byteEn);
|
||||
end
|
||||
endfunction
|
||||
|
||||
function Data gatherLoad(Addr addr, ByteEn byteEn, Bool unsignedLd, Data data);
|
||||
function MemTaggedData gatherLoad( Addr addr, MemDataByteEn byteEn
|
||||
, Bool unsignedLd, MemTaggedData data);
|
||||
function extend = unsignedLd ? zeroExtend : signExtend;
|
||||
Bit#(IndxShamt) offset = truncate(addr);
|
||||
|
||||
if(byteEn[7]) begin
|
||||
return extend(data);
|
||||
if(pack(byteEn) == ~0) return data;
|
||||
else if(byteEn[7]) begin
|
||||
Vector#(2, Bit#(64)) dataVec = unpack(pack(data.data));
|
||||
return dataToMemTaggedData(extend(dataVec[offset[3]]));
|
||||
end else if(byteEn[3]) begin
|
||||
Vector#(2, Bit#(32)) dataVec = unpack(data);
|
||||
return extend(dataVec[offset[2]]);
|
||||
Vector#(4, Bit#(32)) dataVec = unpack(pack(data.data));
|
||||
return dataToMemTaggedData(extend(dataVec[offset[3:2]]));
|
||||
end else if(byteEn[1]) begin
|
||||
Vector#(4, Bit#(16)) dataVec = unpack(data);
|
||||
return extend(dataVec[offset[2:1]]);
|
||||
Vector#(8, Bit#(16)) dataVec = unpack(pack(data.data));
|
||||
return dataToMemTaggedData(extend(dataVec[offset[3:1]]));
|
||||
end else begin
|
||||
Vector#(8, Bit#(8)) dataVec = unpack(data);
|
||||
return extend(dataVec[offset]);
|
||||
Vector#(16, Bit#(8)) dataVec = unpack(pack(data.data));
|
||||
return dataToMemTaggedData(extend(dataVec[offset]));
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// This package implements utility functions used by the floating point
|
||||
// related logic
|
||||
package FP_Utils;
|
||||
import Types::*;
|
||||
import FloatingPoint::*;
|
||||
|
||||
function FloatingPoint#(e,m) canonicalNaN = FloatingPoint{sign: False, exp: '1, sfd: 1 << (valueof(m)-1)};
|
||||
@@ -19,6 +20,9 @@ function Bit #(64) fv_nanbox (Bit #(64) x);
|
||||
Bit #(64) fill_mask = (fill_bits << 32); // [63:32] all ones
|
||||
return (x | fill_mask);
|
||||
endfunction
|
||||
function MemTaggedData fv_nanbox_MemTaggedData (MemTaggedData x) =
|
||||
MemTaggedData { tag: x.tag
|
||||
, data: dataToMemData(fv_nanbox(memDataToData(x.data))) };
|
||||
|
||||
// Take a 64-bit value and check if it is properly nanboxed if operating in a DP
|
||||
// capable environment. If not properly nanboxed, return canonicalNaN32
|
||||
@@ -28,7 +32,7 @@ function Float fv_unbox (Bit #(64) x);
|
||||
return (unpack (x [31:0]));
|
||||
else
|
||||
return (canonicalNaN);
|
||||
//`else
|
||||
//`else
|
||||
// return (unpack (x [31:0]));
|
||||
//`endif
|
||||
endfunction
|
||||
|
||||
@@ -111,16 +111,6 @@ function Bool fn_addr_is_in_line (Addr addr, Addr line_addr);
|
||||
return (fn_align_addr_to_line (addr) == line_addr);
|
||||
endfunction
|
||||
|
||||
function Bit #(64) fn_expand_strb_to_mask (Bit #(8) strb);
|
||||
function Bit #(8) fn_bit_to_byte (Integer j);
|
||||
return ((strb [j] == 1'b1) ? 8'hFF : 8'h00);
|
||||
endfunction
|
||||
|
||||
Vector #(8, Bit #(8)) v = genWith (fn_bit_to_byte);
|
||||
|
||||
return pack (v);
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
|
||||
module mkLLCDmaConnect #(
|
||||
@@ -163,19 +153,13 @@ module mkLLCDmaConnect #(
|
||||
rg_cacheline_cache_addr)));
|
||||
let wr_addr <- get (axi4_slave_xactor.master.aw);
|
||||
let wr_data <- get (axi4_slave_xactor.master.w);
|
||||
Addr addr = wr_addr.awaddr;
|
||||
Bit #(64) data = wr_data.wdata;
|
||||
Bit #(64) mask = fn_expand_strb_to_mask (wr_data.wstrb);
|
||||
|
||||
// Read rg_cacheline_cache_data as 64-bit words
|
||||
Vector #(8, Bit #(64)) line_dwords = unpack (pack (rg_cacheline_cache_data));
|
||||
// Modify relevant bytes of relevant dword
|
||||
Bit #(3) dword_in_line = addr [5:3];
|
||||
Bit #(64) old_dword = line_dwords [dword_in_line];
|
||||
Bit #(64) new_dword = ((old_dword & (~ mask)) | (data & mask));
|
||||
line_dwords [dword_in_line] = new_dword;
|
||||
let newLine = setDataAtBE( rg_cacheline_cache_data
|
||||
, getCLineDataSel(wr_addr.awaddr)
|
||||
, wr_data.wdata, unpack(pack(wr_data.wstrb)));
|
||||
// Save it
|
||||
rg_cacheline_cache_data <= unpack (pack (line_dwords));
|
||||
rg_cacheline_cache_data <= newLine;
|
||||
rg_cacheline_cache_state <= CACHELINE_CACHE_DIRTY;
|
||||
rg_cacheline_cache_dirty_delay <= '1; // start write-back delay countdown
|
||||
|
||||
@@ -189,8 +173,8 @@ module mkLLCDmaConnect #(
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_handle_MemLoader_st_req: addr %0h data %0h strb %0h",
|
||||
cur_cycle, wr_addr.awaddr, wr_data.wdata, wr_data.wstrb);
|
||||
$display (" old_dword: %0h", old_dword);
|
||||
$display (" new_dword: %0h", old_dword);
|
||||
//$display (" old_dword: %0h", old_dword);
|
||||
//$display (" new_dword: %0h", old_dword);
|
||||
end
|
||||
endrule
|
||||
|
||||
@@ -203,12 +187,8 @@ module mkLLCDmaConnect #(
|
||||
&& (fn_addr_is_in_line (axi4_slave_xactor.master.ar.peek.araddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let rd_addr <- get (axi4_slave_xactor.master.ar);
|
||||
Addr addr = rd_addr.araddr;
|
||||
|
||||
// Read rg_cacheline_cache as 64-bit words
|
||||
Vector #(8, Bit #(64)) line_dwords = unpack (pack (rg_cacheline_cache_data));
|
||||
Bit #(3) dword_in_line = addr [5:3];
|
||||
Bit #(64) dword = line_dwords [dword_in_line];
|
||||
let dword = getDataAt( rg_cacheline_cache_data
|
||||
, getCLineDataSel(rd_addr.araddr));
|
||||
|
||||
// Send response to external client
|
||||
axi4_slave_xactor.master.r.put(AXI4_RFlit{
|
||||
@@ -237,7 +217,7 @@ module mkLLCDmaConnect #(
|
||||
function Action fa_writeback;
|
||||
action
|
||||
dmaRqT req = DmaRq {addr: rg_cacheline_cache_addr,
|
||||
byteEn: replicate (True), // Write all bytes
|
||||
byteEn: replicate(replicate(True)), // Write all bytes
|
||||
data: rg_cacheline_cache_data,
|
||||
id: tagged MemLoader (?) // TODO: use wr_addr.awid?
|
||||
};
|
||||
@@ -305,7 +285,7 @@ module mkLLCDmaConnect #(
|
||||
action
|
||||
let line_addr = fn_align_addr_to_line (addr);
|
||||
dmaRqT req = DmaRq {addr: line_addr,
|
||||
byteEn: replicate (False), // all False means 'read'
|
||||
byteEn: replicate(replicate(False)), // all False means 'read'
|
||||
data: ?,
|
||||
id: tagged MemLoader (?)}; // TODO: change uniformly to wr_addr.awid
|
||||
llc.memReq.enq (req);
|
||||
@@ -384,7 +364,7 @@ module mkLLCDmaConnect #(
|
||||
};
|
||||
return DmaRq {
|
||||
addr: r.addr,
|
||||
byteEn: replicate(False), // tlb req is always load
|
||||
byteEn: replicate(replicate(False)), // tlb req is always load
|
||||
data: ?,
|
||||
id: Tlb (id)
|
||||
};
|
||||
@@ -410,7 +390,7 @@ module mkLLCDmaConnect #(
|
||||
llc.respLd.deq;
|
||||
let resp = llc.respLd.first;
|
||||
let ld = TlbLdResp {
|
||||
data: resp.data[id.dataSel],
|
||||
data: getDataAt(resp.data, id.dataSel),
|
||||
id: id.id
|
||||
};
|
||||
tlb[id.core].respLd.enq(ld);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2018 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -115,13 +114,14 @@ module mkMMIOCore#(MMIOCoreInput inIfc)(MMIOCore);
|
||||
if(req.func matches tagged Amo .amoFunc) begin
|
||||
let amoInst = AmoInst {
|
||||
func: amoFunc,
|
||||
doubleWord: False,
|
||||
width: Word,
|
||||
aq: False,
|
||||
rl: False
|
||||
};
|
||||
let newData = amoExec(amoInst, zeroExtend(msip),
|
||||
zeroExtend(req.data), False);
|
||||
inIfc.setMSIP(newData[0]);
|
||||
let newData =
|
||||
amoExec(amoInst, 0, toMemTaggedData(msip),
|
||||
toMemTaggedData(req.data));
|
||||
inIfc.setMSIP(pack(newData.data)[0]);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +7,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
|
||||
@@ -113,7 +112,7 @@ module mkMemLoader#(Clock portalClk, Reset portalRst)(MemLoader);
|
||||
Reg#(LineDataOffset) reqSel <- mkRegU;
|
||||
Reg#(LineAddr) reqAddr <- mkRegU;
|
||||
Reg#(Line) reqData <- mkRegU;
|
||||
Reg#(Vector#(LineSzData, Bit#(DataSzBytes))) reqBE <- mkRegU;
|
||||
Reg#(LineByteEn) reqBE <- mkRegU;
|
||||
|
||||
// sync FIFOs to cross to portal clk
|
||||
Clock userClk <- exposeCurrentClock;
|
||||
@@ -137,7 +136,7 @@ module mkMemLoader#(Clock portalClk, Reset portalRst)(MemLoader);
|
||||
expectWrData <= True;
|
||||
reqSel <= getLineDataOffset(req.addr);
|
||||
reqAddr <= getLineAddr(req.addr);
|
||||
reqBE <= replicate(0);
|
||||
reqBE <= replicate(replicate(False));
|
||||
// check addr align to Data
|
||||
Bit#(LgDataSzBytes) offset = truncate(req.addr);
|
||||
doAssert(offset == 0, "write addr not aligned to Data");
|
||||
@@ -157,13 +156,12 @@ module mkMemLoader#(Clock portalClk, Reset portalRst)(MemLoader);
|
||||
hostWrDataQ.deq;
|
||||
HostWrData wr = hostWrDataQ.first;
|
||||
// merge with req data & BE
|
||||
Line newData = reqData;
|
||||
Vector#(LineSzData, Bit#(DataSzBytes)) newBE = reqBE;
|
||||
newData[reqSel] = wr.data;
|
||||
newBE[reqSel] = wr.byteEn;
|
||||
Line newLine = setDataAt(reqData, reqSel, wr.data);
|
||||
LineDataByteEn newBE = unpack(pack(reqBE));
|
||||
newBE[reqSel] = unpack(pack(wr.byteEn));
|
||||
// common state update
|
||||
expectWrData <= !wr.last;
|
||||
reqData <= newData;
|
||||
reqData <= newLine;
|
||||
reqSel <= reqSel + 1;
|
||||
reqAddr <= reqSel == maxBound ? reqAddr + 1 : reqAddr;
|
||||
// print
|
||||
@@ -177,16 +175,16 @@ module mkMemLoader#(Clock portalClk, Reset portalRst)(MemLoader);
|
||||
MemLoaderMemReq req = DmaRq {
|
||||
addr: {reqAddr, 0},
|
||||
byteEn: unpack(pack(newBE)),
|
||||
data: newData,
|
||||
data: newLine,
|
||||
id: ?
|
||||
};
|
||||
if(verbose) begin
|
||||
$display("[MemLoader doStReq] req to LLC ", fshow(req));
|
||||
end
|
||||
// reset BE for next fresh LLC req
|
||||
reqBE <= replicate(0);
|
||||
reqBE <= replicate(replicate(False));
|
||||
// only send real write to LLC, otherwise may spawn orphan read resp
|
||||
if(req.byteEn != replicate(False)) begin
|
||||
if(req.byteEn != replicate(replicate(False))) begin
|
||||
memReqQ.enq(req);
|
||||
pendStCnt <= pendStCnt + 1;
|
||||
end
|
||||
@@ -195,7 +193,7 @@ module mkMemLoader#(Clock portalClk, Reset portalRst)(MemLoader);
|
||||
end
|
||||
end
|
||||
else begin
|
||||
reqBE <= newBE;
|
||||
reqBE <= unpack(pack(newBE));
|
||||
end
|
||||
endrule
|
||||
|
||||
@@ -225,7 +223,7 @@ module mkMemLoader#(Clock portalClk, Reset portalRst)(MemLoader);
|
||||
if(wrBE == replicate(False)) begin
|
||||
return MMIODataPRs {
|
||||
valid: True,
|
||||
data: offset == 0 ? memStartAddr : zeroExtend(pack(busy))
|
||||
data: offset == 0 ? toMemTaggedData(memStartAddr) : toMemTaggedData(busy)
|
||||
};
|
||||
end
|
||||
else begin
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +8,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
|
||||
@@ -29,7 +29,7 @@ import ClientServer::*;
|
||||
// typedefs for mem access performed by processor
|
||||
// cache line is defined in CacheUtils.bsv
|
||||
|
||||
typedef Data MemResp;
|
||||
typedef MemTaggedData MemResp;
|
||||
|
||||
typedef enum{Ld, St, Lr, Sc, Amo} MemOp deriving(Eq,Bits,FShow); // add more ops
|
||||
|
||||
@@ -40,4 +40,3 @@ Bit#(3) memD = 3'b011;
|
||||
Bit#(3) memBU = 3'b100;
|
||||
Bit#(3) memHU = 3'b101;
|
||||
Bit#(3) memWU = 3'b110;
|
||||
|
||||
|
||||
@@ -397,15 +397,11 @@ typedef 12 InterruptNum; // Without debugger
|
||||
|
||||
// Traps are either an exception or an interrupt
|
||||
typedef union tagged {
|
||||
CapException CapException;
|
||||
Exception Exception;
|
||||
Interrupt Interrupt;
|
||||
} Trap deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
Trap trap;
|
||||
CSR_XCapCause capExp;
|
||||
} TrapWithCap deriving(Bits, FShow);
|
||||
|
||||
// privilege modes
|
||||
Bit#(2) prvU = 0;
|
||||
Bit#(2) prvS = 1;
|
||||
@@ -509,14 +505,17 @@ typedef struct {
|
||||
|
||||
typedef enum {
|
||||
Src1,
|
||||
Src2
|
||||
Src2,
|
||||
Pcc,
|
||||
Ddc
|
||||
} CheckAuthoritySrc deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef enum {
|
||||
Src1Addr,
|
||||
Src2Addr,
|
||||
Src2Type,
|
||||
Src1Base
|
||||
Src1Base,
|
||||
Vaddr // Memory Pipe
|
||||
} CheckLowSrc deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef enum {
|
||||
@@ -524,7 +523,8 @@ typedef enum {
|
||||
Src1Top,
|
||||
Src2Addr,
|
||||
Src2Type,
|
||||
ResultTop
|
||||
ResultTop,
|
||||
VaddrPlusSize // Memory Pipe
|
||||
} CheckHighSrc deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
@@ -619,10 +619,10 @@ typedef struct {
|
||||
// this. We need this for to remove redundant MMIO accesses (for MSIP), and
|
||||
// to determine AMO access range (upper 32 bits, lower 32 bits, or full 64
|
||||
// bits). INST FETCH will not specify this field.
|
||||
ByteEn byteEn;
|
||||
MemDataByteEn byteEn;
|
||||
// For STORE: this is store data shifted to be 64-bit aligned
|
||||
// For AMO: this is UNshifted data (like normal mem req)
|
||||
Data data;
|
||||
MemTaggedData data;
|
||||
} MMIOCRq deriving(Bits, Eq, FShow);
|
||||
|
||||
// resp from platform to core
|
||||
@@ -634,7 +634,7 @@ typedef struct {
|
||||
// shift the result before writting back to reg).
|
||||
// For AMO: this is the result that can be directly written into reg, i.e.,
|
||||
// for 32-bit access, the result has been shifted and sign-extended.
|
||||
Data data;
|
||||
MemTaggedData data;
|
||||
} MMIODataPRs deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef union tagged {
|
||||
@@ -666,7 +666,7 @@ typedef struct {
|
||||
|
||||
// Boot rom: each block is 64-bit data
|
||||
typedef `LOG_BOOT_ROM_BYTES LgBootRomBytes;
|
||||
typedef TSub#(LgBootRomBytes, TLog#(NumBytes)) LgBootRomSzData;
|
||||
typedef TSub#(LgBootRomBytes, TLog#(MemDataBytes)) LgBootRomSzData;
|
||||
typedef Bit#(LgBootRomSzData) BootRomIndex;
|
||||
|
||||
// mtime: we increment mtime by 50 every 5000 cycles, this simulates a
|
||||
@@ -753,6 +753,7 @@ Bit#(5) opFCVT_FW = 5'b11010;
|
||||
//MiscMem
|
||||
Bit#(3) fnFENCE = 3'b000;
|
||||
Bit#(3) fnFENCEI = 3'b001;
|
||||
Bit#(3) fnLC = 3'b010;
|
||||
|
||||
// System
|
||||
Bit#(3) fnPRIV = 3'b000;
|
||||
|
||||
@@ -74,7 +74,7 @@ typedef struct {
|
||||
Maybe#(SCR) scr;
|
||||
Maybe#(CSR) csr;
|
||||
Bool claimed_phy_reg; // whether we need to commmit renaming
|
||||
Maybe#(TrapWithCap)trap;
|
||||
Maybe#(Trap) trap;
|
||||
Addr tval; // in case of trap
|
||||
PPCVAddrCSRData ppc_vaddr_csrData;
|
||||
Bit#(5) fflags;
|
||||
@@ -158,7 +158,7 @@ interface ReorderBufferRowEhr#(numeric type aluExeNum, numeric type fpuMulDivExe
|
||||
method Action setExecuted_doFinishMem(CapPipe vaddr,
|
||||
Data store_data, ByteEn store_data_BE,
|
||||
Bool access_at_commit, Bool non_mmio_st_done,
|
||||
Maybe#(Exception) cause
|
||||
Maybe#(CSR_XCapCause) cause
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle tb
|
||||
`endif
|
||||
@@ -240,7 +240,7 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
|
||||
Integer sb_enq_port = 1; // write spec_bits
|
||||
Integer sb_correctSpec_port = 2; // write spec_bits
|
||||
|
||||
Ehr#(TAdd#(2, aluExeNum), CapMem) pc <- mkEhr(?);
|
||||
Ehr#(TAdd#(2, aluExeNum), CapMem) pc <- mkEhr(?);
|
||||
Reg #(Bit #(32)) orig_inst <- mkRegU;
|
||||
Reg#(IType) iType <- mkRegU;
|
||||
Reg #(Maybe #(ArchRIndx)) rg_dst_reg <- mkRegU;
|
||||
@@ -252,8 +252,8 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
|
||||
Reg#(Maybe#(CSR)) csr <- mkRegU;
|
||||
Reg#(Maybe#(SCR)) scr <- mkRegU;
|
||||
Reg#(Bool) claimed_phy_reg <- mkRegU;
|
||||
Ehr#(TAdd#(TAdd#(2, TDiv#(aluExeNum,2)), aluExeNum), Maybe#(TrapWithCap)) trap <- mkEhr(?);
|
||||
Ehr#(3, Maybe#(TrapWithCap)) mem_early_trap <- mkEhr(?);
|
||||
Ehr#(TAdd#(TAdd#(2, TDiv#(aluExeNum,2)), aluExeNum), Maybe#(Trap)) trap <- mkEhr(?);
|
||||
Ehr#(3, Maybe#(Trap)) mem_early_trap <- mkEhr(?);
|
||||
Ehr#(TAdd#(TAdd#(2, TDiv#(aluExeNum,2)), aluExeNum), Addr) tval <- mkEhr(?);
|
||||
Ehr#(TAdd#(2, aluExeNum), PPCVAddrCSRData) ppc_vaddr_csrData <- mkEhr(?);
|
||||
Ehr#(TAdd#(1, fpuMulDivExeNum), Bit#(5)) fflags <- mkEhr(?);
|
||||
@@ -309,7 +309,7 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
|
||||
ppc_vaddr_csrData[pvc_finishAlu_port(i)] <= PPC (cast(cf.nextPc));
|
||||
end
|
||||
if (cause matches tagged Valid .exp) begin
|
||||
trap[trap_finishAlu_port(i)] <= Valid (TrapWithCap{trap: tagged Exception CHERIFault, capExp: exp});
|
||||
trap[trap_finishAlu_port(i)] <= Valid (CapException (exp));
|
||||
tval[trap_finishAlu_port(i)] <= tval[trap_finishAlu_port(i)];
|
||||
end
|
||||
`ifdef RVFI
|
||||
@@ -337,7 +337,7 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
|
||||
// update fflags
|
||||
fflags[fflags_finishFpuMulDiv_port(i)] <= new_fflags;
|
||||
if (cause matches tagged Valid .exp) begin
|
||||
trap[trap_finishFpuMulDiv_port(i)] <= Valid (TrapWithCap{trap: tagged Exception exp, capExp: noCapCause});
|
||||
trap[trap_finishFpuMulDiv_port(i)] <= Valid (Exception (exp));
|
||||
tval[trap_finishFpuMulDiv_port(i)] <= tval[trap_finishAlu_port(i)];
|
||||
end
|
||||
`ifdef RVFI
|
||||
@@ -359,7 +359,7 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
|
||||
method Action setExecuted_doFinishMem(CapPipe vaddr,
|
||||
Data store_data, ByteEn store_data_BE,
|
||||
Bool access_at_commit, Bool non_mmio_st_done,
|
||||
Maybe#(Exception) cause
|
||||
Maybe#(CSR_XCapCause) cause
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle tb
|
||||
`endif
|
||||
@@ -387,7 +387,7 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
|
||||
// udpate non mmio st
|
||||
nonMMIOStDone[nonMMIOSt_finishMem_port] <= non_mmio_st_done;
|
||||
if (cause matches tagged Valid .exp) begin
|
||||
mem_early_trap[0] <= Valid (TrapWithCap{trap: tagged Exception exp, capExp: noCapCause});
|
||||
mem_early_trap[0] <= Valid ( CapException (exp));
|
||||
tval[trap_finishMem_port] <= tval[trap_finishMem_port];
|
||||
end
|
||||
endmethod
|
||||
@@ -516,7 +516,7 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
|
||||
// record trap
|
||||
//doAssert(!isValid(trap[trap_deqLSQ_port]), "cannot have trap");
|
||||
if (isValid(mem_early_trap[0])) trap[trap_deqLSQ_port] <= mem_early_trap[0];
|
||||
else if(cause matches tagged Valid .e) trap[trap_deqLSQ_port] <= Valid (TrapWithCap{trap: tagged Exception e, capExp: noCapCause});
|
||||
else if(cause matches tagged Valid .e) trap[trap_deqLSQ_port] <= Valid(Exception(e));
|
||||
// TODO: shouldn't we record tval here as well?
|
||||
// record ld misspeculation
|
||||
ldKilled[ldKill_deqLSQ_port] <= ld_killed;
|
||||
@@ -630,7 +630,7 @@ interface SupReorderBuffer#(numeric type aluExeNum, numeric type fpuMulDivExeNum
|
||||
CapPipe vaddr,
|
||||
Data store_data, ByteEn store_data_BE,
|
||||
Bool access_at_commit, Bool non_mmio_st_done,
|
||||
Maybe#(Exception) cause
|
||||
Maybe#(CSR_XCapCause) cause
|
||||
`ifdef RVFI
|
||||
, ExtraTraceBundle tb
|
||||
`endif
|
||||
@@ -1243,7 +1243,7 @@ module mkSupReorderBuffer#(
|
||||
|
||||
method Action setExecuted_doFinishMem(
|
||||
InstTag x, CapPipe vaddr, Data store_data, ByteEn store_data_BE, Bool access_at_commit,
|
||||
Bool non_mmio_st_done, Maybe#(Exception) cause
|
||||
Bool non_mmio_st_done, Maybe#(CSR_XCapCause) cause
|
||||
`ifdef RVFI
|
||||
, tb
|
||||
`endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright (c) 2018 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +8,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
|
||||
@@ -128,7 +128,7 @@ typedef struct {
|
||||
Bool isMMIO;
|
||||
// byte enable after shift to align with dword boudary. This is valid
|
||||
// for all types of memory accesses.
|
||||
ByteEn shiftedBE;
|
||||
MemDataByteEn shiftedBE;
|
||||
|
||||
// ===================
|
||||
// Status bits of the Ld. Typically we don't need to reset any bit as the
|
||||
@@ -220,12 +220,12 @@ typedef struct {
|
||||
Bool isMMIO;
|
||||
// byte enable after shift to align with dword boudary. This is valid
|
||||
// for all types of memory accesses.
|
||||
ByteEn shiftedBE;
|
||||
MemDataByteEn shiftedBE;
|
||||
// St/Sc/Amo data
|
||||
// for St/Sc: store data after shift to align with dword boudary
|
||||
// for Amo: data is **NOT** shifted, this doesn't affect forwarding to Ld,
|
||||
// because AMO never forwards data
|
||||
Data stData;
|
||||
MemTaggedData stData;
|
||||
|
||||
// ===================
|
||||
// status bits of St/Sc/Amo
|
||||
@@ -260,7 +260,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
Maybe#(PhyDst) dst;
|
||||
Data data; // align with dword, not final result written to reg file
|
||||
MemTaggedData data; // align with dword, not final result written to reg file
|
||||
} LSQForwardResult deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef enum {LdQ, StQ, SB} LdStalledBy deriving(Bits, Eq, FShow);
|
||||
@@ -274,7 +274,7 @@ typedef union tagged {
|
||||
typedef struct {
|
||||
LdQTag tag;
|
||||
Addr paddr;
|
||||
ByteEn shiftedBE;
|
||||
MemDataByteEn shiftedBE;
|
||||
} LSQIssueLdInfo deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
@@ -283,7 +283,7 @@ typedef struct {
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
InstTag instTag; // For recording Ld data in ROB
|
||||
`endif
|
||||
Data data;
|
||||
MemTaggedData data;
|
||||
} LSQRespLdResult deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
@@ -295,14 +295,14 @@ typedef struct {
|
||||
LdQTag tag;
|
||||
InstTag instTag;
|
||||
LdQMemFunc memFunc;
|
||||
ByteEn byteEn;
|
||||
MemDataByteEn byteEn;
|
||||
Bool unsignedLd;
|
||||
Bool acq;
|
||||
Bool rel;
|
||||
Maybe#(PhyDst) dst;
|
||||
Addr paddr;
|
||||
Bool isMMIO;
|
||||
ByteEn shiftedBE;
|
||||
MemDataByteEn shiftedBE;
|
||||
Maybe#(Exception) fault;
|
||||
Maybe#(LdKilledBy) killed;
|
||||
} LdQDeqEntry deriving (Bits, Eq, FShow);
|
||||
@@ -316,8 +316,8 @@ typedef struct {
|
||||
Maybe#(PhyDst) dst;
|
||||
Addr paddr;
|
||||
Bool isMMIO;
|
||||
ByteEn shiftedBE;
|
||||
Data stData;
|
||||
MemDataByteEn shiftedBE;
|
||||
MemTaggedData stData;
|
||||
Maybe#(Exception) fault;
|
||||
} StQDeqEntry deriving (Bits, Eq, FShow);
|
||||
|
||||
@@ -336,29 +336,29 @@ interface SplitLSQ;
|
||||
Maybe#(PhyDst) dst,
|
||||
SpecBits spec_bits);
|
||||
// A mem inst needs orignal BE (not shifted) at addr translation
|
||||
method ByteEn getOrigBE(LdStQTag t);
|
||||
method MemDataByteEn getOrigBE(LdStQTag t);
|
||||
// Retrieve information when we want to wakeup RS early in case
|
||||
// Ld/Lr/Sc/Amo hits in cache
|
||||
method ActionValue#(LSQHitInfo) getHit(LdStQTag t);
|
||||
// update store data (shifted for St and Sc, unshifted for AMO). XXX we
|
||||
// assume data is updated before addr is updated
|
||||
method Action updateData(StQTag t, Data d);
|
||||
method Action updateData(StQTag t, MemTaggedData d);
|
||||
// Update addr after address translation. Also search for the (oldest)
|
||||
// younger load to kill. Return if the entry is waiting for wrong path
|
||||
// resp, so Ld can be issued immediately.
|
||||
method ActionValue#(LSQUpdateAddrResult) updateAddr(
|
||||
LdStQTag lsqTag, Maybe#(Exception) fault,
|
||||
// below are only meaningful wen fault is Invalid
|
||||
Addr paddr, Bool isMMIO, ByteEn shiftedBE
|
||||
Addr paddr, Bool isMMIO, MemDataByteEn shiftedBE
|
||||
);
|
||||
// Issue a load, and remove dependence on this load issue.
|
||||
method ActionValue#(LSQIssueLdResult) issueLd(
|
||||
LdQTag lsqTag, Addr paddr, ByteEn shiftedBE, SBSearchRes sbRes
|
||||
LdQTag lsqTag, Addr paddr, MemDataByteEn shiftedBE, SBSearchRes sbRes
|
||||
);
|
||||
// Get the load to issue
|
||||
method ActionValue#(LSQIssueLdInfo) getIssueLd;
|
||||
// Get load resp
|
||||
method ActionValue#(LSQRespLdResult) respLd(LdQTag t, Data alignedData);
|
||||
method ActionValue#(LSQRespLdResult) respLd(LdQTag t, MemTaggedData alignedData);
|
||||
// Deq LQ entry, and wakeup stalled loads. The guard checks the following:
|
||||
// (1) valid
|
||||
// (2) one of the following is true:
|
||||
@@ -444,7 +444,7 @@ endinterface
|
||||
typedef Bit#(TLog#(TMul#(2, LdQSize))) LdQVirTag;
|
||||
typedef Bit#(TLog#(TMul#(2, StQSize))) StQVirTag;
|
||||
|
||||
typedef Bit#(TSub#(AddrSz, TLog#(NumBytes))) DataAlignedAddr;
|
||||
typedef Bit#(TSub#(AddrSz, TLog#(MemDataBytes))) DataAlignedAddr;
|
||||
function DataAlignedAddr getDataAlignedAddr(Addr a) = truncateLSB(a);
|
||||
|
||||
// whether two memory accesses are to the same dword
|
||||
@@ -453,28 +453,30 @@ function Bool sameAlignedAddr(Addr a, Addr b);
|
||||
endfunction
|
||||
|
||||
// whether two memory accesses overlap
|
||||
function Bool overlapAddr(Addr addr_1, ByteEn shift_be_1,
|
||||
Addr addr_2, ByteEn shift_be_2);
|
||||
function Bool overlapAddr(Addr addr_1, MemDataByteEn shift_be_1,
|
||||
Addr addr_2, MemDataByteEn shift_be_2);
|
||||
Bool be_overlap = (pack(shift_be_1) & pack(shift_be_2)) != 0;
|
||||
return be_overlap && sameAlignedAddr(addr_1, addr_2);
|
||||
endfunction
|
||||
|
||||
// check shiftBE1 covers shiftBE2
|
||||
function Bool be1CoverBe2(ByteEn shift_be_1, ByteEn shift_be_2);
|
||||
function Bool be1CoverBe2(MemDataByteEn shift_be_1, MemDataByteEn shift_be_2);
|
||||
return (pack(shift_be_1) & pack(shift_be_2)) == pack(shift_be_2);
|
||||
endfunction
|
||||
|
||||
// check whether mem op addr is aligned w.r.t data size
|
||||
function Bool checkAddrAlign(Addr paddr, ByteEn be);
|
||||
Bit#(TLog#(NumBytes)) byteOffset = truncate(paddr);
|
||||
if(be[7]) begin
|
||||
return byteOffset == 0;
|
||||
function Bool checkAddrAlign(Addr addr, MemDataByteEn byteEn);
|
||||
if(byteEn[15]) begin
|
||||
return addr[3:0] == 0;
|
||||
end
|
||||
else if(be[3]) begin
|
||||
return byteOffset[1:0] == 0;
|
||||
else if(byteEn[7]) begin
|
||||
return addr[2:0] == 0;
|
||||
end
|
||||
else if(be[1]) begin
|
||||
return byteOffset[0] == 0;
|
||||
else if(byteEn[3]) begin
|
||||
return addr[1:0] == 0;
|
||||
end
|
||||
else if(byteEn[1]) begin
|
||||
return addr[0] == 0;
|
||||
end
|
||||
else begin
|
||||
return True;
|
||||
@@ -614,13 +616,13 @@ module mkSplitLSQ(SplitLSQ);
|
||||
Vector#(LdQSize, Reg#(InstTag)) ld_instTag <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(LdQMemFunc)) ld_memFunc <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_unsigned <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(ByteEn)) ld_byteEn <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(MemDataByteEn)) ld_byteEn <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_acq <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_rel <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Maybe#(PhyDst))) ld_dst <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Ehr#(2, Addr)) ld_paddr <- replicateM(mkEhr(?));
|
||||
Vector#(LdQSize, Ehr#(2, Bool)) ld_isMMIO <- replicateM(mkEhr(?));
|
||||
Vector#(LdQSize, Ehr#(2, ByteEn)) ld_shiftedBE <- replicateM(mkEhr(?));
|
||||
Vector#(LdQSize, Ehr#(2, MemDataByteEn)) ld_shiftedBE <- replicateM(mkEhr(?));
|
||||
Vector#(LdQSize, Ehr#(2, Maybe#(Exception))) ld_fault <- replicateM(mkEhr(?));
|
||||
Vector#(LdQSize, Ehr#(2, Bool)) ld_computed <- replicateM(mkEhr(?));
|
||||
Vector#(LdQSize, Ehr#(3, Bool)) ld_inIssueQ <- replicateM(mkEhr(?));
|
||||
@@ -803,14 +805,14 @@ module mkSplitLSQ(SplitLSQ);
|
||||
Vector#(StQSize, Reg#(InstTag)) st_instTag <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(StQMemFunc)) st_memFunc <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(AmoFunc)) st_amoFunc <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(ByteEn)) st_byteEn <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(MemDataByteEn)) st_byteEn <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(Bool)) st_acq <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(Bool)) st_rel <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(Maybe#(PhyDst))) st_dst <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Ehr#(2, Addr)) st_paddr <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(2, Bool)) st_isMMIO <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(2, ByteEn)) st_shiftedBE <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(1, Data)) st_stData <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(2, MemDataByteEn)) st_shiftedBE <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(1, MemTaggedData)) st_stData <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(2, Maybe#(Exception))) st_fault <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(2, Bool)) st_computed <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(2, Bool)) st_verified <- replicateM(mkEhr(?));
|
||||
@@ -1373,7 +1375,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
endinterface);
|
||||
end
|
||||
|
||||
method ByteEn getOrigBE(LdStQTag t);
|
||||
method MemDataByteEn getOrigBE(LdStQTag t);
|
||||
return (case(t) matches
|
||||
tagged Ld .tag: (ld_byteEn[tag]);
|
||||
tagged St .tag: (st_byteEn[tag]);
|
||||
@@ -1498,7 +1500,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
wrongSpec_enq_conflict.wset(?);
|
||||
endmethod
|
||||
|
||||
method Action updateData(StQTag t, Data d);
|
||||
method Action updateData(StQTag t, MemTaggedData d);
|
||||
`ifndef INORDER_CORE
|
||||
// in-order core allocates entry and write data in the same rule
|
||||
doAssert(st_valid_updData[t], "entry must be valid");
|
||||
@@ -1509,7 +1511,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
|
||||
method ActionValue#(LSQUpdateAddrResult) updateAddr(
|
||||
LdStQTag lsqTag, Maybe#(Exception) fault,
|
||||
Addr pa, Bool mmio, ByteEn shift_be
|
||||
Addr pa, Bool mmio, MemDataByteEn shift_be
|
||||
);
|
||||
// index vec for vector functions
|
||||
Vector#(LdQSize, LdQTag) idxVec = genWith(fromInteger);
|
||||
@@ -1685,7 +1687,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
|
||||
method ActionValue#(LSQIssueLdResult) issueLd(LdQTag tag,
|
||||
Addr pa,
|
||||
ByteEn shift_be,
|
||||
MemDataByteEn shift_be,
|
||||
SBSearchRes sbRes);
|
||||
if(verbose) begin
|
||||
$display("[LSQ - issueLd] ", fshow(tag), "; ", fshow(pa),
|
||||
@@ -1974,7 +1976,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
return issueLdQ.first.data;
|
||||
endmethod
|
||||
|
||||
method ActionValue#(LSQRespLdResult) respLd(LdQTag t, Data alignedData);
|
||||
method ActionValue#(LSQRespLdResult) respLd(LdQTag t, MemTaggedData alignedData);
|
||||
let res = LSQRespLdResult {
|
||||
wrongPath: False,
|
||||
dst: Invalid,
|
||||
@@ -2009,8 +2011,9 @@ module mkSplitLSQ(SplitLSQ);
|
||||
let is32BitLd = (bEn[3] && !bEn[7]);
|
||||
res.dst = ld_dst[t];
|
||||
if (dst.Valid.isFpuReg && is32BitLd)
|
||||
res.data = fv_nanbox (gatherLoad(ld_paddr_resp[t], ld_byteEn[t],
|
||||
ld_unsigned[t], alignedData));
|
||||
res.data = fv_nanbox_MemTaggedData(
|
||||
gatherLoad(ld_paddr_resp[t], ld_byteEn[t],
|
||||
ld_unsigned[t], alignedData));
|
||||
else
|
||||
res.data = gatherLoad(ld_paddr_resp[t], ld_byteEn[t],
|
||||
ld_unsigned[t], alignedData);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -8,10 +8,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
|
||||
@@ -32,50 +32,49 @@ import Ehr::*;
|
||||
import CacheUtils::*;
|
||||
|
||||
// store buffer data block byte size == cache line
|
||||
typedef CLineNumBytes SBBlockNumBytes;
|
||||
typedef TMul#(8, SBBlockNumBytes) SBBlockSz;
|
||||
typedef TMul#(8, CLineDataNumBytes) SBBlockSz;
|
||||
typedef Bit#(SBBlockSz) SBBlock;
|
||||
typedef Vector#(SBBlockNumBytes, Bool) SBByteEn;
|
||||
typedef Vector#(CLineDataNumBytes, Bool) SBByteEn;
|
||||
|
||||
// aligned addr
|
||||
typedef TSub#(AddrSz, TLog#(SBBlockNumBytes)) SBBlockAddrSz;
|
||||
typedef TSub#(AddrSz, LogCLineDataNumBytes) SBBlockAddrSz;
|
||||
typedef Bit#(SBBlockAddrSz) SBBlockAddr;
|
||||
function SBBlockAddr getSBBlockAddr(Addr a);
|
||||
return truncateLSB(a);
|
||||
endfunction
|
||||
|
||||
// SB block vs. normal data
|
||||
typedef TDiv#(SBBlockSz, DataSz) SBBlockNumData;
|
||||
typedef Bit#(TLog#(SBBlockNumData)) SBBlockDataSel;
|
||||
function SBBlockDataSel getSBBlockDataSel(Addr a);
|
||||
return truncate(a >> valueOf(TLog#(NumBytes)));
|
||||
typedef TDiv#(SBBlockSz, MemDataSz) SBBlockNumMemData;
|
||||
typedef Bit#(TLog#(SBBlockNumMemData)) SBBlockMemDataSel;
|
||||
function SBBlockMemDataSel getSBBlockMemDataSel(Addr a);
|
||||
return truncate(a >> valueOf(TLog#(MemDataBytes)));
|
||||
endfunction
|
||||
|
||||
// store buffer entry
|
||||
typedef struct {
|
||||
SBBlockAddr addr;
|
||||
SBByteEn byteEn;
|
||||
SBBlock data;
|
||||
CLine line;
|
||||
} SBEntry deriving(Bits, Eq, FShow);
|
||||
|
||||
// result of searching (e.g. load byass)
|
||||
typedef struct {
|
||||
Maybe#(SBIndex) matchIdx;
|
||||
Maybe#(Data) forwardData; // XXX data is not shifted to match load addr offset
|
||||
Maybe#(MemTaggedData) forwardData; // XXX data is not shifted to match load addr offset
|
||||
} SBSearchRes deriving(Bits, Eq, FShow);
|
||||
|
||||
interface StoreBuffer;
|
||||
method Bool isEmpty;
|
||||
method Maybe#(SBIndex) getEnqIndex(Addr paddr);
|
||||
method Action enq(SBIndex idx, Addr paddr, ByteEn be, Data data);
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data);
|
||||
method ActionValue#(SBEntry) deq(SBIndex idx);
|
||||
method ActionValue#(Tuple2#(SBIndex, SBEntry)) issue;
|
||||
method SBSearchRes search(Addr paddr, ByteEn be); // load bypass/stall or atomic inst stall
|
||||
method SBSearchRes search(Addr paddr, MemDataByteEn be); // load bypass/stall or atomic inst stall
|
||||
// check no matching entry for AMO/Lr/Sc issue
|
||||
// XXX assume BE has been shifted approriately for paddr offset
|
||||
// (for load we need to do that before calling the methods)
|
||||
method Bool noMatchLdQ(Addr paddr, ByteEn be);
|
||||
method Bool noMatchStQ(Addr paddr, ByteEn be);
|
||||
method Bool noMatchLdQ(Addr paddr, MemDataByteEn be);
|
||||
method Bool noMatchStQ(Addr paddr, MemDataByteEn be);
|
||||
endinterface
|
||||
|
||||
/////////////////
|
||||
@@ -100,7 +99,7 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
// entries with valid bit
|
||||
Vector#(SBSize, Ehr#(2, SBEntry)) entry <- replicateM(mkEhr(?));
|
||||
Vector#(SBSize, Ehr#(2, Bool)) valid <- replicateM(mkEhr(False));
|
||||
|
||||
|
||||
// FIFO of entries to be issued to memory
|
||||
FIFOF#(SBIndex) issueQ <- mkUGSizedFIFOF(valueOf(SBSize));
|
||||
// FIFO of empty entries
|
||||
@@ -129,19 +128,19 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
function Bool noMatch(Addr paddr, ByteEn be);
|
||||
function Bool noMatch(Addr paddr, MemDataByteEn be);
|
||||
// input BE has been shifted, just pack it
|
||||
Bit#(NumBytes) ldBE = pack(be);
|
||||
Bit#(MemDataBytes) ldBE = pack(be);
|
||||
|
||||
// data offset within block
|
||||
SBBlockDataSel sel = getSBBlockDataSel(paddr);
|
||||
SBBlockMemDataSel sel = getSBBlockMemDataSel(paddr);
|
||||
|
||||
// helper to extract byteEn from entry
|
||||
function Bit#(NumBytes) getEntryBE(SBIndex idx);
|
||||
Vector#(SBBlockNumData, ByteEn) byteEn = unpack(pack(entry[idx][searchPort].byteEn));
|
||||
function Bit#(MemDataBytes) getEntryBE(SBIndex idx);
|
||||
Vector#(SBBlockNumMemData, MemDataByteEn) byteEn = unpack(pack(entry[idx][searchPort].byteEn));
|
||||
return pack(byteEn[sel]);
|
||||
endfunction
|
||||
|
||||
|
||||
// func to determine whether the load matches a store entry
|
||||
function Bool matchEntry(Integer i);
|
||||
// entry must be valid, addr should match, byte enable should overlap
|
||||
@@ -179,28 +178,27 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
end
|
||||
endmethod
|
||||
|
||||
method Action enq(SBIndex idx, Addr paddr, ByteEn be, Data d) if(inited);
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData d) if(inited);
|
||||
// get data offset
|
||||
SBBlockDataSel sel = getSBBlockDataSel(paddr);
|
||||
SBBlockMemDataSel sel = getSBBlockMemDataSel(paddr);
|
||||
// check whether the entry already exists
|
||||
if(valid[idx][enqPort]) begin
|
||||
// existing entry: merge
|
||||
doAssert(getSBBlockAddr(paddr) == entry[idx][enqPort].addr, "SB enq to existing entry addr should match");
|
||||
// update data
|
||||
Vector#(SBBlockNumData, Data) block = unpack(entry[idx][enqPort].data);
|
||||
Vector#(NumBytes, Bit#(8)) origData = unpack(block[sel]);
|
||||
Vector#(NumBytes, Bit#(8)) wrData = unpack(d);
|
||||
function Bit#(8) getNewByte(Integer i) = be[i] ? wrData[i] : origData[i];
|
||||
Vector#(NumBytes, Bit#(8)) newData = map(getNewByte, genVector);
|
||||
block[sel] = pack(newData);
|
||||
CLine block = entry[idx][enqPort].line;
|
||||
block.data[sel] = mergeDataBE(block.data[sel], d.data, be);
|
||||
// update tag
|
||||
if (pack(be) == ~0) block.tag[sel] = d.tag;
|
||||
else if (pack(be) != 0) block.tag[sel] = False;
|
||||
// update byte enable
|
||||
Vector#(SBBlockNumData, ByteEn) byteEn = unpack(pack(entry[idx][enqPort].byteEn));
|
||||
Vector#(SBBlockNumMemData, MemDataByteEn) byteEn = unpack(pack(entry[idx][enqPort].byteEn));
|
||||
byteEn[sel] = unpack(pack(byteEn[sel]) | pack(be));
|
||||
// update entry
|
||||
entry[idx][enqPort] <= SBEntry {
|
||||
addr: getSBBlockAddr(paddr),
|
||||
byteEn: unpack(pack(byteEn)),
|
||||
data: pack(block)
|
||||
line: block
|
||||
};
|
||||
// this entry must have been sent to issueQ
|
||||
end
|
||||
@@ -208,14 +206,16 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
// new entry: set valid
|
||||
valid[idx][enqPort] <= True;
|
||||
// setup entry
|
||||
Vector#(SBBlockNumData, Data) block = ?;
|
||||
block[sel] = d;
|
||||
Vector#(SBBlockNumData, ByteEn) byteEn = replicate(replicate(False));
|
||||
CLine block = ?;
|
||||
block.data[sel] = d.data;
|
||||
if (pack(be) == ~0) block.tag[sel] = d.tag;
|
||||
else if (pack(be) != 0) block.tag[sel] = False;
|
||||
Vector#(SBBlockNumMemData, MemDataByteEn) byteEn = replicate(replicate(False));
|
||||
byteEn[sel] = be;
|
||||
entry[idx][enqPort] <= SBEntry {
|
||||
addr: getSBBlockAddr(paddr),
|
||||
byteEn: unpack(pack(byteEn)),
|
||||
data: pack(block)
|
||||
line: block
|
||||
};
|
||||
// send this entry to issueQ
|
||||
doAssert(issueQ.notFull, "SB issueQ should not be full");
|
||||
@@ -239,19 +239,19 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
return tuple2(idx, entry[idx][issuePort]);
|
||||
endmethod
|
||||
|
||||
method SBSearchRes search(Addr paddr, ByteEn be);
|
||||
method SBSearchRes search(Addr paddr, MemDataByteEn be);
|
||||
// input BE has been shifted, just pack it
|
||||
Bit#(NumBytes) ldBE = pack(be);
|
||||
Bit#(MemDataBytes) ldBE = pack(be);
|
||||
|
||||
// data offset within block
|
||||
SBBlockDataSel sel = getSBBlockDataSel(paddr);
|
||||
SBBlockMemDataSel sel = getSBBlockMemDataSel(paddr);
|
||||
|
||||
// helper to extract byteEn from entry
|
||||
function Bit#(NumBytes) getEntryBE(SBIndex idx);
|
||||
Vector#(SBBlockNumData, ByteEn) byteEn = unpack(pack(entry[idx][searchPort].byteEn));
|
||||
function Bit#(MemDataBytes) getEntryBE(SBIndex idx);
|
||||
Vector#(SBBlockNumMemData, MemDataByteEn) byteEn = unpack(pack(entry[idx][searchPort].byteEn));
|
||||
return pack(byteEn[sel]);
|
||||
endfunction
|
||||
|
||||
|
||||
// func to determine whether the load matches a store entry
|
||||
function Bool matchEntry(Integer i);
|
||||
// entry must be valid, addr should match, byte enable should overlap
|
||||
@@ -266,10 +266,11 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
// check whether bytes reading are all covered by the entry
|
||||
if((getEntryBE(idx) & ldBE) == ldBE) begin
|
||||
// fully covered, forward data
|
||||
Vector#(SBBlockNumData, Data) block = unpack(entry[idx][searchPort].data);
|
||||
CLine block = entry[idx][searchPort].line;
|
||||
return SBSearchRes {
|
||||
matchIdx: Valid (idx),
|
||||
forwardData: Valid (block[sel])
|
||||
forwardData: Valid (MemTaggedData { tag: block.tag[sel]
|
||||
, data: block.data[sel]})
|
||||
};
|
||||
end
|
||||
else begin
|
||||
@@ -297,7 +298,7 @@ endmodule
|
||||
module mkDummyStoreBuffer(StoreBuffer);
|
||||
method Bool isEmpty = True;
|
||||
method Maybe#(SBIndex) getEnqIndex(Addr paddr) = Invalid;
|
||||
method Action enq(SBIndex idx, Addr paddr, ByteEn be, Data data);
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data);
|
||||
doAssert(False, "enq should never be called)");
|
||||
endmethod
|
||||
method ActionValue#(SBEntry) deq(SBIndex idx);
|
||||
@@ -308,9 +309,9 @@ module mkDummyStoreBuffer(StoreBuffer);
|
||||
doAssert(False, "issue should never be called)");
|
||||
return ?;
|
||||
endmethod
|
||||
method SBSearchRes search(Addr paddr, ByteEn be);
|
||||
method SBSearchRes search(Addr paddr, MemDataByteEn be);
|
||||
return SBSearchRes {matchIdx: Invalid, forwardData: Invalid};
|
||||
endmethod
|
||||
method Bool noMatchLdQ(Addr paddr, ByteEn be) = True;
|
||||
method Bool noMatchStQ(Addr paddr, ByteEn be) = True;
|
||||
method Bool noMatchLdQ(Addr paddr, MemDataByteEn be) = True;
|
||||
method Bool noMatchStQ(Addr paddr, MemDataByteEn be) = True;
|
||||
endmodule
|
||||
|
||||
@@ -37,6 +37,56 @@ typedef Bit#(AddrSz) Addr;
|
||||
|
||||
typedef 64 DataSz;
|
||||
typedef Bit#(DataSz) Data;
|
||||
typedef TDiv#(DataSz, 8) DataBytes;
|
||||
typedef Vector#(DataBytes, Bool) ByteEn;
|
||||
typedef struct {
|
||||
tag_t tag;
|
||||
data_t data;
|
||||
} TaggedData#(type tag_t, type data_t) deriving (Bits, FShow, Eq);
|
||||
typedef Vector#(2, Data) MemData;
|
||||
typedef Bool MemTag;
|
||||
typedef SizeOf#(MemData) MemDataSz;
|
||||
typedef TDiv#(MemDataSz, 8) MemDataBytes;
|
||||
typedef SizeOf#(MemTag) MemTagSz;
|
||||
typedef SizeOf#(MemTaggedData) MemTaggedDataSz;
|
||||
typedef TaggedData#(MemTag, MemData) MemTaggedData;
|
||||
instance Literal#(MemTaggedData);
|
||||
function fromInteger(i);
|
||||
Bit#(MemDataSz) val = fromInteger(i);
|
||||
return MemTaggedData { tag: False, data: unpack(val) };
|
||||
endfunction
|
||||
function inLiteralRange(x, i) = i < 2**valueOf(MemDataSz);
|
||||
endinstance
|
||||
function data_res mergeDataBE(data_t0 oldData, data_t1 newData, be_t be)
|
||||
provisos( Bits#(data_t0, data_sz), Bits#(data_t1, data_sz), Bits#(be_t, be_sz)
|
||||
, Bits#(data_res, data_sz)
|
||||
, Mul#(be_sz, 8, data_sz));
|
||||
Vector#(be_sz, Bit#(8)) oldVec = unpack(pack(oldData));
|
||||
Vector#(be_sz, Bit#(8)) newVec = unpack(pack(newData));
|
||||
Vector#(be_sz, Bool) beVec = unpack(pack(be));
|
||||
function Bit#(8) getNewByte(Integer i) = beVec[i] ? newVec[i] : oldVec[i];
|
||||
Vector#(be_sz, Bit#(8)) finalVec = map(getNewByte, genVector);
|
||||
return unpack(pack(finalVec));
|
||||
endfunction
|
||||
function MemTaggedData mergeMemTaggedDataBE( MemTaggedData oldItem
|
||||
, MemTaggedData newItem
|
||||
, be_t be)
|
||||
provisos (Bits#(be_t, MemDataBytes)) =
|
||||
MemTaggedData { tag : (pack(be) == ~0) ? newItem.tag : False
|
||||
, data: mergeDataBE(oldItem.data, newItem.data, be)};
|
||||
function MemData dataToMemData(Data x) = unpack(zeroExtend(x));
|
||||
function MemDataByteEn dataBEToMemDataBE(ByteEn x) = unpack(zeroExtend(pack(x)));
|
||||
function Data memDataToData(MemData x) = x[0];
|
||||
function ByteEn memDataBEToDataBE(MemDataByteEn x) = unpack(truncate(pack(x)));
|
||||
function MemTaggedData toMemTaggedData(t x)
|
||||
provisos (Bits#(t, sz), Add#(sz, smthg, MemDataSz)) = MemTaggedData {
|
||||
tag: False,
|
||||
data: unpack(zeroExtend(pack(x)))
|
||||
};
|
||||
function MemTaggedData dataToMemTaggedData(Data x) = toMemTaggedData(x);
|
||||
function t fromMemTaggedData(MemTaggedData x)
|
||||
provisos (Bits#(t, sz), Add#(sz, smthg, MemDataSz)) =
|
||||
unpack(truncate(pack(x.data)));
|
||||
|
||||
typedef 32 InstSz;
|
||||
typedef Bit#(InstSz) Instruction;
|
||||
@@ -48,30 +98,34 @@ typedef Bit #(Inst16_Sz) Instruction16;
|
||||
typedef 0 AsidSz; // not really implement ASID
|
||||
typedef Bit#(AsidSz) Asid;
|
||||
|
||||
typedef TDiv#(DataSz, 8) NumBytes;
|
||||
typedef TLog#(NumBytes) IndxShamt;
|
||||
typedef Vector#(NumBytes, Bool) ByteEn;
|
||||
typedef TLog#(MemDataBytes) IndxShamt;
|
||||
typedef Vector#(MemDataBytes, Bool) MemDataByteEn;
|
||||
|
||||
typedef TDiv#(DataSz, InstSz) DataSzInst;
|
||||
typedef TLog#(DataSzInst) LgDataSzInst;
|
||||
typedef Bit#(LgDataSzInst) DataInstOffset;
|
||||
typedef TDiv#(MemDataSz, InstSz) MemDataSzInst;
|
||||
typedef TLog#(MemDataSzInst) LgMemDataSzInst;
|
||||
typedef Bit#(LgMemDataSzInst) MemDataInstOffset;
|
||||
|
||||
// These types show up in many places so they are defined here
|
||||
typedef enum {Swap, Add, Xor, And, Or, Min, Max, Minu, Maxu, None} AmoFunc deriving(Bits, Eq, FShow, Bounded);
|
||||
typedef enum {QWord, DWord, Word} AmoWidth deriving(Bits, Eq, FShow, Bounded);
|
||||
typedef enum { Ld, St, Lr, Sc, Amo, Fence } MemFunc deriving(Bits, Eq, FShow);
|
||||
typedef struct {
|
||||
AmoFunc func;
|
||||
Bool doubleWord;
|
||||
Bool aq;
|
||||
Bool rl;
|
||||
AmoFunc func;
|
||||
AmoWidth width;
|
||||
Bool aq;
|
||||
Bool rl;
|
||||
} AmoInst deriving(Bits, Eq, FShow);
|
||||
typedef struct {
|
||||
MemFunc mem_func; // Ld, St, Lr, Sc, Amo
|
||||
AmoFunc amo_func;
|
||||
Bool unsignedLd;
|
||||
ByteEn byteEn; // takes place of double word
|
||||
Bool aq;
|
||||
Bool rl;
|
||||
MemFunc mem_func; // Ld, St, Lr, Sc, Amo
|
||||
AmoFunc amo_func;
|
||||
Bool unsignedLd;
|
||||
MemDataByteEn byteEn; // takes place of double word
|
||||
Bool aq;
|
||||
Bool rl;
|
||||
Bool reg_bounds;
|
||||
} MemInst deriving(Bits, Eq, FShow);
|
||||
|
||||
`ifdef BSIM
|
||||
@@ -81,7 +135,7 @@ function Action doAssert(Bool b, String s) = dynamicAssert(b, s);
|
||||
`endif
|
||||
|
||||
`ifdef RVFI_DII
|
||||
typedef Vector#(`sizeSup, Maybe#(RVFI_DII_Execution #(DataSz,DataSz))) Rvfi_Traces;
|
||||
typedef Vector#(`sizeSup, Maybe#(RVFI_DII_Execution #(64, 64))) Rvfi_Traces;
|
||||
typedef Vector#(`sizeSup, Maybe#(Dii_Id)) Dii_Ids;
|
||||
typedef Vector#(`sizeSup, Maybe#(Bit#(32))) Dii_Insts;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user