Skip to main content

gwr_models/memory/
memory_access.rs

1// Copyright (c) 2025 Graphcore Ltd. All rights reserved.
2
3use std::fmt::Display;
4use std::rc::Rc;
5
6use gwr_engine::sim_error;
7use gwr_engine::traits::{Routable, SimObject, TotalBytes};
8use gwr_engine::types::{AccessType, SimError};
9use gwr_track::entity::Entity;
10use gwr_track::id::Unique;
11use gwr_track::{Id, create_id, track_create_object};
12
13use crate::memory::CacheHintType;
14use crate::memory::memory_map::DeviceId;
15use crate::memory::traits::{AccessMemory, ReadMemory};
16
17#[derive(Clone, Debug)]
18pub struct MemoryAccess {
19    created_by: Rc<Entity>,
20    id: Id,
21    access_type: AccessType,
22    access_size_bytes: usize,
23    dst_addr: u64,
24    src_addr: u64,
25    dst_device: DeviceId,
26    src_device: DeviceId,
27    cache_hint: CacheHintType,
28
29    /// Non-data overhead. Control/Read accesses don't contain any data.
30    overhead_size_bytes: usize,
31}
32
33impl Display for MemoryAccess {
34    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
35        write!(
36            f,
37            "{}: {}@{:x}",
38            self.access_type, self.access_size_bytes, self.dst_addr
39        )
40    }
41}
42
43impl TotalBytes for MemoryAccess {
44    fn total_bytes(&self) -> usize {
45        match self.access_type {
46            AccessType::Control | AccessType::ReadRequest | AccessType::WriteNonPostedResponse => {
47                self.overhead_size_bytes
48            }
49            AccessType::WriteRequest
50            | AccessType::WriteNonPostedRequest
51            | AccessType::ReadResponse => self.access_size_bytes + self.overhead_size_bytes,
52        }
53    }
54}
55
56impl Unique for MemoryAccess {
57    fn id(&self) -> Id {
58        self.id
59    }
60}
61
62impl AccessMemory for MemoryAccess {
63    fn dst_addr(&self) -> u64 {
64        self.dst_addr
65    }
66
67    fn src_addr(&self) -> u64 {
68        self.src_addr
69    }
70
71    fn dst_device(&self) -> DeviceId {
72        self.dst_device
73    }
74
75    fn src_device(&self) -> DeviceId {
76        self.src_device
77    }
78
79    fn cache_hint(&self) -> CacheHintType {
80        CacheHintType::Allocate
81    }
82
83    fn access_size_bytes(&self) -> usize {
84        self.access_size_bytes
85    }
86
87    fn to_response(&self, _mem: &impl ReadMemory) -> Result<Self, SimError> {
88        let response_type = match self.access_type {
89            AccessType::Control => AccessType::Control,
90            AccessType::ReadRequest => AccessType::ReadResponse,
91            AccessType::WriteNonPostedRequest => AccessType::WriteNonPostedResponse,
92            AccessType::ReadResponse
93            | AccessType::WriteNonPostedResponse
94            | AccessType::WriteRequest => {
95                return sim_error!("{}: unsupported by to_response()", self.access_type);
96            }
97        };
98        Ok(MemoryAccess {
99            created_by: self.created_by.clone(),
100            id: self.id,
101            access_type: response_type,
102            access_size_bytes: self.access_size_bytes,
103            dst_addr: self.dst_addr,
104            src_addr: self.src_addr,
105            dst_device: self.src_device,
106            src_device: self.dst_device,
107            cache_hint: self.cache_hint,
108            overhead_size_bytes: self.overhead_size_bytes,
109        })
110    }
111}
112
113impl Routable for MemoryAccess {
114    fn destination(&self) -> u64 {
115        // The device ID is used for routing
116        self.dst_device.0
117    }
118    fn access_type(&self) -> AccessType {
119        self.access_type
120    }
121}
122
123impl MemoryAccess {
124    #[must_use]
125    #[expect(clippy::too_many_arguments)]
126    pub fn new(
127        created_by: &Rc<Entity>,
128        access_type: AccessType,
129        access_size_bytes: usize,
130        dst_addr: u64,
131        src_addr: u64,
132        dst_device: DeviceId,
133        src_device: DeviceId,
134        overhead_size_bytes: usize,
135    ) -> Self {
136        let access = Self {
137            created_by: created_by.clone(),
138            id: create_id!(created_by),
139            access_size_bytes,
140            access_type,
141            dst_addr,
142            src_addr,
143            dst_device,
144            src_device,
145            cache_hint: CacheHintType::Allocate,
146            overhead_size_bytes,
147        };
148        track_create_object!(
149            created_by;
150            access.id,
151            access.total_bytes(),
152            "bytes",
153            access.access_type() as u8,
154            "MemoryAccess: {access}"
155        );
156        access
157    }
158}
159
160impl SimObject for MemoryAccess {}