1use std::cell::RefCell;
19use std::rc::Rc;
20
21use async_trait::async_trait;
22use gwr_components::delay::Delay;
23use gwr_components::flow_controls::credit_issuer::CreditIssuer;
24use gwr_components::flow_controls::credit_limiter::CreditLimiter;
25use gwr_components::store::ObjectStore;
26use gwr_components::types::Credit;
27use gwr_components::{connect_port, connect_tx, port_rx};
28use gwr_engine::engine::Engine;
29use gwr_engine::port::PortStateResult;
30use gwr_engine::time::clock::Clock;
31use gwr_engine::traits::SimObject;
32use gwr_engine::types::{SimError, SimResult};
33use gwr_model_builder::{EntityDisplay, EntityGet, Runnable};
34use gwr_track::build_aka;
35use gwr_track::entity::Entity;
36use gwr_track::tracker::aka::Aka;
37
38pub struct FcPipelineConfig {
40 buffer_size: usize,
41 data_delay_ticks: usize,
42 credit_delay_ticks: usize,
43}
44
45impl FcPipelineConfig {
46 #[must_use]
47 pub fn new(buffer_size: usize, data_delay_ticks: usize, credit_delay_ticks: usize) -> Self {
48 Self {
49 buffer_size,
50 data_delay_ticks,
51 credit_delay_ticks,
52 }
53 }
54}
55
56#[derive(EntityGet, EntityDisplay, Runnable)]
58pub struct FcPipeline<T>
59where
60 T: SimObject,
61{
62 entity: Rc<Entity>,
63 credit_limiter: RefCell<Option<Rc<CreditLimiter<T>>>>,
64 credit_delay: RefCell<Option<Rc<Delay<Credit>>>>,
65 credit_issuer: RefCell<Option<Rc<CreditIssuer<T>>>>,
66 data_delay: RefCell<Option<Rc<Delay<T>>>>,
67}
68
69impl<T> FcPipeline<T>
70where
71 T: SimObject,
72{
73 pub fn new_and_register_with_renames(
74 engine: &Engine,
75 clock: &Clock,
76 parent: &Rc<Entity>,
77 name: &str,
78 aka: Option<&Aka>,
79 config: &FcPipelineConfig,
80 ) -> Result<Rc<Self>, SimError> {
81 let entity = Rc::new(Entity::new(parent, name));
82
83 let credit_limiter_aka = build_aka!(aka, &entity, &[("rx", "rx")]);
84 let credit_limiter = CreditLimiter::new_and_register(
85 engine,
86 clock,
87 &entity,
88 "credit_limiter",
89 Some(&credit_limiter_aka),
90 config.buffer_size,
91 );
92
93 let data_delay =
94 Delay::new_and_register(engine, clock, &entity, "pipe", config.data_delay_ticks);
95 data_delay.set_error_on_output_stall();
98
99 let buffer =
100 ObjectStore::new_and_register(engine, clock, &entity, "buf", config.buffer_size)?;
101
102 connect_port!(credit_limiter, tx => data_delay, rx)
103 .expect("Internal ports should connect without error");
104 connect_port!(data_delay, tx => buffer, rx)
105 .expect("Internal ports should connect without error");
106
107 let credit_issuer_aka = build_aka!(aka, &entity, &[("tx", "tx")]);
108 let credit_issuer = CreditIssuer::new_and_register_with_renames(
109 engine,
110 clock,
111 &entity,
112 "credit_issuer",
113 Some(&credit_issuer_aka),
114 );
115 let credit_delay = Delay::new_and_register(
116 engine,
117 clock,
118 &entity,
119 "credit_pipe",
120 config.credit_delay_ticks,
121 );
122 credit_delay.set_error_on_output_stall();
125
126 connect_port!(buffer, tx => credit_issuer, rx)
127 .expect("Internal ports should connect without error");
128 connect_port!(credit_issuer, credit_tx => credit_delay, rx)
129 .expect("Internal ports should connect without error");
130 connect_port!(credit_delay, tx => credit_limiter, credit_rx)
131 .expect("Internal ports should connect without error");
132
133 let rc_self = Rc::new(Self {
134 entity,
135 credit_limiter: RefCell::new(Some(credit_limiter)),
136 credit_delay: RefCell::new(Some(credit_delay)),
137 credit_issuer: RefCell::new(Some(credit_issuer)),
138 data_delay: RefCell::new(Some(data_delay)),
139 });
140 engine.register(rc_self.clone());
141 Ok(rc_self)
142 }
143
144 pub fn new_and_register(
145 engine: &Engine,
146 clock: &Clock,
147 parent: &Rc<Entity>,
148 name: &str,
149 config: &FcPipelineConfig,
150 ) -> Result<Rc<Self>, SimError> {
151 Self::new_and_register_with_renames(engine, clock, parent, name, None, config)
152 }
153
154 pub fn set_data_delay(&self, delay: usize) -> SimResult {
155 self.data_delay.borrow().as_ref().unwrap().set_delay(delay)
156 }
157
158 pub fn set_credit_delay(&self, delay: usize) -> SimResult {
159 self.credit_delay
160 .borrow()
161 .as_ref()
162 .unwrap()
163 .set_delay(delay)
164 }
165
166 pub fn connect_port_tx(&self, port_state: PortStateResult<T>) -> SimResult {
167 connect_tx!(self.credit_issuer, connect_port_tx ; port_state)
168 }
169
170 pub fn port_rx(&self) -> PortStateResult<T> {
171 port_rx!(self.credit_limiter, port_rx)
172 }
173}