Try new types to hold capabilities
This commit is contained in:
committed by
Alexandre Joannou
parent
0b68498940
commit
b70498e00a
@@ -239,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
|
||||
|
||||
|
||||
@@ -82,7 +82,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
|
||||
@@ -288,7 +288,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 +308,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 +349,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);
|
||||
@@ -457,6 +457,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,16 +466,19 @@ 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
|
||||
|
||||
@@ -570,7 +574,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
`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 +701,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 +722,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 +866,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 +881,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 +954,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 +966,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 +1018,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 +1114,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 +1162,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 +1207,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 +1219,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 +1313,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 +1325,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 +1357,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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -103,7 +103,7 @@ function Maybe#(MemInst) decodeMemInst(Instruction inst);
|
||||
// byteEn
|
||||
// TODO: Some combinations of operations and byteEn's are illegal.
|
||||
// They should be detected here.
|
||||
ByteEn byteEn = replicate(False);
|
||||
MemDataByteEn byteEn = replicate(False);
|
||||
case (funct3)
|
||||
memB, memBU : byteEn[0] = True;
|
||||
memH, memHU : begin
|
||||
@@ -116,7 +116,16 @@ function Maybe#(MemInst) decodeMemInst(Instruction inst);
|
||||
byteEn[2] = True;
|
||||
byteEn[3] = True;
|
||||
end
|
||||
memD : byteEn = replicate(True);
|
||||
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
|
||||
|
||||
|
||||
@@ -407,8 +407,11 @@ function Maybe#(Trap) checkForException(
|
||||
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
|
||||
@@ -422,21 +425,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 MemTaggedData { tag: False, data: unpack(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 MemTaggedData { tag: False, data: unpack(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 MemTaggedData { tag: False, data: unpack(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 MemTaggedData { tag: False, data: unpack(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;
|
||||
|
||||
|
||||
@@ -608,10 +608,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
|
||||
@@ -623,7 +623,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 {
|
||||
@@ -655,7 +655,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
|
||||
|
||||
@@ -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,55 @@ 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 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 +97,33 @@ 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;
|
||||
} MemInst deriving(Bits, Eq, FShow);
|
||||
|
||||
`ifdef BSIM
|
||||
@@ -81,7 +133,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