Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions src/main/scala/Bundles.scala
Original file line number Diff line number Diff line change
Expand Up @@ -245,16 +245,23 @@ class UncacheMMStoreEvent extends DifftestBaseBundle with HasValid {
}

class StoreEvent extends DifftestBaseBundle with HasValid {
val addr = UInt(64.W)
val data = UInt(64.W)
val highData = UInt(64.W)
val mask = UInt(16.W)
val wLine = Bool()
val vecNeedSplit = Bool()
val eew = UInt(8.W)
val offset = UInt(16.W)
val pc = UInt(64.W)
val robidx = UInt(10.W)

val isNonCacheable = Bool()
val isVStore = Bool()
val isUStride = Bool()
val isMasked = Bool()
val isWhole = Bool()
val veew = UInt(8.W)
val nf = UInt(8.W)
val rawDataLow = UInt(64.W)
val rawDataHigh = UInt(64.W)
val rawMask = UInt(16.W)
val rawAddr = UInt(64.W)
val isHighPart = Bool()
}

class LoadEvent extends DifftestBaseBundle with HasValid {
Expand Down
94 changes: 85 additions & 9 deletions src/test/csrc/difftest/checkers/store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ void StoreRecorder::clear_valid(DifftestStoreEvent &probe) {
probe.valid = 0;
}

// Expand 8-bit mask to bit-and with 64-bit wide data
static uint64_t MaskExpand(uint8_t mask) {
uint64_t expander = 0x0101010101010101ULL;
uint64_t selector = 0x8040201008040201ULL;
return (((((mask * expander) & selector) * 0xFFULL) >> 7) & expander) * 0xFFULL;
}

int StoreRecorder::check(const DifftestStoreEvent &probe) {
if (!probe.valid)
return STATE_OK;
Expand All @@ -35,18 +42,87 @@ int StoreRecorder::check(const DifftestStoreEvent &probe) {
int WORDBYTES = 8;
int COMMITBYTES = 16;

auto addr = probe.addr;
auto lowData = probe.data;
auto highData = probe.highData;
auto mask = probe.mask;
uint64_t calcAddr;
uint64_t calcDataLow;
uint64_t calcDataHigh;
uint16_t calcMask;
uint8_t calcEEW;
bool calcIsVSLine;

auto isNonCacheable = probe.isNonCacheable;
auto isVStore = probe.isVStore;
auto isUStride = probe.isUStride;
auto isMasked = probe.isMasked;
auto isWhole = probe.isWhole;
auto veew = probe.veew;
auto nf = probe.nf;
auto rawDataLow = probe.rawDataLow;
auto rawDataHigh = probe.rawDataHigh;
auto rawMask = probe.rawMask;
auto rawAddr = probe.rawAddr;
auto wLine = probe.wLine;
auto isHighPart = probe.isHighPart;

if (!isNonCacheable) {
bool isVse = isVStore && isUStride;
bool isVsm = isVStore && isMasked;
bool isVsr = isVStore && isWhole;

uint8_t eew = veew;
uint32_t EEB = 1 << eew;
uint8_t nf2 = isVsr ? 0 : nf;

bool isSegment = nf2 != 0 && !isVsm;
bool isVSLine = (isVse || isVsm || isVsr) && !isSegment;
bool isWline = wLine;
calcIsVSLine = isVSLine;

if (isVSLine) {
calcAddr = rawAddr;
calcDataLow = rawDataLow;
calcDataHigh = rawDataHigh;
calcMask = rawMask;
} else if (isWline) {
calcAddr = rawAddr;
calcDataLow = rawDataLow;
calcDataHigh = rawDataHigh;
calcMask = rawMask;
Assert(rawDataLow == 0 && rawDataHigh == 0, "wLine only supports whole zero write now");
} else if (isHighPart) {
calcAddr = (rawAddr & (~0xFULL)) | 0b1000;
calcMask = (rawMask >> 8) & 0xFF;
uint64_t tmpData = rawDataHigh;
calcDataLow = tmpData & MaskExpand(calcMask);
calcDataHigh = 0;
} else {
calcAddr = rawAddr & (~0xFULL);
calcMask = rawMask & 0xFF;
uint64_t tmpData = rawDataLow;
calcDataLow = tmpData & MaskExpand(calcMask);
calcDataHigh = 0;
}
calcEEW = EEB;
} else {
calcAddr = rawAddr & (~7ULL);
calcMask = rawMask;
calcDataLow = rawDataLow & MaskExpand(calcMask);
calcDataHigh = 0;
calcEEW = 0;
calcIsVSLine = false;
}

auto addr = calcAddr;
auto lowData = calcDataLow;
auto highData = calcDataHigh;
auto mask = calcMask;
auto offset = probe.offset;
auto eew = probe.eew;
auto eew = calcEEW;
auto pc = probe.pc;
auto robIdx = probe.robidx;

uint64_t rawVecAddr = addr + offset;

if (probe.vecNeedSplit) {
if (calcIsVSLine) {
uint16_t flow = COMMITBYTES / eew;
uint64_t flowMask = (eew == 1) ? 0x1ULL : (eew == 2) ? 0x3ULL : (eew == 4) ? 0xfULL : (eew == 8) ? 0xffULL : 0x0ULL;
uint64_t flowMaskBit = (eew == 1) ? 0xffULL
Comment on lines +125 to 128
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the vector-store path to if (calcIsVSLine) makes this block run whenever calcIsVSLine is true. In the downstream handleMisalign handling inside this block, refStoreCommitData is computed via shifts of (64 - (rawOffset * 8)); when offset % 8 == 0 (so rawOffset == 0), that code shifts by 64 bits, which is undefined behavior in C++. Please guard rawOffset == 0 (result should be 0) or rewrite the extraction using a mask to avoid shift-by-64 UB.

Copilot uses AI. Check for mistakes.
Expand Down Expand Up @@ -103,7 +179,7 @@ int StoreRecorder::check(const DifftestStoreEvent &probe) {

nextOffset = 8 - rawOffset;
auto nextDataOffset = nextOffset * 8;
auto nextData = probe.highData << nextDataOffset;
auto nextData = calcDataHigh << nextDataOffset;

refStoreCommitData = (nextData + presentData) & flowMaskBit;
} else {
Expand Down Expand Up @@ -145,9 +221,9 @@ int StoreRecorder::check(const DifftestStoreEvent &probe) {
}
} else {
DiffState::StoreCommit storeCommit = {probe.valid,
probe.addr,
calcAddr,
lowData,
static_cast<uint8_t>(probe.mask & 0xFF),
static_cast<uint8_t>(calcMask & 0xFF),
pc,
robIdx
#ifdef CONFIG_DIFFTEST_SQUASH
Expand Down
Loading