1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
//! Fork some.
use super::*;
impl<P: Copy, R1: Copy, R2: Copy, const D: Dep> I<VrH<P, (R1, R2)>, D> {
/// Forks into some of the two `VrH` hazard interfaces.
///
/// An ingress transfer and egress transfers happen as soon as when the ingress payload is valid and at least one of
/// the egress ready signals is true. Note that the egress transfers happen only for the ready egress interfaces.
///
/// - Payload: Each egress payload becomes available when its own egress ready signal is true. The payload value `P`
/// is duplicated to multiple interfaces.
/// - Resolvers: The ingress ready signal is true if any of the egress ready signals are true. The inner values
/// `R1`, `R2` of the resolvers are preserved, and combined into one interface.
///
/// | Interface | Ingress | Egress |
/// | :-------: | ----------------- | -------------------------- |
/// | **Fwd** | `HOption<P>` | `(HOption<P>, HOption<P>)` |
/// | **Bwd** | `Ready<(R1, R2)>` | `(Ready<R1>, Ready<R2>)` |
#[allow(clippy::type_complexity)]
pub fn fork_some(self) -> (I<VrH<P, R1>, { Dep::Demanding }>, I<VrH<P, R2>, { Dep::Demanding }>) {
unsafe {
Interface::fsm(self, (), |ip, er: (Ready<R1>, Ready<R2>), ()| {
let ep = match ip {
Some(p) => {
let ep0 = if er.0.ready { Some(p) } else { None };
let ep1 = if er.1.ready { Some(p) } else { None };
(ep0, ep1)
}
None => (None, None),
};
let ir = Ready::new(er.0.ready || er.1.ready, (er.0.inner, er.1.inner));
(ep, ir, ())
})
}
}
}
macro_rules! impl_i_vr_h_fork_some {
($($R:ident),+; $($index:tt),+) => {
impl<P: Copy, $($R: Copy,)+ const D: Dep> I<VrH<P, ($($R,)+)>, D> {
/// A variation of [`fork_some`] to 3-12 `VrH` hazard interfaces. See the 2-tuple version for more
/// information.
#[allow(clippy::type_complexity)]
pub fn fork_some(self) -> ($(I<VrH<P, $R>, { Dep::Demanding }>,)+) {
unsafe {
Interface::fsm(self, (), |ip, er: ($(Ready<$R>,)+), ()| {
let ep = match ip {
Some(p) => ($(if er.$index.ready { Some(p) } else { None },)+),
None => ($(replace!($index, None),)+),
};
let ir = Ready::new($(er.$index.ready)||+, ($(er.$index.inner,)+));
(ep, ir, ())
})
}
}
}
};
}
impl_i_vr_h_fork_some! { R1, R2, R3; 0, 1, 2 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4; 0, 1, 2, 3 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4, R5; 0, 1, 2, 3, 4 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4, R5, R6; 0, 1, 2, 3, 4, 5 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4, R5, R6, R7; 0, 1, 2, 3, 4, 5, 6 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4, R5, R6, R7, R8; 0, 1, 2, 3, 4, 5, 6, 7 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4, R5, R6, R7, R8, R9; 0, 1, 2, 3, 4, 5, 6, 7, 8 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4, R5, R6, R7, R8, R9, R10; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
impl_i_vr_h_fork_some! { R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }
impl<P: Copy, R: Copy, const N: usize, const D: Dep> I<VrH<P, Array<R, N>>, D> {
/// Forks into some of the `N` `VrH` hazard interfaces.
///
/// An ingress transfer and egress transfers happen as soon as when the ingress payload is valid and at least one of
/// the egress ready signals are true. Note that the egress transfers happen only for the ready egress interfaces.
///
/// - Payload: Each egress payload becomes available when its own egress ready signal is true. The payload value `P`
/// is duplicated to multiple interfaces.
/// - Resolvers: The ingress ready signal is true if any of the egress ready signals are true. The inner values
/// `R` of the resolvers are preserved, and combined into one interface.
///
/// | Interface | Ingress | Egress |
/// | :-------: | -------------------- | ---------------------- |
/// | **Fwd** | `HOption<P>` | `Array<HOption<P>, N>` |
/// | **Bwd** | `Ready<Array<R, N>>` | `Array<Ready<R>, N>` |
pub fn fork_some(self) -> [I<VrH<P, R>, { Dep::Demanding }>; N] {
unsafe {
Interface::fsm(self, (), |ip, er: Array<Ready<R>, N>, ()| {
let ep = match ip {
Some(p) => er.map(|r| if r.ready { Some(p) } else { None }),
None => None.repeat(),
};
let ir = Ready::new(er.any(|r| r.ready), er.map(|r| r.inner));
(ep, ir, ())
})
}
}
}
impl<P: Copy, const D: Dep> Vr<P, D> {
/// A variation of [`fork_some`] for a valid-ready interface, that has the correct resolver type.
///
/// - Payload: Each egress payload becomes available when its own egress ready signal is true. The payload value `P`
/// is duplicated to multiple interfaces.
/// - Resolvers: The ingress ready signal is true if any of the egress ready signals are true.
///
/// | Interface | Ingress | Egress |
/// | :-------: | ------------ | -------------------------- |
/// | **Fwd** | `HOption<P>` | `(HOption<P>, HOption<P>)` |
/// | **Bwd** | `Ready<()>` | `(Ready<()>, Ready<()>)` |
pub fn fork_some(self) -> (Vr<P, { Dep::Demanding }>, Vr<P, { Dep::Demanding }>) {
self.map_resolver_inner::<((), ())>(|_| ()).fork_some()
}
}