Loop Timing Witness
Native controller and runtime interfaces; hardware qualification pending
Loading...
Searching...
No Matches
spike_amp_transport.h
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Commercial license available
3// © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
4// © Code 2020–2026 Miroslav Šotek. All rights reserved.
5// ORCID: 0009-0009-3560-0851
6// Contact: www.anulum.li | protoscience@anulum.li
7// Loop Timing Witness — actual architectural RAM and production AXI transport for AMP logging
8
12
13#ifndef WITNESS_SPIKE_AMP_TRANSPORT_H
14#define WITNESS_SPIKE_AMP_TRANSPORT_H
15#include "sim.h"
16#include "../refusal.h"
17#include "../rtl/simulation.h"
18extern "C" {
20}
21#include <array>
22#include <cstddef>
23#include <stdexcept>
24
25namespace witness {
28 Simulation &fabric;
29 abstract_mem_t *ram = nullptr;
30 std::uint64_t ram_base = 0, shared;
31
33 std::uint64_t offset(std::uint64_t address) const {
34 if (address < shared || address - shared > sizeof(witness_amp_mailbox) - 4 || address % 4)
35 throw witness::ArgumentRefused("AMP memory access outside the reserved mailbox");
36 return address - ram_base;
37 }
38
39 public:
42 SpikeAmpTransport(const sim_t &simulator, Simulation &model, std::uint64_t mailbox_address)
43 : fabric(model), shared(mailbox_address) {
44 if (!shared || shared % 8 || shared > UINT64_MAX - sizeof(witness_amp_mailbox))
45 throw witness::ArgumentRefused("AMP shared memory address outside bounds");
46 for (const auto &entry : simulator.get_bus().get_devices()) {
47 auto *candidate = dynamic_cast<abstract_mem_t *>(entry.second);
48 if (!candidate || shared < entry.first)
49 continue;
50 const auto displacement = shared - entry.first;
51 if (displacement > candidate->size() ||
52 sizeof(witness_amp_mailbox) > candidate->size() - displacement)
53 continue;
54 ram = candidate;
55 ram_base = entry.first;
56 break;
57 }
58 if (!ram)
59 throw witness::ArgumentRefused("AMP mailbox does not fit actual simulator RAM");
60 }
61
63 std::uint32_t read_memory32(std::uint64_t address) {
64 std::array<std::uint8_t, 4> bytes{};
65 if (!ram->load(offset(address), bytes.size(), bytes.data()))
66 throw witness::RuntimeRefused("actual AMP RAM load refused");
67 std::uint32_t result = 0;
68 for (unsigned index = 0; index < 4; ++index)
69 result |= static_cast<std::uint32_t>(bytes[index]) << (index * 8);
70 return result;
71 }
72
74 void write_memory32(std::uint64_t address, std::uint32_t value) {
75 const auto displacement = address >= shared ? address - shared : UINT64_MAX;
76 if (displacement != offsetof(witness_amp_mailbox, consumer) &&
77 displacement != offsetof(witness_amp_mailbox, logger_status))
78 throw witness::ArgumentRefused("AMP logger cannot write firmware-owned memory");
79 std::array<std::uint8_t, 4> bytes{};
80 for (unsigned index = 0; index < 4; ++index)
81 bytes[index] = static_cast<std::uint8_t>(value >> (index * 8));
82 if (!ram->store(offset(address), bytes.size(), bytes.data()))
83 throw witness::RuntimeRefused("actual AMP RAM store refused");
84 }
85
87 Edge read(std::uint8_t address) { return fabric.read(address); }
89 Edge write(std::uint8_t address, std::uint32_t value, std::uint8_t strobes) {
90 return fabric.write(address, value, strobes);
91 }
92
93 std::uint64_t time() const { return fabric.time(); }
94};
95} // namespace witness
96#endif
std::uint32_t read_memory32(std::uint64_t address)
SpikeAmpTransport(const sim_t &simulator, Simulation &model, std::uint64_t mailbox_address)
void write_memory32(std::uint64_t address, std::uint32_t value)
Edge write(std::uint8_t address, std::uint32_t value, std::uint8_t strobes)
Edge read(std::uint8_t address)