Skip to content
Merged
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
3 changes: 2 additions & 1 deletion docs/isa.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ destination write path preflights every selected PE before applying one atomic
descriptor-and-payload update. The first write fixes the allocation mask and
per-PE capacity; later subset writes are legal, while allocation expansion or
descriptor drift fails without partial effects. A zero PE mask is a strict
no-op, and uninitialized reads return no value without changing state.
no-op, and uninitialized reads return no value without changing state. PE-mask
bits are architectural-order: bit 3 selects PE0 through bit 0 selecting PE3.

The machine-readable differential contract is committed at
`tests/fixtures/pto_v058_shared_state.json`. It fixes the TLSU state
Expand Down
12 changes: 8 additions & 4 deletions src/emulator/shared_tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ namespace {

constexpr std::uint8_t kValidPeMask = (1U << kLinxCorePeCount) - 1U;

constexpr std::uint8_t PeMaskBit(std::size_t pe) noexcept {
return static_cast<std::uint8_t>(1U << (kLinxCorePeCount - 1U - pe));
}

bool DescriptorValid(const SharedTileDescriptor &descriptor, std::uint32_t capacity) noexcept {
if (descriptor.rows == 0 || descriptor.cols == 0 || descriptor.valid_rows > descriptor.rows ||
descriptor.valid_cols > descriptor.cols) {
Expand Down Expand Up @@ -60,7 +64,7 @@ SharedTileBank::Write(std::uint16_t shared_id, std::uint8_t pe_mask, std::uint8_
}

for (std::size_t pe = 0; pe < kLinxCorePeCount; ++pe) {
const auto bit = static_cast<std::uint8_t>(1U << pe);
const auto bit = PeMaskBit(pe);
if ((pe_mask & bit) == 0U) {
continue;
}
Expand All @@ -84,15 +88,15 @@ SharedTileBank::Write(std::uint16_t shared_id, std::uint8_t pe_mask, std::uint8_
version.per_pe_capacity = *capacity;
version.allocated_bytes = *capacity * static_cast<std::uint32_t>(std::popcount(pe_mask));
for (std::size_t pe = 0; pe < kLinxCorePeCount; ++pe) {
if ((pe_mask & static_cast<std::uint8_t>(1U << pe)) != 0U) {
if ((pe_mask & PeMaskBit(pe)) != 0U) {
version.dtype = descriptors[pe].dtype;
break;
}
}
}

for (std::size_t pe = 0; pe < kLinxCorePeCount; ++pe) {
const auto bit = static_cast<std::uint8_t>(1U << pe);
const auto bit = PeMaskBit(pe);
if ((pe_mask & bit) == 0U) {
continue;
}
Expand All @@ -109,7 +113,7 @@ const SharedTileLane *SharedTileBank::Read(std::uint16_t shared_id,
return nullptr;
}
const auto &version = versions_[shared_id];
if ((version.initialized_mask & static_cast<std::uint8_t>(1U << pe_id)) == 0U) {
if ((version.initialized_mask & PeMaskBit(pe_id)) == 0U) {
return nullptr;
}
return &version.lanes[pe_id];
Expand Down
4 changes: 4 additions & 0 deletions tests/checks/check_pto_v058_shared_fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ def main() -> int:
_require(fixture.get("schema") == "linx-pto-v058-shared-state-v1", "unexpected schema")
_require(fixture.get("pto_isa_release") == "0.58.0", "fixture must target PTO ISA 0.58.0")
_require(fixture.get("pe_count") == 4, "fixture must use the architectural four-PE Core")
_require(
fixture.get("pe_mask_bits") == {"3": "PE0", "2": "PE1", "1": "PE2", "0": "PE3"},
"PE mask must map bit3=PE0 through bit0=PE3",
)
_require(fixture.get("shared_tile_ids") == [0, 255], "fixture must cover S0..S255")
_require(fixture.get("tsize_bytes_per_pe") == EXPECTED_SIZE_BYTES, "TSize table drifted")

Expand Down
13 changes: 7 additions & 6 deletions tests/fixtures/pto_v058_shared_state.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"pto_isa_release": "0.58.0",
"pto_spec_commit": "8a77c9f0eab36cc41051519366ff163171f81463",
"pe_count": 4,
"pe_mask_bits": {"3": "PE0", "2": "PE1", "1": "PE2", "0": "PE3"},
"shared_tile_ids": [0, 255],
"tsize_bytes_per_pe": {
"1": 128,
Expand All @@ -27,8 +28,8 @@
"shared_tid": 0,
"pe_mask": "0b0101",
"tsize_code": 2,
"descriptors": {"0": {"rows": 8, "cols": 8}, "2": {"rows": 4, "cols": 16}},
"payload_bytes": {"0": 256, "2": 256}
"descriptors": {"1": {"rows": 8, "cols": 8}, "3": {"rows": 4, "cols": 16}},
"payload_bytes": {"1": 256, "3": 256}
},
"expected": {
"status": "applied",
Expand All @@ -41,7 +42,7 @@
"id": "tlsu-subset-update",
"operation": "TLSU",
"precondition": {"allocation_mask": "0b0101", "initialized_mask": "0b0101"},
"input": {"shared_tid": 0, "pe_mask": "0b0001", "tsize_code": 2, "payload_bytes": {"0": 256}},
"input": {"shared_tid": 0, "pe_mask": "0b0001", "tsize_code": 2, "payload_bytes": {"3": 256}},
"expected": {"status": "applied", "allocation_mask": "0b0101", "initialized_mask": "0b0101"}
},
{
Expand All @@ -55,20 +56,20 @@
"id": "tlsu-descriptor-mismatch-atomic",
"operation": "TLSU",
"precondition": {"allocation_mask": "0b0101", "initialized_mask": "0b0101"},
"input": {"shared_tid": 0, "pe_mask": "0b0101", "tsize_code": 2, "descriptors": {"0": {"rows": 8, "cols": 8}, "2": {"rows": 8, "cols": 8}}},
"input": {"shared_tid": 0, "pe_mask": "0b0101", "tsize_code": 2, "descriptors": {"1": {"rows": 8, "cols": 8}, "3": {"rows": 8, "cols": 8}}},
"expected": {"status": "rejected", "reason": "descriptor-mismatch", "state_unchanged": true}
},
{
"id": "tlsu-payload-mismatch-atomic",
"operation": "TLSU",
"precondition": {"allocation_mask": "0b0101", "initialized_mask": "0b0101"},
"input": {"shared_tid": 0, "pe_mask": "0b0101", "tsize_code": 2, "payload_bytes": {"0": 256, "2": 128}},
"input": {"shared_tid": 0, "pe_mask": "0b0101", "tsize_code": 2, "payload_bytes": {"1": 256, "3": 128}},
"expected": {"status": "rejected", "reason": "payload-size-mismatch", "state_unchanged": true}
},
{
"id": "tlsu-undefined-read",
"operation": "TLSU",
"input": {"shared_tid": 255, "pe_mask": "0b0001", "access": "read"},
"input": {"shared_tid": 255, "pe_id": 3, "access": "read"},
"expected": {"status": "uninitialized", "state_unchanged": true}
},
{
Expand Down
34 changes: 17 additions & 17 deletions tests/unit/emulator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ int TestStateReset() {
return 0;
}

int TestV058SharedTileState() {
int TestSharedTileState() {
SharedTileBank bank;
const SharedTileDescriptor descriptor{
.dtype = 3,
Expand Down Expand Up @@ -100,40 +100,40 @@ int TestV058SharedTileState() {
bank.Version(7).allocation_mask != 0 || bank.Version(7).initialized_mask != 0) {
return 31;
}
if (bank.Write(7, 0x3, 1, descriptors, payloads) != SharedTileWriteStatus::Applied ||
bank.Version(7).allocation_mask != 0x3 || bank.Version(7).initialized_mask != 0x3 ||
if (bank.Write(7, 0xc, 1, descriptors, payloads) != SharedTileWriteStatus::Applied ||
bank.Version(7).allocation_mask != 0xc || bank.Version(7).initialized_mask != 0xc ||
bank.Version(7).allocated_bytes != 256 || bank.Read(7, 1)->descriptor.valid_rows != 2) {
return 32;
}
if (bank.Read(7, 2) != nullptr || bank.Version(7).initialized_mask != 0x3) {
if (bank.Read(7, 2) != nullptr || bank.Version(7).initialized_mask != 0xc) {
return 33;
}

const auto lane1_before = bank.Read(7, 1)->data;
payloads[0].assign(128, 0x44);
if (bank.Write(7, 0x1, 1, descriptor, payloads) != SharedTileWriteStatus::Applied ||
if (bank.Write(7, 0x8, 1, descriptor, payloads) != SharedTileWriteStatus::Applied ||
bank.Read(7, 0)->data.front() != 0x44 || bank.Read(7, 1)->data != lane1_before ||
bank.Version(7).allocation_mask != 0x3) {
bank.Version(7).allocation_mask != 0xc) {
return 34;
}

const auto lane0_before = bank.Read(7, 0)->data;
payloads[0].assign(128, 0x66);
payloads[1].assign(1, 0x77);
if (bank.Write(7, 0x3, 1, descriptors, payloads) != SharedTileWriteStatus::PayloadSizeMismatch ||
if (bank.Write(7, 0xc, 1, descriptors, payloads) != SharedTileWriteStatus::PayloadSizeMismatch ||
bank.Read(7, 0)->data != lane0_before || bank.Read(7, 1)->data != lane1_before) {
return 35;
}

payloads[1].assign(128, 0x22);
payloads[2].assign(128, 0x55);
if (bank.Write(7, 0x4, 1, descriptor, payloads) != SharedTileWriteStatus::AllocationExpansion ||
bank.Version(7).allocation_mask != 0x3 || bank.Read(7, 2) != nullptr) {
if (bank.Write(7, 0x2, 1, descriptor, payloads) != SharedTileWriteStatus::AllocationExpansion ||
bank.Version(7).allocation_mask != 0xc || bank.Read(7, 2) != nullptr) {
return 36;
}
auto mismatched = descriptor;
mismatched.dtype = 9;
if (bank.Write(7, 0x1, 1, mismatched, payloads) != SharedTileWriteStatus::DescriptorMismatch ||
if (bank.Write(7, 0x8, 1, mismatched, payloads) != SharedTileWriteStatus::DescriptorMismatch ||
bank.Read(7, 0)->descriptor.dtype != 3 || bank.Read(7, 0)->data.front() != 0x44) {
return 37;
}
Expand All @@ -145,7 +145,7 @@ int TestV058SharedTileState() {
return 0;
}

int TestV058BindingPolicy() {
int TestSharedTileBindingPolicy() {
if (!linx::model::emulator::BindingAllows(TileBindingKind::Bior,
TileOperandSpace::ScalarAddress) ||
linx::model::emulator::BindingAllows(TileBindingKind::Bior, TileOperandSpace::Local) ||
Expand Down Expand Up @@ -173,7 +173,7 @@ int TestV058BindingPolicy() {
return 0;
}

int TestV058BiosDecode() {
int TestSharedTileBindingDecode() {
Minst inst;
if (DecodeMinstPacked(0x00001013ULL, 32, inst) != MinstCodecStatus::Ok ||
inst.mnemonic != "B.IOS" || inst.form_id != "11ff57a2e635") {
Expand Down Expand Up @@ -201,7 +201,7 @@ int TestV058BiosDecode() {
return 0;
}

int TestV058TileHeadersAndUnsupportedScalar() {
int TestTileHeadersAndUnsupportedScalar() {
{
const auto bytes = EncodedBytes(BuildZeroInst("3c9e83c5a42f")); // BSTART.TPREFETCH
if (bytes.empty()) {
Expand Down Expand Up @@ -429,13 +429,13 @@ int main() {
if (const int rc = TestStateReset(); rc != 0) {
return rc;
}
if (const int rc = TestV058SharedTileState(); rc != 0) {
if (const int rc = TestSharedTileState(); rc != 0) {
return rc;
}
if (const int rc = TestV058BindingPolicy(); rc != 0) {
if (const int rc = TestSharedTileBindingPolicy(); rc != 0) {
return rc;
}
if (const int rc = TestV058BiosDecode(); rc != 0) {
if (const int rc = TestSharedTileBindingDecode(); rc != 0) {
return rc;
}
if (const int rc = TestMinstRecordAdapter(); rc != 0) {
Expand All @@ -456,7 +456,7 @@ int main() {
if (const int rc = TestMinstRecordDumpFormatting(); rc != 0) {
return rc;
}
if (const int rc = TestV058TileHeadersAndUnsupportedScalar(); rc != 0) {
if (const int rc = TestTileHeadersAndUnsupportedScalar(); rc != 0) {
return rc;
}
return 0;
Expand Down
16 changes: 8 additions & 8 deletions tests/unit/minst_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ int RunCoverageRoundTripSmoke() {
return 0;
}

int RunV058DeltaDecodeSmoke() {
int RunActiveDeltaDecodeSmoke() {
struct ExpectedForm {
std::string_view uid;
std::string_view mnemonic;
Expand Down Expand Up @@ -313,7 +313,7 @@ int RunV058DeltaDecodeSmoke() {
return 0;
}

int RunV058TeplSelectorSmoke() {
int RunTeplSelectorSmoke() {
const auto *form = LookupFormByUid("f0754cf51a8d");
if (form == nullptr || form->mnemonic != "BSTART.TEPL") {
return 70;
Expand Down Expand Up @@ -500,14 +500,14 @@ int main() {
std::cerr << "RunAsmTemplateReplacementSmoke failed with code " << asm_replace << '\n';
return 6;
}
const auto v058_delta = RunV058DeltaDecodeSmoke();
if (v058_delta != 0) {
std::cerr << "RunV058DeltaDecodeSmoke failed with code " << v058_delta << '\n';
const auto active_delta = RunActiveDeltaDecodeSmoke();
if (active_delta != 0) {
std::cerr << "RunActiveDeltaDecodeSmoke failed with code " << active_delta << '\n';
return 7;
}
const auto v058_tepl = RunV058TeplSelectorSmoke();
if (v058_tepl != 0) {
std::cerr << "RunV058TeplSelectorSmoke failed with code " << v058_tepl << '\n';
const auto tepl_selector = RunTeplSelectorSmoke();
if (tepl_selector != 0) {
std::cerr << "RunTeplSelectorSmoke failed with code " << tepl_selector << '\n';
return 8;
}
return 0;
Expand Down
Loading