1use super::{
6 elem_type::{AccessMode, AddressKind, CachingMode, ImmOrPNode},
7 interface::IPort,
8 ivalue::IValue,
9 node_base::NodeElementBase,
10 store::{CacheStore, NodeId, NodeStore, ValueStore},
11 Device, GenApiError, GenApiResult, ValueCtxt,
12};
13
14#[derive(Debug, Clone)]
15pub struct RegisterBase {
16 pub(crate) elem_base: NodeElementBase,
17
18 pub(crate) streamable: bool,
19 pub(crate) address_kinds: Vec<AddressKind>,
20 pub(crate) length: ImmOrPNode<i64>,
21 pub(crate) access_mode: AccessMode,
22 pub(crate) p_port: NodeId,
23 pub(crate) cacheable: CachingMode,
24 pub(crate) polling_time: Option<u64>,
25 pub(crate) p_invalidators: Vec<NodeId>,
26}
27
28impl RegisterBase {
29 #[must_use]
30 pub fn streamable(&self) -> bool {
31 self.streamable
32 }
33
34 #[must_use]
35 pub fn address_kinds(&self) -> &[AddressKind] {
36 &self.address_kinds
37 }
38
39 #[must_use]
40 pub fn length_elem(&self) -> &ImmOrPNode<i64> {
41 &self.length
42 }
43
44 #[must_use]
45 pub fn access_mode(&self) -> AccessMode {
46 self.access_mode
47 }
48
49 #[must_use]
50 pub fn p_port(&self) -> NodeId {
51 self.p_port
52 }
53
54 #[must_use]
55 pub fn cacheable(&self) -> CachingMode {
56 self.cacheable
57 }
58
59 #[must_use]
60 pub fn polling_time(&self) -> Option<u64> {
61 self.polling_time
62 }
63
64 #[must_use]
65 pub fn p_invalidators(&self) -> &[NodeId] {
66 &self.p_invalidators
67 }
68
69 pub(super) fn with_cache_or_read<T: ValueStore, U: CacheStore, R>(
70 &self,
71 nid: NodeId,
72 device: &mut impl Device,
73 store: &impl NodeStore,
74 cx: &mut ValueCtxt<T, U>,
75 f: impl FnOnce(&[u8]) -> GenApiResult<R>,
76 ) -> GenApiResult<R> {
77 let length = self.length(device, store, cx)?;
78 let address = self.address(device, store, cx)?;
79 if let Some(cache) = cx.get_cache(nid, address, length) {
80 f(cache)
81 } else {
82 let mut buf = vec![0; length as usize];
83 self.read_and_cache(nid, address, length, &mut buf, device, store, cx)?;
84 f(&buf)
85 }
86 }
87
88 #[allow(clippy::too_many_arguments)]
89 pub(super) fn read_and_cache<T: ValueStore, U: CacheStore>(
90 &self,
91 nid: NodeId,
92 address: i64,
93 length: i64,
94 buf: &mut [u8],
95 device: &mut impl Device,
96 store: &impl NodeStore,
97 cx: &mut ValueCtxt<T, U>,
98 ) -> GenApiResult<()> {
99 if buf.len() != length as usize {
100 return Err(GenApiError::invalid_buffer(
101 "given buffer length doesn't same as the register length".into(),
102 ));
103 }
104 self.p_port
105 .expect_iport_kind(store)?
106 .read(address, buf, device, store, cx)?;
107 if self.cacheable != CachingMode::NoCache {
108 cx.cache_data(nid, address, length, buf);
109 }
110
111 Ok(())
112 }
113
114 pub(super) fn write_and_cache<T: ValueStore, U: CacheStore>(
115 &self,
116 nid: NodeId,
117 buf: &[u8],
118 device: &mut impl Device,
119 store: &impl NodeStore,
120 cx: &mut ValueCtxt<T, U>,
121 ) -> GenApiResult<()> {
122 let length = self.length(device, store, cx)?;
123
124 if buf.len() != length as usize {
125 return Err(GenApiError::invalid_buffer(
126 "given buffer length doesn't same as the register length".into(),
127 ));
128 }
129
130 let address = self.address(device, store, cx)?;
131 self.p_port
132 .expect_iport_kind(store)?
133 .write(address, buf, device, store, cx)?;
134
135 if self.cacheable == CachingMode::WriteThrough {
136 cx.cache_data(nid, address, length, buf);
137 }
138 Ok(())
139 }
140
141 pub(super) fn address<T: ValueStore, U: CacheStore>(
142 &self,
143 device: &mut impl Device,
144 store: &impl NodeStore,
145 cx: &mut ValueCtxt<T, U>,
146 ) -> GenApiResult<i64> {
147 let mut address = 0;
148 for addr_kind in self.address_kinds() {
149 address += addr_kind.value(device, store, cx)?;
150 }
151 Ok(address)
152 }
153
154 pub(super) fn length<T: ValueStore, U: CacheStore>(
155 &self,
156 device: &mut impl Device,
157 store: &impl NodeStore,
158 cx: &mut ValueCtxt<T, U>,
159 ) -> GenApiResult<i64> {
160 self.length_elem().value(device, store, cx)
161 }
162
163 pub(super) fn is_readable<T: ValueStore, U: CacheStore>(
164 &self,
165 device: &mut impl Device,
166 store: &impl NodeStore,
167 cx: &mut ValueCtxt<T, U>,
168 ) -> GenApiResult<bool> {
169 Ok(self.elem_base.is_readable(device, store, cx)?
170 && !matches!(self.access_mode(), AccessMode::WO))
171 }
172
173 pub(super) fn is_writable<T: ValueStore, U: CacheStore>(
174 &self,
175 device: &mut impl Device,
176 store: &impl NodeStore,
177 cx: &mut ValueCtxt<T, U>,
178 ) -> GenApiResult<bool> {
179 Ok(self.elem_base.is_writable(device, store, cx)?
180 && !matches!(self.access_mode(), AccessMode::RO))
181 }
182}