1use rhdl::prelude::*;
47
48pub const MAX_REPLICAS: usize = 16;
50
51pub mod fault {
53 pub const CONFIG: u128 = 1;
55 pub const ORDER: u128 = 2;
57 pub const LENGTH: u128 = 4;
59 pub const DUP_SIG: u128 = 8;
61 pub const BAD_SIG: u128 = 16;
63 pub const EQUIVOCATION: u128 = 32;
65 pub const WRAP: u128 = 64;
67}
68
69#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
71pub struct RxConfig {
72 pub init: bool,
74 pub n: b5,
76 pub me: b5,
78 pub b: b5,
80 pub session: b64,
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Digital)]
87pub struct DataIn<const P: usize> {
88 pub valid: bool,
89 pub idx: b32,
90 pub len: b5,
92 pub payload: [b32; P],
93}
94
95#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
97pub struct EchoIn {
98 pub valid: bool,
99 pub from: b5,
100 pub idx: b32,
101 pub digest: [b64; 4],
102}
103
104#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
106pub struct SigIn {
107 pub valid: bool,
108 pub idx: b32,
109 pub sig: [b64; 8],
110}
111
112#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
116pub struct DigestIn {
117 pub valid: bool,
118 pub epoch: b32,
121 pub slot: b4,
122 pub idx: b32,
123 pub digest: [b64; 4],
124}
125
126#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
129pub struct VerdictIn {
130 pub valid: bool,
131 pub epoch: b32,
134 pub slot: b4,
135 pub idx: b32,
136 pub conflict: bool,
137 pub ok: bool,
138}
139
140#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
142pub struct WriteDoneIn {
143 pub valid: bool,
144 pub epoch: b32,
147 pub slot: b4,
148 pub idx: b32,
149}
150
151#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
155pub struct ReadAnswerIn {
156 pub valid: bool,
157 pub epoch: b32,
160 pub from: b5,
161 pub slot: b4,
162 pub idx: b32,
163 pub ok: bool,
164 pub empty: bool,
165 pub r_idx: b32,
166 pub r_digest: [b64; 4],
167 pub r_sig: [b64; 8],
168}
169
170#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
173pub struct CatchupIn {
174 pub enable: bool,
175 pub wait: b32,
177}
178
179#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
182pub struct FetchReqIn {
183 pub valid: bool,
184 pub from: b5,
185 pub epoch: b32,
186 pub idx: b32,
187}
188
189#[derive(Clone, Copy, Debug, PartialEq, Digital)]
193pub struct FetchAnsIn<const P: usize> {
194 pub valid: bool,
195 pub from: b5,
196 pub epoch: b32,
197 pub idx: b32,
198 pub len: b5,
199 pub payload: [b32; P],
200 pub sig: [b64; 8],
201}
202
203#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
206pub struct FetchReqOut {
207 pub valid: bool,
208 pub to: b5,
209 pub epoch: b32,
210 pub idx: b32,
211}
212
213#[derive(Clone, Copy, Debug, PartialEq, Digital)]
215pub struct FetchAnsOut<const P: usize> {
216 pub valid: bool,
217 pub to: b5,
218 pub epoch: b32,
219 pub idx: b32,
220 pub len: b5,
221 pub payload: [b32; P],
222 pub sig: [b64; 8],
223}
224
225#[derive(Clone, Copy, Debug, PartialEq, Digital)]
228pub struct RxIn<const P: usize> {
229 pub cfg: RxConfig,
230 pub data: DataIn<P>,
231 pub echo: EchoIn,
232 pub sig: SigIn,
233 pub digest: DigestIn,
234 pub verdict: VerdictIn,
235 pub wdone: WriteDoneIn,
236 pub rans: ReadAnswerIn,
237 pub catchup: CatchupIn,
238 pub freq: FetchReqIn,
239 pub fans: FetchAnsIn<P>,
240 pub fetch_ready: bool,
242 pub fans_ready: bool,
243 pub digest_ready: bool,
244 pub echo_ready: bool,
245 pub verify_ready: bool,
246 pub write_ready: bool,
247 pub read_ready: bool,
248 pub deliver_ready: bool,
249}
250
251#[derive(Clone, Copy, Debug, PartialEq, Digital)]
253pub struct DigestReq<const P: usize> {
254 pub valid: bool,
255 pub epoch: b32,
258 pub slot: b4,
259 pub idx: b32,
260 pub len: b5,
261 pub payload: [b32; P],
262}
263
264#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
266pub struct EchoOut {
267 pub valid: bool,
268 pub idx: b32,
269 pub digest: [b64; 4],
270}
271
272#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
275pub struct VerifyReq {
276 pub valid: bool,
277 pub epoch: b32,
280 pub slot: b4,
281 pub idx: b32,
282 pub conflict: bool,
283 pub digest: [b64; 4],
284 pub sig: [b64; 8],
285}
286
287#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
289pub struct WriteReq {
290 pub valid: bool,
291 pub epoch: b32,
294 pub slot: b4,
295 pub idx: b32,
296 pub digest: [b64; 4],
297 pub sig: [b64; 8],
298}
299
300#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
302pub struct ReadReq {
303 pub valid: bool,
304 pub epoch: b32,
307 pub from: b5,
308 pub slot: b4,
309 pub idx: b32,
310}
311
312#[derive(Clone, Copy, Debug, PartialEq, Digital)]
316pub struct Delivery<const P: usize> {
317 pub valid: bool,
318 pub gap: bool,
319 pub lo: b32,
321 pub idx: b32,
322 pub len: b5,
323 pub payload: [b32; P],
324 pub slow: bool,
326}
327
328#[derive(Clone, Copy, Debug, PartialEq, Digital)]
330pub struct RxOut<const P: usize> {
331 pub data_ready: bool,
332 pub digest_req: DigestReq<P>,
333 pub echo: EchoOut,
334 pub verify: VerifyReq,
335 pub write: WriteReq,
336 pub read: ReadReq,
337 pub deliver: Delivery<P>,
338 pub fetch: FetchReqOut,
339 pub fans: FetchAnsOut<P>,
340 pub fault: b8,
342 pub configured: bool,
343 pub quiescent: bool,
347 pub init_refused: bool,
349}
350
351#[derive(Clone, Copy, Debug, PartialEq, Digital)]
353pub struct Entry<const P: usize> {
354 pub live: bool,
356 pub early: bool,
358 pub idx: b32,
359 pub len: b5,
360 pub payload: [b32; P],
361 pub dig_sent: bool,
362 pub dig_have: bool,
363 pub digest: [b64; 4],
364 pub eref_have: bool,
366 pub eref: [b64; 4],
367 pub echo_bits: b16,
369 pub echo_bad: bool,
371 pub echo_sent: bool,
372 pub sig_have: bool,
373 pub sig: [b64; 8],
374 pub ver_sent: bool,
375 pub sig_ok: bool,
376 pub wr_sent: bool,
377 pub wr_done: bool,
378 pub rd_sent: b16,
380 pub checked: b16,
381 pub stuck: bool,
383 pub delivered: bool,
384 pub fetched: bool,
387}
388
389#[derive(Clone, Copy, Debug, PartialEq, Digital)]
391pub struct RxState<const T: usize, const P: usize> {
392 pub configured: bool,
393 pub epoch: b32,
395 pub n: b5,
396 pub me: b5,
397 pub b: b5,
398 pub session: b64,
399 pub others: b16,
401 pub fault: b8,
402 pub any_data: bool,
403 pub last_idx: b32,
404 pub e: [Entry<P>; T],
405 pub reg_busy: [bool; T],
407 pub busy_idx: [b32; T],
409 pub conf_busy: bool,
411 pub conf_sent: bool,
412 pub conf_slot: b4,
413 pub conf_idx: b32,
415 pub conf_ridx: b32,
418 pub conf_newer: bool,
419 pub conf_from: b5,
420 pub conf_digest: [b64; 4],
421 pub conf_sig: [b64; 8],
422 pub next_out: b32,
424 pub h_dig: DigestReq<P>,
427 pub h_echo: EchoOut,
428 pub h_ver: VerifyReq,
429 pub h_wr: WriteReq,
430 pub h_rd: ReadReq,
431 pub h_dl: Delivery<P>,
432 pub delivered_fast: b32,
434 pub delivered_slow: b32,
435 pub gaps: b32,
436 pub clock: b32,
441 pub f_busy: bool,
442 pub f_idx: b32,
443 pub f_start: b32,
444 pub f_last: b32,
445 pub f_inj: bool,
446 pub f_to: b5,
448 pub f_tried: bool,
449 pub f_tried_idx: b32,
450 pub h_fx: FetchReqOut,
451 pub h_fa: FetchAnsOut<P>,
452 pub recovered: b32,
453}
454
455impl<const P: usize> Entry<P> {
456 pub fn empty() -> Self {
457 Self {
458 live: false,
459 early: false,
460 idx: b32(0),
461 len: b5(0),
462 payload: [b32(0); P],
463 dig_sent: false,
464 dig_have: false,
465 digest: [b64(0); 4],
466 eref_have: false,
467 eref: [b64(0); 4],
468 echo_bits: b16(0),
469 echo_bad: false,
470 echo_sent: false,
471 sig_have: false,
472 sig: [b64(0); 8],
473 ver_sent: false,
474 sig_ok: false,
475 wr_sent: false,
476 wr_done: false,
477 rd_sent: b16(0),
478 checked: b16(0),
479 stuck: false,
480 delivered: false,
481 fetched: false,
482 }
483 }
484}
485
486impl<const T: usize, const P: usize> RxState<T, P> {
487 pub fn idle() -> Self {
488 Self {
489 configured: false,
490 epoch: b32(0),
491 n: b5(0),
492 me: b5(0),
493 b: b5(0),
494 session: b64(0),
495 others: b16(0),
496 fault: b8(0),
497 any_data: false,
498 last_idx: b32(0),
499 e: [Entry::empty(); T],
500 reg_busy: [false; T],
501 busy_idx: [b32(0); T],
502 conf_busy: false,
503 conf_sent: false,
504 conf_slot: b4(0),
505 conf_idx: b32(0),
506 conf_ridx: b32(0),
507 conf_newer: false,
508 conf_from: b5(0),
509 conf_digest: [b64(0); 4],
510 conf_sig: [b64(0); 8],
511 next_out: b32(0),
512 h_dig: DigestReq::<P> { valid: false, epoch: b32(0), slot: b4(0), idx: b32(0), len: b5(0), payload: [b32(0); P] },
513 h_echo: EchoOut::default(),
514 h_ver: VerifyReq::default(),
515 h_wr: WriteReq::default(),
516 h_rd: ReadReq::default(),
517 h_dl: Delivery::<P> { valid: false, gap: false, lo: b32(0), idx: b32(0), len: b5(0), payload: [b32(0); P], slow: false },
518 delivered_fast: b32(0),
519 delivered_slow: b32(0),
520 gaps: b32(0),
521 clock: b32(0),
522 f_busy: false,
523 f_idx: b32(0),
524 f_start: b32(0),
525 f_last: b32(0),
526 f_inj: false,
527 f_to: b5(0),
528 f_tried: false,
529 f_tried_idx: b32(0),
530 h_fx: FetchReqOut::default(),
531 h_fa: FetchAnsOut::<P> { valid: false, to: b5(0), epoch: b32(0), idx: b32(0), len: b5(0), payload: [b32(0); P], sig: [b64(0); 8] },
532 recovered: b32(0),
533 }
534 }
535}
536
537impl<const P: usize> Default for Entry<P> {
538 fn default() -> Self {
539 Self::empty()
540 }
541}
542
543impl<const T: usize, const P: usize> Default for RxState<T, P> {
544 fn default() -> Self {
545 Self::idle()
546 }
547}
548
549impl<const P: usize> Default for DataIn<P> {
550 fn default() -> Self {
551 Self { valid: false, idx: b32(0), len: b5(0), payload: [b32(0); P] }
552 }
553}
554
555impl<const P: usize> Default for RxIn<P> {
556 fn default() -> Self {
557 Self {
558 cfg: RxConfig::default(),
559 data: DataIn::default(),
560 echo: EchoIn::default(),
561 sig: SigIn::default(),
562 digest: DigestIn::default(),
563 verdict: VerdictIn::default(),
564 wdone: WriteDoneIn::default(),
565 rans: ReadAnswerIn::default(),
566 catchup: CatchupIn::default(),
567 freq: FetchReqIn::default(),
568 fans: FetchAnsIn::<P> { valid: false, from: b5(0), epoch: b32(0), idx: b32(0), len: b5(0), payload: [b32(0); P], sig: [b64(0); 8] },
569 fetch_ready: false,
570 fans_ready: false,
571 digest_ready: false,
572 echo_ready: false,
573 verify_ready: false,
574 write_ready: false,
575 read_ready: false,
576 deliver_ready: false,
577 }
578 }
579}
580
581#[kernel]
583pub fn empty_entry<const P: usize>() -> Entry<P> {
584 Entry::<P> {
585 live: false,
586 early: false,
587 idx: b32(0),
588 len: b5(0),
589 payload: [b32(0); P],
590 dig_sent: false,
591 dig_have: false,
592 digest: [b64(0); 4],
593 eref_have: false,
594 eref: [b64(0); 4],
595 echo_bits: b16(0),
596 echo_bad: false,
597 echo_sent: false,
598 sig_have: false,
599 sig: [b64(0); 8],
600 ver_sent: false,
601 sig_ok: false,
602 wr_sent: false,
603 wr_done: false,
604 rd_sent: b16(0),
605 checked: b16(0),
606 stuck: false,
607 delivered: false,
608 fetched: false,
609 }
610}
611
612#[kernel]
614pub fn idle_fans<const P: usize>() -> FetchAnsOut<P> {
615 FetchAnsOut::<P> { valid: false, to: b5(0), epoch: b32(0), idx: b32(0), len: b5(0), payload: [b32(0); P], sig: [b64(0); 8] }
616}
617
618#[kernel]
620pub fn idle_digest_req<const P: usize>() -> DigestReq<P> {
621 DigestReq::<P> { valid: false, epoch: b32(0), slot: b4(0), idx: b32(0), len: b5(0), payload: [b32(0); P] }
622}
623
624#[kernel]
626pub fn idle_delivery<const P: usize>() -> Delivery<P> {
627 Delivery::<P> { valid: false, gap: false, lo: b32(0), idx: b32(0), len: b5(0), payload: [b32(0); P], slow: false }
628}
629
630#[kernel]
632pub fn others_mask(n: b5, me: b5, b: b5) -> b16 {
633 let mut m = b16(0);
634 for k in 0..16 {
635 let id = b5(k as u128);
636 if id < n && id != me && id != b {
637 m = m | (b16(1) << b16(k as u128));
638 }
639 }
640 m
641}
642
643#[kernel]
645pub fn rx_step<const T: usize, const P: usize>(i: RxIn<P>, r: RxState<T, P>) -> (RxOut<P>, RxState<T, P>) {
646 let mut s = r;
647 let mask = b32(T as u128) - b32(1);
648 let tail = b33(T as u128);
649 let mut quiescent = true;
650 for k in 0..T {
651 if r.reg_busy[k] {
652 quiescent = false;
653 }
654 }
655 let init = i.cfg.init && quiescent;
658
659 if init {
661 let mut fresh = r;
662 fresh.configured = true;
663 fresh.epoch = r.epoch + b32(1);
664 fresh.n = i.cfg.n;
665 fresh.me = i.cfg.me;
666 fresh.b = i.cfg.b;
667 fresh.session = i.cfg.session;
668 fresh.others = others_mask(i.cfg.n, i.cfg.me, i.cfg.b);
669 fresh.fault = b8(0);
670 fresh.any_data = false;
671 fresh.last_idx = b32(0);
672 for k in 0..T {
673 fresh.e[k] = empty_entry::<P>();
674 fresh.reg_busy[k] = false;
675 fresh.busy_idx[k] = b32(0);
676 }
677 fresh.h_dig = idle_digest_req::<P>();
678 fresh.h_echo = EchoOut { valid: false, idx: b32(0), digest: [b64(0); 4] };
679 fresh.h_ver = VerifyReq { valid: false, epoch: b32(0), slot: b4(0), idx: b32(0), conflict: false, digest: [b64(0); 4], sig: [b64(0); 8] };
680 fresh.h_wr = WriteReq { valid: false, epoch: b32(0), slot: b4(0), idx: b32(0), digest: [b64(0); 4], sig: [b64(0); 8] };
681 fresh.h_rd = ReadReq { valid: false, epoch: b32(0), from: b5(0), slot: b4(0), idx: b32(0) };
682 fresh.h_dl = idle_delivery::<P>();
683 fresh.conf_busy = false;
684 fresh.conf_sent = false;
685 fresh.next_out = b32(0);
686 fresh.delivered_fast = b32(0);
687 fresh.delivered_slow = b32(0);
688 fresh.gaps = b32(0);
689 fresh.f_busy = false;
690 fresh.f_inj = false;
691 fresh.f_tried = false;
692 fresh.h_fx = FetchReqOut { valid: false, to: b5(0), epoch: b32(0), idx: b32(0) };
693 fresh.h_fa = idle_fans::<P>();
694 fresh.recovered = b32(0);
695 let bad = i.cfg.n < b5(3)
696 || i.cfg.n > b5(16)
697 || i.cfg.me >= i.cfg.n
698 || i.cfg.b >= i.cfg.n
699 || i.cfg.me == i.cfg.b
700 || i.cfg.session == b64(0);
701 if bad {
702 fresh.fault = b8(fault::CONFIG);
703 }
704 s = fresh;
705 }
706 let live_cfg = r.configured && !init;
707 let quarantined = r.fault != b8(0);
708 let mut fault_now = b8(0);
709
710 if live_cfg && i.digest.valid && i.digest.epoch == r.epoch {
713 let k = i.digest.slot;
714 let e = s.e[k];
715 if e.live && e.idx == i.digest.idx && !e.dig_have {
716 s.e[k].dig_have = true;
717 s.e[k].digest = i.digest.digest;
718 if e.eref_have && e.eref != i.digest.digest {
721 s.e[k].echo_bad = true;
722 }
723 }
724 }
725 if live_cfg && i.verdict.valid && i.verdict.epoch == r.epoch {
727 let k = i.verdict.slot;
728 let e = s.e[k];
729 if !i.verdict.conflict {
730 if e.live && e.idx == i.verdict.idx && e.ver_sent && !e.sig_ok {
731 if i.verdict.ok {
732 s.e[k].sig_ok = true;
733 } else if e.fetched {
734 s.e[k] = empty_entry::<P>();
737 s.f_inj = false;
738 } else {
739 fault_now = fault_now | b8(fault::BAD_SIG);
740 }
741 }
742 } else if s.conf_busy && s.conf_sent && s.conf_slot == i.verdict.slot && s.conf_ridx == i.verdict.idx {
743 s.conf_busy = false;
744 s.conf_sent = false;
745 let entry = e.live && e.idx == s.conf_idx;
746 if i.verdict.ok && !s.conf_newer {
747 fault_now = fault_now | b8(fault::EQUIVOCATION);
749 } else if i.verdict.ok {
750 if entry {
754 s.e[k].stuck = true;
755 }
756 } else if entry {
757 s.e[k].checked = e.checked | (b16(1) << s.conf_from.resize::<16>());
759 s.e[k].rd_sent = e.rd_sent & !(b16(1) << s.conf_from.resize::<16>());
760 }
761 }
762 }
763 if live_cfg && i.wdone.valid && i.wdone.epoch == r.epoch {
765 let k = i.wdone.slot;
766 if s.reg_busy[k] && s.busy_idx[k] == i.wdone.idx {
768 s.reg_busy[k] = false;
769 }
770 if s.e[k].live && s.e[k].idx == i.wdone.idx && s.e[k].wr_sent {
771 s.e[k].wr_done = true;
772 }
773 }
774 if live_cfg && i.rans.valid && i.rans.epoch == r.epoch {
776 let k = i.rans.slot;
777 let e = s.e[k];
778 let bit = b16(1) << i.rans.from.resize::<16>();
779 let ours = e.live && e.idx == i.rans.idx && (e.rd_sent & bit) != b16(0);
780 if ours {
781 if !i.rans.ok {
782 s.e[k].rd_sent = e.rd_sent & !bit;
784 } else if i.rans.empty
785 || i.rans.r_idx < e.idx
786 || (i.rans.r_idx & mask) != (e.idx & mask)
787 || (i.rans.r_digest[3] >> b64(32)) != b64(0)
788 {
789 s.e[k].checked = e.checked | bit;
796 } else if i.rans.r_idx == e.idx && e.dig_have && i.rans.r_digest == e.digest {
797 s.e[k].checked = e.checked | bit;
798 } else if !s.conf_busy {
799 s.conf_busy = true;
803 s.conf_sent = false;
804 s.conf_slot = i.rans.slot;
805 s.conf_idx = i.rans.idx;
806 s.conf_ridx = i.rans.r_idx;
807 s.conf_newer = i.rans.r_idx > e.idx;
808 s.conf_from = i.rans.from;
809 s.conf_digest = i.rans.r_digest;
810 s.conf_sig = i.rans.r_sig;
811 } else {
812 s.e[k].rd_sent = e.rd_sent & !bit;
814 }
815 }
816 }
817
818 let data_ready = live_cfg;
820
821 let mut o = RxOut::<P> {
829 data_ready: data_ready,
830 digest_req: r.h_dig,
831 echo: r.h_echo,
832 verify: r.h_ver,
833 write: r.h_wr,
834 read: r.h_rd,
835 deliver: r.h_dl,
836 fetch: r.h_fx,
837 fans: r.h_fa,
838 fault: r.fault,
839 configured: r.configured,
840 quiescent: quiescent,
841 init_refused: i.cfg.init && !quiescent,
842 };
843 if init {
844 o.digest_req.valid = false;
845 o.echo.valid = false;
846 o.verify.valid = false;
847 o.write.valid = false;
848 o.read.valid = false;
849 o.deliver.valid = false;
850 o.fetch.valid = false;
851 o.fans.valid = false;
852 }
853 if !init {
854 if r.h_dig.valid && i.digest_ready {
855 s.h_dig.valid = false;
856 }
857 if r.h_echo.valid && i.echo_ready {
858 s.h_echo.valid = false;
859 }
860 if r.h_ver.valid && i.verify_ready {
861 s.h_ver.valid = false;
862 }
863 if r.h_wr.valid && i.write_ready {
864 s.h_wr.valid = false;
865 }
866 if r.h_rd.valid && i.read_ready {
867 s.h_rd.valid = false;
868 }
869 if r.h_dl.valid && i.deliver_ready {
870 s.h_dl.valid = false;
871 }
872 if r.h_fx.valid && i.fetch_ready {
873 s.h_fx.valid = false;
874 }
875 if r.h_fa.valid && i.fans_ready {
876 s.h_fa.valid = false;
877 }
878 s.clock = r.clock + b32(1);
879 }
880 if r.configured && r.fault == b8(0) && !init {
881 let mut d_done = r.h_dig.valid;
882 let mut x_done = r.h_echo.valid;
883 let mut v_done = r.h_ver.valid;
884 let mut w_done = r.h_wr.valid;
885 let mut q_done = r.h_rd.valid;
886 for k in 0..T {
887 let e = r.e[k];
888 let slot = b4(k as u128);
889 if !d_done && e.live && !e.dig_sent {
890 d_done = true;
891 s.h_dig = DigestReq::<P> { valid: true, epoch: r.epoch, slot: slot, idx: e.idx, len: e.len, payload: e.payload };
892 s.e[k].dig_sent = true;
893 }
894 if !x_done && e.live && e.dig_have && !e.echo_sent {
895 x_done = true;
896 s.h_echo = EchoOut { valid: true, idx: e.idx, digest: e.digest };
897 s.e[k].echo_sent = true;
898 }
899 if !v_done && e.live && e.dig_have && e.sig_have && !e.ver_sent {
900 v_done = true;
901 s.h_ver = VerifyReq { valid: true, epoch: r.epoch, slot: slot, idx: e.idx, conflict: false, digest: e.digest, sig: e.sig };
902 s.e[k].ver_sent = true;
903 }
904 if !w_done && e.live && e.sig_ok && !e.wr_sent && !r.reg_busy[k] {
905 w_done = true;
906 s.h_wr = WriteReq { valid: true, epoch: r.epoch, slot: slot, idx: e.idx, digest: e.digest, sig: e.sig };
907 s.e[k].wr_sent = true;
908 s.reg_busy[k] = true;
909 s.busy_idx[k] = e.idx;
910 }
911 let want = r.others & !e.rd_sent & !e.checked;
912 if !q_done && e.live && e.wr_done && !e.stuck && !e.delivered && want != b16(0) {
913 q_done = true;
914 let mut from = b5(0);
915 let mut found = false;
916 for j in 0..16 {
917 if !found && ((want >> b16(j as u128)) & b16(1)) != b16(0) {
918 found = true;
919 from = b5(j as u128);
920 }
921 }
922 s.h_rd = ReadReq { valid: true, epoch: r.epoch, from: from, slot: slot, idx: e.idx };
923 s.e[k].rd_sent = s.e[k].rd_sent | (b16(1) << from.resize::<16>());
925 }
926 }
927 if !v_done && r.conf_busy && !r.conf_sent {
929 s.h_ver = VerifyReq { valid: true, epoch: r.epoch, slot: r.conf_slot, idx: r.conf_ridx, conflict: true, digest: r.conf_digest, sig: r.conf_sig };
930 s.conf_sent = true;
931 }
932
933 if !r.h_dl.valid {
935 let hk: b4 = (r.next_out & mask).resize();
937 let h = r.e[hk];
938 let held = h.live && h.idx == r.next_out;
939 let fast = h.dig_have && !h.echo_bad && h.echo_bits == r.others;
940 let slow = h.sig_ok && h.wr_done && !h.stuck && h.checked == r.others;
941 let cu = i.catchup.enable && T < 16;
944 let evicted = h.live && h.idx != r.next_out;
945 let pending = r.f_busy && r.f_idx == r.next_out;
946 let expired = pending && r.clock - r.f_start >= i.catchup.wait;
947 let tried = r.f_tried && r.f_tried_idx == r.next_out;
948 if held && !h.delivered && (fast || slow) {
949 s.h_dl = Delivery::<P> { valid: true, gap: false, lo: h.idx, idx: h.idx, len: h.len, payload: h.payload, slow: !fast };
950 s.e[hk].delivered = true;
951 s.next_out = r.next_out + b32(1);
952 if fast {
953 s.delivered_fast = r.delivered_fast + b32(1);
954 } else {
955 s.delivered_slow = r.delivered_slow + b32(1);
956 }
957 if h.fetched {
958 s.recovered = r.recovered + b32(1);
959 }
960 if pending {
961 s.f_busy = false;
962 s.f_inj = false;
963 }
964 } else if cu && held && pending && expired && h.fetched && !h.delivered {
965 s.e[hk] = empty_entry::<P>();
968 s.f_busy = false;
969 s.f_inj = false;
970 s.f_tried = true;
971 s.f_tried_idx = r.next_out;
972 } else if cu && !held && !evicted && !tried && !pending && r.any_data && r.last_idx >= r.next_out {
973 s.f_busy = true;
976 s.f_idx = r.next_out;
977 s.f_start = r.clock;
978 s.f_last = r.clock - (i.catchup.wait >> b32(4)) - b32(1);
979 s.f_inj = false;
980 s.f_to = b5(31);
982 } else if cu && !held && !evicted && pending && !expired {
983 } else if !held && r.any_data && r.last_idx >= r.next_out {
985 if pending {
986 s.f_busy = false;
987 s.f_inj = false;
988 s.f_tried = true;
989 s.f_tried_idx = r.next_out;
990 }
991 let mut hi = r.last_idx + b32(1);
995 for k in 0..T {
996 let e = r.e[k];
997 if e.live && e.idx > r.next_out && e.idx < hi {
998 hi = e.idx;
999 }
1000 }
1001 if cu && !evicted && hi > r.next_out + b32(1) {
1004 hi = r.next_out + b32(1);
1005 }
1006 s.h_dl = Delivery::<P> { valid: true, gap: true, lo: r.next_out, idx: hi, len: b5(0), payload: [b32(0); P], slow: false };
1007 s.next_out = hi;
1008 s.gaps = r.gaps + b32(1);
1009 }
1010 }
1011 let resend = (i.catchup.wait >> b32(4)) + b32(1);
1014 if !r.h_fx.valid && r.f_busy && !r.f_inj && r.clock - r.f_last >= resend {
1015 let mut first = b5(0);
1016 let mut have_first = false;
1017 let mut nxt = b5(0);
1018 let mut have_nxt = false;
1019 for k in 0..16 {
1020 let set = ((r.others >> b16(k as u128)) & b16(1)) != b16(0);
1021 if set && !have_first {
1022 have_first = true;
1023 first = b5(k as u128);
1024 }
1025 if set && !have_nxt && b5(k as u128) > r.f_to {
1026 have_nxt = true;
1027 nxt = b5(k as u128);
1028 }
1029 }
1030 let to = if have_nxt { nxt } else { first };
1031 if have_first {
1032 s.h_fx = FetchReqOut { valid: true, to: to, epoch: r.epoch, idx: r.f_idx };
1033 s.f_to = to;
1034 s.f_last = r.clock;
1035 }
1036 }
1037 if !r.h_fa.valid && i.freq.valid && i.freq.from < r.n && i.freq.from != r.me && i.freq.from != r.b {
1041 let fk: b4 = (i.freq.idx & mask).resize();
1042 let fe = r.e[fk];
1043 if fe.live && fe.idx == i.freq.idx && fe.sig_have && !fe.fetched {
1044 s.h_fa = FetchAnsOut::<P> { valid: true, to: i.freq.from, epoch: i.freq.epoch, idx: fe.idx, len: fe.len, payload: fe.payload, sig: fe.sig };
1045 }
1046 }
1047 }
1048
1049 if live_cfg && i.data.valid && data_ready {
1051 if quarantined {
1052 } else if i.data.idx >= b32(0xFFFF_0000) {
1054 fault_now = fault_now | b8(fault::WRAP);
1055 } else if s.any_data && i.data.idx <= s.last_idx {
1056 fault_now = fault_now | b8(fault::ORDER);
1057 } else if i.data.len > b5(P as u128) {
1058 fault_now = fault_now | b8(fault::LENGTH);
1059 } else {
1060 s.any_data = true;
1061 s.last_idx = i.data.idx;
1062 let idx33: b33 = i.data.idx.resize();
1063 for k in 0..T {
1066 let e = s.e[k];
1067 let old = (e.live || e.early) && e.idx.resize::<33>() + tail <= idx33;
1068 if old {
1069 s.e[k] = empty_entry::<P>();
1070 }
1071 }
1072 let k: b4 = (i.data.idx & mask).resize();
1073 let e = s.e[k];
1074 let mut n = empty_entry::<P>();
1075 if e.early && e.idx == i.data.idx {
1077 n.echo_bits = e.echo_bits;
1078 n.echo_bad = e.echo_bad;
1079 n.eref_have = e.eref_have;
1080 n.eref = e.eref;
1081 }
1082 n.live = true;
1083 n.idx = i.data.idx;
1084 n.len = i.data.len;
1085 n.payload = i.data.payload;
1086 s.e[k] = n;
1087 }
1088 }
1089
1090 if live_cfg && i.echo.valid && !quarantined {
1092 let bit = b16(1) << i.echo.from.resize::<16>();
1093 let from_ok = (s.others & bit) != b16(0);
1094 let k: b4 = (i.echo.idx & mask).resize();
1095 let e = s.e[k];
1096 if from_ok && (e.echo_bits & bit) == b16(0) {
1097 if e.live && e.idx == i.echo.idx {
1098 s.e[k].echo_bits = e.echo_bits | bit;
1099 if e.dig_have {
1100 if i.echo.digest != e.digest {
1101 s.e[k].echo_bad = true;
1102 }
1103 } else if e.eref_have {
1104 if i.echo.digest != e.eref {
1105 s.e[k].echo_bad = true;
1106 }
1107 } else {
1108 s.e[k].eref_have = true;
1109 s.e[k].eref = i.echo.digest;
1110 }
1111 } else if e.early && e.idx == i.echo.idx {
1112 s.e[k].echo_bits = e.echo_bits | bit;
1113 if i.echo.digest != e.eref {
1114 s.e[k].echo_bad = true;
1115 }
1116 } else {
1117 let ahead = !s.any_data || i.echo.idx > s.last_idx;
1121 let free = !e.live && (!e.early || e.idx < i.echo.idx);
1122 if ahead && free {
1123 let mut n = empty_entry::<P>();
1124 n.early = true;
1125 n.idx = i.echo.idx;
1126 n.echo_bits = bit;
1127 n.eref_have = true;
1128 n.eref = i.echo.digest;
1129 s.e[k] = n;
1130 }
1131 }
1132 }
1133 }
1134
1135 if live_cfg && i.sig.valid && !quarantined {
1137 let k: b4 = (i.sig.idx & mask).resize();
1138 let e = s.e[k];
1139 if e.live && e.idx == i.sig.idx {
1140 if e.sig_have && e.fetched {
1141 } else if e.sig_have {
1145 fault_now = fault_now | b8(fault::DUP_SIG);
1146 } else {
1147 s.e[k].sig_have = true;
1148 s.e[k].sig = i.sig.sig;
1149 }
1150 }
1151 }
1152
1153 if live_cfg && !quarantined && i.fans.valid && i.fans.epoch == r.epoch && s.f_busy && !s.f_inj && i.fans.from == s.f_to && i.fans.idx == s.f_idx && i.fans.len <= b5(P as u128) {
1158 let fk: b4 = (i.fans.idx & mask).resize();
1159 let fe = s.e[fk];
1160 let in_tail = i.fans.idx.resize::<33>() + tail > s.last_idx.resize::<33>();
1161 let free = !fe.live && (!fe.early || fe.idx == i.fans.idx);
1162 if in_tail && free {
1163 let mut n = empty_entry::<P>();
1164 if fe.early && fe.idx == i.fans.idx {
1165 n.echo_bits = fe.echo_bits;
1166 n.echo_bad = fe.echo_bad;
1167 n.eref_have = fe.eref_have;
1168 n.eref = fe.eref;
1169 }
1170 n.live = true;
1171 n.idx = i.fans.idx;
1172 n.len = i.fans.len;
1173 n.payload = i.fans.payload;
1174 n.sig_have = true;
1175 n.sig = i.fans.sig;
1176 n.fetched = true;
1177 s.e[fk] = n;
1178 s.f_inj = true;
1179 }
1180 }
1181
1182 s.fault = s.fault | fault_now;
1184 (o, s)
1185}