11 f_set_mux_disable{
bus::replace_function_idx(block_address, 5)},
12 f_reset_mux_disable{
bus::replace_function_idx(block_address, 6)},
13 f_reset_connections{
bus::replace_function_idx(block_address, 4)},
14 f_connections{
bus::replace_function_idx(block_address, 2), F_CONNECTION_SPI_SETTINGS},
15 f_connections_sync{
bus::replace_function_idx(block_address, 3)} {}
22 return mux_0.encode() | (mux_1.encode() << 2) | (mux_2.encode() << 4) | (mux_3.encode() << 6);
27 std::array<uint8_t, 24> data{};
28 for (
auto idx = 0u; idx < data.size(); idx++) {
31 muxes[idx * 4 + 1], muxes[idx * 4 + 0]);
41#ifdef ANABRID_PEDANTIC
42 std::array<uint8_t, 24> data{0};
44 return std::all_of(data.begin(), data.end(), [](
auto value) { return value == 0; });
50FLASHMEM TBlock::TBlock(TBlockHAL *hardware) : FunctionBlock(
"T", hardware), hardware(hardware) {
51 classifier.class_enum = CLASS_;
54FLASHMEM TBlock::TBlock() : TBlock(new DummyTBlockHAL()) {}
57TBlock *TBlock::from_entity_classifier(entities::EntityClassifier classifier, bus::addr_t block_address) {
58 if (!classifier or classifier.class_enum != CLASS_ or classifier.type != TYPE)
61 if (classifier.version < entities::Version(1, 0, 2))
64 if (classifier.version < entities::Version(1, 1))
69FLASHMEM utils::status TBlock::config_self_from_json(JsonObjectConst cfg) {
70 for (
auto cfgItr = cfg.begin(); cfgItr != cfg.end(); ++cfgItr) {
71 if (cfgItr->key() ==
"muxes") {
72 auto res = config_self_from_muxes(cfgItr->value());
76 return utils::status(
"CBlock: Unknown configuration key");
79 return utils::status::success();
82FLASHMEM utils::status TBlock::config_self_from_muxes(
const JsonVariantConst &muxes) {
83 if (!muxes.is<JsonArrayConst>())
84 return utils::status(
"TBlock: Muxes must be array");
86 for (
const JsonVariantConst &mux : muxes.as<JsonArrayConst>()) {
88 return utils::status(
"TBlock: Mux must be int");
89 int mux_value = mux.as<
int>();
90 if (mux_value < 0 || 4 <= mux_value)
91 return utils::status(
"TBlock: Mux must be interval [0, 3]");
92 f_data[idx] = Mux::from(mux_value);
96 return status::success();
99FLASHMEM
void TBlock::config_self_to_json(JsonObject &cfg) {
100 Entity::config_self_to_json(cfg);
101 auto muxes_cfg = cfg.createNestedArray(
"muxes");
102 for (
auto mux : f_data) {
103 muxes_cfg.add(mux.index());
107FLASHMEM
status TBlock::connect(uint8_t src_sector, uint8_t dst_sector, uint8_t sector_lane) {
108 assert(src_sector < 4 && dst_sector < 4);
109 auto dst_lane = dst_sector * 24 + sector_lane;
110 if (f_used.test(dst_lane)) {
112 return status(
"TBlock output lane already used");
115 f_used.set(dst_lane);
116 f_data[dst_lane] = Mux::from(src_sector);
117 return status::success();
120FLASHMEM
void TBlock::reset(entities::ResetAction action) {
121 Entity::reset(action);
122 if (action.has(entities::ResetAction::CIRCUIT_RESET))
124 if (action.has(entities::ResetAction::EVERYTHING))
128FLASHMEM
void TBlock::reset_connections() {
132 f_data = {Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D,
133 Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D,
134 Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D,
135 Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D,
136 Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D,
137 Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D,
138 Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D,
139 Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D, Mux::A, Mux::B, Mux::C, Mux::D};
142FLASHMEM
status TBlock::write_to_hardware() {
143 RETURN_IF_FAILED(Entity::write_to_hardware());
144 if (!hardware->write_muxes(f_data))
145 return status(
"Error writing mux settings to hardware.");
147 hardware->reset_mux_disable();
149 hardware->set_mux_disable();
150 return status::success();
153FLASHMEM
bool TBlock::is_enabled()
const {
return enabled; }
155FLASHMEM
void TBlock::set_enabled(
bool enabled_) { enabled = enabled_; }
157FLASHMEM
status Router::route_cluster(SignalId output, SignalId input) {
158 auto output_carrier = output.cluster.carrier;
159 auto input_carrier = input.cluster.carrier;
160 assert(output_carrier == input_carrier);
163 return status(output == input);
166 auto output_sector_lane = output.id % 24;
167 auto input_sector_lane = input.id % 24;
169 if (output_sector_lane != input_sector_lane)
170 return status(
"Connections inside carrier only allowed between same lane indices!");
172 auto tblock = find_carrier_t_block(input_carrier);
173 return tblock->connect(output.cluster.id, input.cluster.id, input_sector_lane);
176FLASHMEM
status Router::route_carrier(SignalId output, SignalId input) {
177 auto output_carrier = output.cluster.carrier;
178 auto input_carrier = input.cluster.carrier;
179 if (output_carrier == input_carrier) {
180 return route_cluster(output, input);
183 auto output_stack = output_carrier.stack;
184 auto input_stack = input_carrier.stack;
186 auto output_carrier_block = find_carrier_t_block(output_carrier);
187 auto input_carrier_block = find_carrier_t_block(input_carrier);
190 if (8 <= output.id && output.id < 16) {
191 bool short_loop = stack_is_long_loop.find(output_stack) == stack_is_long_loop.end();
192 size_t loop_size = short_loop ? 3 : 6;
193 size_t carrier_offset = output.id < 12 ? 1 : loop_size - 1;
194 size_t next_carrier = (output_carrier.id + carrier_offset) % loop_size;
197 if (output_carrier.id >= 3)
200 CarrierId wired_carrier = CarrierId::from(input_stack.id,
static_cast<uint8_t
>(next_carrier));
202 if (wired_carrier != input_carrier)
203 return status(
"Connections between lanes [8, 15] are hard wired to different carrier");
205 int lane_offset = output.id < 12 ? 4 : -4;
206 auto wired_lane = output.id + lane_offset;
207 if (wired_lane != input.id)
208 return status(
"Output connections between lanes [8, 15] are hard wired to different input lanes");
210 auto output_sector_lane = output.id % 24;
211 auto input_sector_lane = input.id % 24;
213 status result = status::success();
214 result.attach(output_carrier_block->connect(output.cluster.id, 3, output_sector_lane));
215 result.attach(input_carrier_block->connect(3, input.cluster.id, input_sector_lane));
219 if (16 <= output.id && output.id < 32) {
220 if (output.id != input.id)
221 return status(
"Carrier connections only allowed between common lanes");
223 status result = status::success();
224 auto sector_lane = output.id;
225 result.attach(output_carrier_block->connect(output.cluster.id, 3, sector_lane));
226 result.attach(input_carrier_block->connect(3, input.cluster.id, sector_lane));
227 auto stack_block = find_stack_t_block(output_carrier);
228 return stack_block->connect(output.cluster.id % 3, input.cluster.id % 3, sector_lane);
231 return status::failure();
235 auto cluster_id =
carrier.id / 3;
236 auto stack_id =
carrier.stack.id;
237 return 2 * stack_id + (stack_id ^ cluster_id);
240FLASHMEM
status Router::route_stack(SignalId output, SignalId input) {
241 if (output.id < 16 || 32 <= output.id)
242 return status(
"Stack connection lanes out of range");
244 if (output.id != input.id)
245 return status(
"Can only connect mRedac's common lanes");
247 auto output_carrier = output.cluster.carrier;
248 auto input_carrier = input.cluster.carrier;
250 auto carrier_sector_lane = output.id - 8;
251 auto output_carrier_block = find_carrier_t_block(output_carrier);
254 if (output_carrier.is_lhs() == input_carrier.is_lhs())
255 return output_carrier_block->connect(output.cluster.id, input.cluster.id, carrier_sector_lane);
257 auto output_clock_idx =
clock_idx(output_carrier);
258 auto input_clock_idx =
clock_idx(input_carrier);
260 if (16 <= output.id && output.id < 24) {
261 bool cw = (output_clock_idx + 1) % 4 == input_clock_idx;
263 return status(
"Routing clockwise loop only on output lanes [16, 23]");
264 }
else if (24 <= output.id && output.id < 32) {
265 bool ccw = output_clock_idx == (input_clock_idx + 1) % 4;
267 return status(
"Routing counter clockwise loop only on output lanes [24, 31]");
270 auto input_carrier_block = find_carrier_t_block(input_carrier);
272 status result = status::success();
273 result.attach(output_carrier_block->connect(output.cluster.id, 3, carrier_sector_lane));
274 result.attach(input_carrier_block->connect(3, input.cluster.id, carrier_sector_lane));
276 auto output_stack_block = find_stack_t_block(output_carrier);
277 auto input_stack_block = find_stack_t_block(input_carrier);
278 result.attach(output_stack_block->connect(output.cluster.id, 3, carrier_sector_lane));
279 result.attach(input_stack_block->connect(3, input.cluster.id, carrier_sector_lane));
283FLASHMEM
status Router::route(SignalId output, SignalId input) {
284 assert(input.id < 32 && output.id < 32);
286 auto output_node = output.cluster;
287 auto input_node = input.cluster;
288 assert(output_node.id < 4 && input_node.id < 4);
290 auto output_carrier = output_node.carrier;
291 auto input_carrier = input_node.carrier;
292 assert(output_carrier.id < 6 && input_carrier.id < 6);
294 auto output_stack = output_carrier.stack;
295 auto input_stack = input_carrier.stack;
296 assert(output_stack.id < 2 && input_stack.id < 2);
298 if (output_stack != input_stack || output_carrier.is_lhs() != input_carrier.is_lhs())
299 return route_stack(output, input);
301 return route_carrier(output, input);
HAL class for TBlock version 1.0.1.
const functions::TriggerFunction f_reset_mux_disable
TBlockHAL_V_1_0_X(bus::addr_t block_address)
static const SPISettings F_CONNECTION_SPI_SETTINGS
bool reset_muxes() override
void reset_mux_disable() override
const functions::TriggerFunction f_set_mux_disable
const functions::TriggerFunction f_connections_sync
const functions::TriggerFunction f_reset_connections
const functions::SR74HCT595 f_connections
void set_mux_disable() override
bool write_muxes(std::array< Mux, 96 > muxes)
bool transfer(const void *mosi_buf, void *miso_buf, size_t count) const
static constexpr int success
FLASHMEM int clock_idx(CarrierId carrier)
FLASHMEM uint8_t four_muxes_to_bit_sequence(Mux mux_0, Mux mux_1, Mux mux_2, Mux mux_3)