Skip to main content

gwr_models/
ethernet_link.rs

1// Copyright (c) 2023 Graphcore Ltd. All rights reserved.
2
3//! Bi-directional link with two ends (a & b).
4//!
5//! Models the bi-directional pipelined connection provided by an ethernet link.
6//!
7//! # Ports
8//!
9//! This component has four ports:
10//!  - Two [input ports](gwr_engine::port::InPort): `rx_a`, `rx_b`,
11//!  - Two [output ports](gwr_engine::port::OutPort): `tx_a`, `tx_b`,
12
13use std::rc::Rc;
14
15use async_trait::async_trait;
16use gwr_components::delay::Delay;
17use gwr_components::flow_controls::limiter::Limiter;
18use gwr_components::{connect_port, rc_limiter};
19use gwr_engine::engine::Engine;
20use gwr_engine::port::PortStateResult;
21use gwr_engine::time::clock::Clock;
22use gwr_engine::traits::SimObject;
23use gwr_engine::types::{SimError, SimResult};
24use gwr_model_builder::{EntityDisplay, EntityGet, Runnable};
25use gwr_track::build_aka;
26use gwr_track::entity::Entity;
27use gwr_track::tracker::aka::Aka;
28
29// Default values for an Ethernet Link
30pub const DELAY_TICKS: usize = 500;
31pub const BITS_PER_TICK: usize = 100;
32
33#[derive(EntityGet, EntityDisplay, Runnable)]
34pub struct EthernetLink<T>
35where
36    T: SimObject,
37{
38    entity: Rc<Entity>,
39    limiter_a: Rc<Limiter<T>>,
40    delay_a: Rc<Delay<T>>,
41    limiter_b: Rc<Limiter<T>>,
42    delay_b: Rc<Delay<T>>,
43}
44
45impl<T> EthernetLink<T>
46where
47    T: SimObject,
48{
49    pub fn new_and_register_with_renames(
50        engine: &Engine,
51        clock: &Clock,
52        parent: &Rc<Entity>,
53        name: &str,
54        aka: Option<&Aka>,
55    ) -> Result<Rc<Self>, SimError> {
56        let entity = Rc::new(Entity::new(parent, name));
57        let limiter = rc_limiter!(clock, BITS_PER_TICK);
58        let limiter_a_aka = build_aka!(aka, &entity, &[("rx_a", "rx")]);
59        let limiter_a = Limiter::new_and_register_with_renames(
60            engine,
61            clock,
62            &entity,
63            "limit_a",
64            Some(&limiter_a_aka),
65            limiter.clone(),
66        );
67        let delay_a_aka = build_aka!(aka, &entity, &[("tx_a", "tx")]);
68        let delay_a = Delay::new_and_register_with_renames(
69            engine,
70            clock,
71            &entity,
72            "a",
73            Some(&delay_a_aka),
74            DELAY_TICKS,
75        );
76        connect_port!(limiter_a, tx => delay_a, rx)
77            .expect("Internal ports should connect without error");
78
79        let limiter_b_aka = build_aka!(aka, &entity, &[("rx_b", "rx")]);
80        let limiter_b: Rc<Limiter<_>> = Limiter::new_and_register_with_renames(
81            engine,
82            clock,
83            &entity,
84            "limit_b",
85            Some(&limiter_b_aka),
86            limiter.clone(),
87        );
88        let delay_b_aka = build_aka!(aka, &entity, &[("tx_b", "tx")]);
89        let delay_b = Delay::new_and_register_with_renames(
90            engine,
91            clock,
92            &entity,
93            "b",
94            Some(&delay_b_aka),
95            DELAY_TICKS,
96        );
97        connect_port!(limiter_b, tx => delay_b, rx)
98            .expect("Internal ports should connect without error");
99
100        let rc_self = Rc::new(Self {
101            entity: entity.clone(),
102            limiter_a,
103            delay_a,
104            limiter_b,
105            delay_b,
106        });
107        engine.register(rc_self.clone());
108        Ok(rc_self)
109    }
110
111    pub fn new_and_register(
112        engine: &Engine,
113        clock: &Clock,
114        parent: &Rc<Entity>,
115        name: &str,
116    ) -> Result<Rc<Self>, SimError> {
117        Self::new_and_register_with_renames(engine, clock, parent, name, None)
118    }
119
120    /// Change the delay value. Can only be done before the simulation has
121    /// started.
122    pub fn set_delay(&self, delay: usize) -> SimResult {
123        self.delay_a.set_delay(delay)?;
124        self.delay_b.set_delay(delay)
125    }
126
127    pub fn connect_port_tx_a(&self, port_state: PortStateResult<T>) -> SimResult {
128        self.delay_a.connect_port_tx(port_state)
129    }
130
131    pub fn connect_port_tx_b(&self, port_state: PortStateResult<T>) -> SimResult {
132        self.delay_b.connect_port_tx(port_state)
133    }
134
135    pub fn port_rx_a(&self) -> PortStateResult<T> {
136        self.limiter_a.port_rx()
137    }
138
139    pub fn port_rx_b(&self) -> PortStateResult<T> {
140        self.limiter_b.port_rx()
141    }
142}