1use rhdl::prelude::*;
43use rhdl_fpga::core::dff::DFF;
44use sha256_rhdl::lane::{CompressionInput, CompressionOutput};
45
46use crate::tag::{decode_tag_kernel, decode_task_tag, tag_is_well_formed_kernel};
47
48pub const CONTEXT_COUNT: usize = 9;
50pub const LANE_COUNT: usize = 3;
52
53const _: () = {
54 assert!(CONTEXT_COUNT <= 16);
55 assert!(LANE_COUNT <= CONTEXT_COUNT);
56};
57
58#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
60pub struct IssueInput {
61 pub contexts: [CompressionInput; CONTEXT_COUNT],
63}
64
65#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
71pub struct IssueControlInput {
72 pub valid: [bool; CONTEXT_COUNT],
74 pub tags: [b32; CONTEXT_COUNT],
76}
77
78#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
80pub struct IssueControlOutput {
81 pub lane_contexts: [b4; LANE_COUNT],
83 pub lane_valid: [bool; LANE_COUNT],
85 pub accepted: [bool; CONTEXT_COUNT],
87 pub rejected: [bool; CONTEXT_COUNT],
89 pub grant_count: b2,
91 pub next_context: b4,
93}
94
95#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
97pub struct IssueOutput {
98 pub lanes: [CompressionInput; LANE_COUNT],
100 pub ready: [bool; CONTEXT_COUNT],
105 pub accepted: [bool; CONTEXT_COUNT],
108 pub rejected: [bool; CONTEXT_COUNT],
111 pub grant_count: b2,
113 pub next_context: b4,
115}
116
117#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
119pub struct ResponseRouterInput {
120 pub lanes: [CompressionOutput; LANE_COUNT],
122}
123
124#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
126pub struct ResponseControlInput {
127 pub valid: [bool; LANE_COUNT],
129 pub tags: [b32; LANE_COUNT],
131}
132
133#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
135pub struct ResponseControlOutput {
136 pub lane_contexts: [b4; LANE_COUNT],
138 pub lane_accepted: [bool; LANE_COUNT],
140 pub context_accepted: [bool; CONTEXT_COUNT],
142 pub malformed: [bool; LANE_COUNT],
144 pub out_of_range: [bool; LANE_COUNT],
146 pub collision: [bool; LANE_COUNT],
148 pub rejected: [bool; LANE_COUNT],
150}
151
152#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
154pub struct ResponseRouterOutput {
155 pub contexts: [CompressionOutput; CONTEXT_COUNT],
157 pub accepted: [bool; CONTEXT_COUNT],
159 pub lane_accepted: [bool; LANE_COUNT],
161 pub malformed: [bool; LANE_COUNT],
163 pub out_of_range: [bool; LANE_COUNT],
165 pub collision: [bool; LANE_COUNT],
168 pub rejected: [bool; LANE_COUNT],
170}
171
172#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
174pub struct TransportInput {
175 pub issue: IssueInput,
177 pub returns: ResponseRouterInput,
179}
180
181#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
183pub struct TransportOutput {
184 pub issue: IssueOutput,
186 pub returns: ResponseRouterOutput,
188}
189
190#[kernel]
196fn select_request_kernel(
197 requests: [CompressionInput; CONTEXT_COUNT],
198 context: b4,
199) -> CompressionInput {
200 match context {
201 Bits::<4>(0) => requests[0],
202 Bits::<4>(1) => requests[1],
203 Bits::<4>(2) => requests[2],
204 Bits::<4>(3) => requests[3],
205 Bits::<4>(4) => requests[4],
206 Bits::<4>(5) => requests[5],
207 Bits::<4>(6) => requests[6],
208 Bits::<4>(7) => requests[7],
209 _ => requests[8],
210 }
211}
212
213#[kernel]
215fn increment_context_kernel(context: b4) -> b4 {
216 if context == b4(8) {
217 b4(0)
218 } else {
219 context + b4(1)
220 }
221}
222
223#[kernel]
225fn context_mask_kernel(mask: b9) -> [bool; CONTEXT_COUNT] {
226 [
227 mask & b9(0x001) != b9(0),
228 mask & b9(0x002) != b9(0),
229 mask & b9(0x004) != b9(0),
230 mask & b9(0x008) != b9(0),
231 mask & b9(0x010) != b9(0),
232 mask & b9(0x020) != b9(0),
233 mask & b9(0x040) != b9(0),
234 mask & b9(0x080) != b9(0),
235 mask & b9(0x100) != b9(0),
236 ]
237}
238
239#[kernel]
244#[allow(clippy::assign_op_pattern)] pub fn issue_control_kernel(input: IssueControlInput, cursor: b4) -> IssueControlOutput {
246 let mut lane_contexts = [b4(0); LANE_COUNT];
247 let mut lane_valid = [false; LANE_COUNT];
248 let mut accepted_mask = b9(0);
249 let mut rejected_mask = b9(0);
250 let mut eligible_mask = b9(0);
251 let mut grant_count = b2(0);
252 let mut scan_context = cursor;
253 let mut next_context = cursor;
254
255 let fields = [
259 decode_tag_kernel(input.tags[0]),
260 decode_tag_kernel(input.tags[1]),
261 decode_tag_kernel(input.tags[2]),
262 decode_tag_kernel(input.tags[3]),
263 decode_tag_kernel(input.tags[4]),
264 decode_tag_kernel(input.tags[5]),
265 decode_tag_kernel(input.tags[6]),
266 decode_tag_kernel(input.tags[7]),
267 decode_tag_kernel(input.tags[8]),
268 ];
269 let canonical = [
270 tag_is_well_formed_kernel(input.tags[0]) && fields[0].context == b4(0),
271 tag_is_well_formed_kernel(input.tags[1]) && fields[1].context == b4(1),
272 tag_is_well_formed_kernel(input.tags[2]) && fields[2].context == b4(2),
273 tag_is_well_formed_kernel(input.tags[3]) && fields[3].context == b4(3),
274 tag_is_well_formed_kernel(input.tags[4]) && fields[4].context == b4(4),
275 tag_is_well_formed_kernel(input.tags[5]) && fields[5].context == b4(5),
276 tag_is_well_formed_kernel(input.tags[6]) && fields[6].context == b4(6),
277 tag_is_well_formed_kernel(input.tags[7]) && fields[7].context == b4(7),
278 tag_is_well_formed_kernel(input.tags[8]) && fields[8].context == b4(8),
279 ];
280 if input.valid[0] && canonical[0] {
281 eligible_mask = eligible_mask | b9(0x001);
282 }
283 if input.valid[1] && canonical[1] {
284 eligible_mask = eligible_mask | b9(0x002);
285 }
286 if input.valid[2] && canonical[2] {
287 eligible_mask = eligible_mask | b9(0x004);
288 }
289 if input.valid[3] && canonical[3] {
290 eligible_mask = eligible_mask | b9(0x008);
291 }
292 if input.valid[4] && canonical[4] {
293 eligible_mask = eligible_mask | b9(0x010);
294 }
295 if input.valid[5] && canonical[5] {
296 eligible_mask = eligible_mask | b9(0x020);
297 }
298 if input.valid[6] && canonical[6] {
299 eligible_mask = eligible_mask | b9(0x040);
300 }
301 if input.valid[7] && canonical[7] {
302 eligible_mask = eligible_mask | b9(0x080);
303 }
304 if input.valid[8] && canonical[8] {
305 eligible_mask = eligible_mask | b9(0x100);
306 }
307 if input.valid[0] && !canonical[0] {
308 rejected_mask = rejected_mask | b9(0x001);
309 }
310 if input.valid[1] && !canonical[1] {
311 rejected_mask = rejected_mask | b9(0x002);
312 }
313 if input.valid[2] && !canonical[2] {
314 rejected_mask = rejected_mask | b9(0x004);
315 }
316 if input.valid[3] && !canonical[3] {
317 rejected_mask = rejected_mask | b9(0x008);
318 }
319 if input.valid[4] && !canonical[4] {
320 rejected_mask = rejected_mask | b9(0x010);
321 }
322 if input.valid[5] && !canonical[5] {
323 rejected_mask = rejected_mask | b9(0x020);
324 }
325 if input.valid[6] && !canonical[6] {
326 rejected_mask = rejected_mask | b9(0x040);
327 }
328 if input.valid[7] && !canonical[7] {
329 rejected_mask = rejected_mask | b9(0x080);
330 }
331 if input.valid[8] && !canonical[8] {
332 rejected_mask = rejected_mask | b9(0x100);
333 }
334
335 for _offset in 0..CONTEXT_COUNT {
336 let context_bit = b9(1) << scan_context;
337 let eligible = eligible_mask & context_bit != b9(0);
338 if eligible && grant_count < b2(3) {
339 match grant_count {
340 Bits::<2>(0) => {
341 lane_contexts[0] = scan_context;
342 lane_valid[0] = true;
343 }
344 Bits::<2>(1) => {
345 lane_contexts[1] = scan_context;
346 lane_valid[1] = true;
347 }
348 _ => {
349 lane_contexts[2] = scan_context;
350 lane_valid[2] = true;
351 }
352 }
353 accepted_mask = accepted_mask | context_bit;
354 grant_count = grant_count + b2(1);
355 next_context = increment_context_kernel(scan_context);
356 }
357 scan_context = increment_context_kernel(scan_context);
358 }
359
360 let accepted = context_mask_kernel(accepted_mask);
361 IssueControlOutput {
362 lane_contexts,
363 lane_valid,
364 accepted,
365 rejected: context_mask_kernel(rejected_mask),
366 grant_count,
367 next_context,
368 }
369}
370
371#[kernel]
377pub fn issue_requests_kernel(input: IssueInput, cursor: b4) -> IssueOutput {
378 let control = issue_control_kernel(
379 IssueControlInput {
380 valid: [
381 input.contexts[0].valid,
382 input.contexts[1].valid,
383 input.contexts[2].valid,
384 input.contexts[3].valid,
385 input.contexts[4].valid,
386 input.contexts[5].valid,
387 input.contexts[6].valid,
388 input.contexts[7].valid,
389 input.contexts[8].valid,
390 ],
391 tags: [
392 input.contexts[0].tag,
393 input.contexts[1].tag,
394 input.contexts[2].tag,
395 input.contexts[3].tag,
396 input.contexts[4].tag,
397 input.contexts[5].tag,
398 input.contexts[6].tag,
399 input.contexts[7].tag,
400 input.contexts[8].tag,
401 ],
402 },
403 cursor,
404 );
405 let mut lanes = [CompressionInput::default(); LANE_COUNT];
406 if control.lane_valid[0] {
407 lanes[0] = select_request_kernel(input.contexts, control.lane_contexts[0]);
408 }
409 if control.lane_valid[1] {
410 lanes[1] = select_request_kernel(input.contexts, control.lane_contexts[1]);
411 }
412 if control.lane_valid[2] {
413 lanes[2] = select_request_kernel(input.contexts, control.lane_contexts[2]);
414 }
415 IssueOutput {
416 lanes,
417 ready: control.accepted,
418 accepted: control.accepted,
419 rejected: control.rejected,
420 grant_count: control.grant_count,
421 next_context: control.next_context,
422 }
423}
424
425#[kernel]
427fn select_response_kernel(
428 lanes: [CompressionOutput; LANE_COUNT],
429 lane_contexts: [b4; LANE_COUNT],
430 lane_accepted: [bool; LANE_COUNT],
431 context: b4,
432) -> CompressionOutput {
433 let mut response = CompressionOutput::default();
434 if lane_accepted[0] && lane_contexts[0] == context {
435 response = lanes[0];
436 }
437 if lane_accepted[1] && lane_contexts[1] == context {
438 response = lanes[1];
439 }
440 if lane_accepted[2] && lane_contexts[2] == context {
441 response = lanes[2];
442 }
443 response
444}
445
446#[kernel]
451pub fn response_control_kernel(input: ResponseControlInput) -> ResponseControlOutput {
452 let fields = [
453 decode_tag_kernel(input.tags[0]),
454 decode_tag_kernel(input.tags[1]),
455 decode_tag_kernel(input.tags[2]),
456 ];
457 let well_formed = [
458 tag_is_well_formed_kernel(input.tags[0]),
459 tag_is_well_formed_kernel(input.tags[1]),
460 tag_is_well_formed_kernel(input.tags[2]),
461 ];
462 let lane_contexts = [fields[0].context, fields[1].context, fields[2].context];
463 let malformed = [
464 input.valid[0] && !well_formed[0],
465 input.valid[1] && !well_formed[1],
466 input.valid[2] && !well_formed[2],
467 ];
468 let out_of_range = [
469 input.valid[0] && well_formed[0] && lane_contexts[0] >= b4(9),
470 input.valid[1] && well_formed[1] && lane_contexts[1] >= b4(9),
471 input.valid[2] && well_formed[2] && lane_contexts[2] >= b4(9),
472 ];
473 let eligible = [
474 input.valid[0] && well_formed[0] && lane_contexts[0] < b4(9),
475 input.valid[1] && well_formed[1] && lane_contexts[1] < b4(9),
476 input.valid[2] && well_formed[2] && lane_contexts[2] < b4(9),
477 ];
478 let collision = [
479 eligible[0]
480 && ((eligible[1] && lane_contexts[0] == lane_contexts[1])
481 || (eligible[2] && lane_contexts[0] == lane_contexts[2])),
482 eligible[1]
483 && ((eligible[0] && lane_contexts[1] == lane_contexts[0])
484 || (eligible[2] && lane_contexts[1] == lane_contexts[2])),
485 eligible[2]
486 && ((eligible[0] && lane_contexts[2] == lane_contexts[0])
487 || (eligible[1] && lane_contexts[2] == lane_contexts[1])),
488 ];
489 let lane_accepted = [
490 eligible[0] && !collision[0],
491 eligible[1] && !collision[1],
492 eligible[2] && !collision[2],
493 ];
494 let context_accepted = [
495 (lane_accepted[0] && lane_contexts[0] == b4(0))
496 || (lane_accepted[1] && lane_contexts[1] == b4(0))
497 || (lane_accepted[2] && lane_contexts[2] == b4(0)),
498 (lane_accepted[0] && lane_contexts[0] == b4(1))
499 || (lane_accepted[1] && lane_contexts[1] == b4(1))
500 || (lane_accepted[2] && lane_contexts[2] == b4(1)),
501 (lane_accepted[0] && lane_contexts[0] == b4(2))
502 || (lane_accepted[1] && lane_contexts[1] == b4(2))
503 || (lane_accepted[2] && lane_contexts[2] == b4(2)),
504 (lane_accepted[0] && lane_contexts[0] == b4(3))
505 || (lane_accepted[1] && lane_contexts[1] == b4(3))
506 || (lane_accepted[2] && lane_contexts[2] == b4(3)),
507 (lane_accepted[0] && lane_contexts[0] == b4(4))
508 || (lane_accepted[1] && lane_contexts[1] == b4(4))
509 || (lane_accepted[2] && lane_contexts[2] == b4(4)),
510 (lane_accepted[0] && lane_contexts[0] == b4(5))
511 || (lane_accepted[1] && lane_contexts[1] == b4(5))
512 || (lane_accepted[2] && lane_contexts[2] == b4(5)),
513 (lane_accepted[0] && lane_contexts[0] == b4(6))
514 || (lane_accepted[1] && lane_contexts[1] == b4(6))
515 || (lane_accepted[2] && lane_contexts[2] == b4(6)),
516 (lane_accepted[0] && lane_contexts[0] == b4(7))
517 || (lane_accepted[1] && lane_contexts[1] == b4(7))
518 || (lane_accepted[2] && lane_contexts[2] == b4(7)),
519 (lane_accepted[0] && lane_contexts[0] == b4(8))
520 || (lane_accepted[1] && lane_contexts[1] == b4(8))
521 || (lane_accepted[2] && lane_contexts[2] == b4(8)),
522 ];
523 ResponseControlOutput {
524 lane_contexts,
525 lane_accepted,
526 context_accepted,
527 malformed,
528 out_of_range,
529 collision,
530 rejected: [
531 malformed[0] || out_of_range[0] || collision[0],
532 malformed[1] || out_of_range[1] || collision[1],
533 malformed[2] || out_of_range[2] || collision[2],
534 ],
535 }
536}
537
538#[kernel]
543pub fn route_responses_kernel(input: ResponseRouterInput) -> ResponseRouterOutput {
544 let control = response_control_kernel(ResponseControlInput {
545 valid: [
546 input.lanes[0].valid,
547 input.lanes[1].valid,
548 input.lanes[2].valid,
549 ],
550 tags: [input.lanes[0].tag, input.lanes[1].tag, input.lanes[2].tag],
551 });
552 let contexts = [
553 select_response_kernel(
554 input.lanes,
555 control.lane_contexts,
556 control.lane_accepted,
557 b4(0),
558 ),
559 select_response_kernel(
560 input.lanes,
561 control.lane_contexts,
562 control.lane_accepted,
563 b4(1),
564 ),
565 select_response_kernel(
566 input.lanes,
567 control.lane_contexts,
568 control.lane_accepted,
569 b4(2),
570 ),
571 select_response_kernel(
572 input.lanes,
573 control.lane_contexts,
574 control.lane_accepted,
575 b4(3),
576 ),
577 select_response_kernel(
578 input.lanes,
579 control.lane_contexts,
580 control.lane_accepted,
581 b4(4),
582 ),
583 select_response_kernel(
584 input.lanes,
585 control.lane_contexts,
586 control.lane_accepted,
587 b4(5),
588 ),
589 select_response_kernel(
590 input.lanes,
591 control.lane_contexts,
592 control.lane_accepted,
593 b4(6),
594 ),
595 select_response_kernel(
596 input.lanes,
597 control.lane_contexts,
598 control.lane_accepted,
599 b4(7),
600 ),
601 select_response_kernel(
602 input.lanes,
603 control.lane_contexts,
604 control.lane_accepted,
605 b4(8),
606 ),
607 ];
608 ResponseRouterOutput {
609 contexts,
610 accepted: control.context_accepted,
611 lane_accepted: control.lane_accepted,
612 malformed: control.malformed,
613 out_of_range: control.out_of_range,
614 collision: control.collision,
615 rejected: control.rejected,
616 }
617}
618
619#[derive(Clone, Debug, Synchronous, SynchronousDQ)]
624#[rhdl(dq_no_prefix)]
625pub struct ShaTransportFabric {
626 cursor: DFF<b4>,
627}
628
629impl Default for ShaTransportFabric {
630 fn default() -> Self {
631 Self {
632 cursor: DFF::new(b4(0)),
633 }
634 }
635}
636
637impl SynchronousIO for ShaTransportFabric {
638 type I = TransportInput;
639 type O = TransportOutput;
640 type Kernel = sha_transport_fabric_kernel;
641}
642
643#[kernel]
645#[allow(clippy::used_underscore_binding)] pub fn sha_transport_fabric_kernel(
647 _clock_reset: ClockReset,
648 input: TransportInput,
649 q: Q,
650) -> (TransportOutput, D) {
651 let issue = issue_requests_kernel(input.issue, q.cursor);
652 let returns = route_responses_kernel(input.returns);
653 (
654 TransportOutput { issue, returns },
655 D {
656 cursor: issue.next_context,
657 },
658 )
659}
660
661fn word_u32(word: b32) -> u32 {
662 let bytes = word.raw().to_le_bytes();
663 u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
664}
665
666fn host_request_is_canonical(request: &CompressionInput, slot: usize) -> bool {
667 if !request.valid {
668 return false;
669 }
670 decode_task_tag(word_u32(request.tag)).is_ok_and(|tag| usize::from(tag.context) == slot)
671}
672
673#[must_use]
683pub fn host_issue_oracle(input: IssueInput, cursor: usize) -> IssueOutput {
684 assert!(cursor < CONTEXT_COUNT, "host cursor must name a context");
685 let mut output = IssueOutput {
686 next_context: b4(u128::try_from(cursor).expect("nine contexts fit b4")),
687 ..IssueOutput::default()
688 };
689 let mut granted = 0_usize;
690 for offset in 0..CONTEXT_COUNT {
691 let slot = (cursor + offset) % CONTEXT_COUNT;
692 let request = input.contexts[slot];
693 let canonical = host_request_is_canonical(&request, slot);
694 if request.valid && !canonical {
695 output.rejected[slot] = true;
696 }
697 if canonical && granted < LANE_COUNT {
698 output.lanes[granted] = request;
699 output.ready[slot] = true;
700 output.accepted[slot] = true;
701 granted += 1;
702 output.next_context =
703 b4(u128::try_from((slot + 1) % CONTEXT_COUNT).expect("nine contexts fit b4"));
704 }
705 }
706 output.grant_count = b2(u128::try_from(granted).expect("three grants fit b2"));
707 output
708}
709
710#[must_use]
714pub fn host_response_router_oracle(input: ResponseRouterInput) -> ResponseRouterOutput {
715 let mut output = ResponseRouterOutput::default();
716 let mut decoded_contexts = [None; LANE_COUNT];
717
718 for (lane, response) in input.lanes.into_iter().enumerate() {
719 if !response.valid {
720 continue;
721 }
722 match decode_task_tag(word_u32(response.tag)) {
723 Err(_) => output.malformed[lane] = true,
724 Ok(tag) if usize::from(tag.context) >= CONTEXT_COUNT => {
725 output.out_of_range[lane] = true;
726 }
727 Ok(tag) => decoded_contexts[lane] = Some(usize::from(tag.context)),
728 }
729 }
730
731 for left in 0..LANE_COUNT {
732 for right in (left + 1)..LANE_COUNT {
733 if decoded_contexts[left].is_some() && decoded_contexts[left] == decoded_contexts[right]
734 {
735 output.collision[left] = true;
736 output.collision[right] = true;
737 }
738 }
739 }
740
741 for (lane, decoded_context) in decoded_contexts.into_iter().enumerate() {
742 output.rejected[lane] =
743 output.malformed[lane] || output.out_of_range[lane] || output.collision[lane];
744 if let Some(context) = decoded_context
745 && !output.rejected[lane]
746 {
747 output.contexts[context] = input.lanes[lane];
748 output.accepted[context] = true;
749 output.lane_accepted[lane] = true;
750 }
751 }
752 output
753}