1use qcode::{
30 context::Context,
31 space::{MemorySpaceId, Space, SpaceId, SpaceType},
32};
33use qcode_emulator::EmulatorErrorKind;
34use rustc_hash::FxHashMap;
35
36const MAX_FLAT_SPACE: usize = 1 << 24;
42
43#[derive(Debug, Default, Clone)]
45pub struct FlatSpace {
46 bytes: Vec<u8>,
47 written: Vec<bool>,
51 zero_filled: bool,
57}
58
59impl FlatSpace {
60 fn new(zero_filled: bool) -> Self {
61 Self {
62 bytes: Vec::new(),
63 written: Vec::new(),
64 zero_filled,
65 }
66 }
67
68 fn reserve_to(&mut self, end: usize) -> Result<(), EmulatorErrorKind> {
70 if end > MAX_FLAT_SPACE {
71 return Err(EmulatorErrorKind::AddressOverflow(end as u64, 0));
72 }
73 if self.bytes.len() < end {
74 self.bytes.resize(end, 0);
75 if !self.zero_filled {
79 self.written.resize(end, false);
80 }
81 }
82 Ok(())
83 }
84
85 fn range(addr: u64, size: usize) -> Option<(usize, usize)> {
87 let start = usize::try_from(addr).ok()?;
88 let end = start.checked_add(size)?;
89 (end <= MAX_FLAT_SPACE).then_some((start, end))
90 }
91
92 pub fn base_ptr(&mut self, len: usize) -> Result<*mut u8, EmulatorErrorKind> {
100 self.reserve_to(len)?;
101 Ok(self.bytes.as_mut_ptr())
102 }
103
104 pub fn read_bytes(&self, addr: u64, size: usize) -> Result<Vec<u8>, EmulatorErrorKind> {
105 let Some((start, end)) = Self::range(addr, size) else {
106 return Err(EmulatorErrorKind::AddressOverflow(addr, size));
107 };
108 if end > self.bytes.len() {
111 if !self.zero_filled {
112 return Err(EmulatorErrorKind::MemoryReadError(
113 self.bytes.len().max(start) as u64,
114 ));
115 }
116 let mut out = vec![0; size];
117 let available = self.bytes.len().saturating_sub(start);
118 if available > 0 {
119 out[..available].copy_from_slice(&self.bytes[start..self.bytes.len()]);
120 }
121 return Ok(out);
122 }
123 if !self.zero_filled
124 && let Some(offset) = self.written[start..end].iter().position(|written| !written)
125 {
126 return Err(EmulatorErrorKind::MemoryReadError((start + offset) as u64));
127 }
128 Ok(self.bytes[start..end].to_vec())
129 }
130
131 pub fn read_u128(&self, addr: u64, size: usize) -> Result<u128, EmulatorErrorKind> {
134 let width = size.min(16);
135 let Some((start, end)) = Self::range(addr, width) else {
136 return Err(EmulatorErrorKind::AddressOverflow(addr, width));
137 };
138 if end > self.bytes.len()
139 || (!self.zero_filled && self.written[start..end].contains(&false))
140 {
141 let bytes = self.read_bytes(addr, width)?;
143 let mut bits = 0u128;
144 for (index, byte) in bytes.iter().enumerate() {
145 bits |= u128::from(*byte) << (index * 8);
146 }
147 return Ok(bits);
148 }
149 let mut bits = 0u128;
150 for (index, byte) in self.bytes[start..end].iter().enumerate() {
151 bits |= u128::from(*byte) << (index * 8);
152 }
153 Ok(bits)
154 }
155
156 pub fn write_bytes(&mut self, addr: u64, bytes: &[u8]) -> Result<(), EmulatorErrorKind> {
157 let Some((start, end)) = Self::range(addr, bytes.len()) else {
158 return Err(EmulatorErrorKind::AddressOverflow(addr, bytes.len()));
159 };
160 self.reserve_to(end)?;
161 self.bytes[start..end].copy_from_slice(bytes);
162 if !self.zero_filled {
163 self.written[start..end].fill(true);
164 }
165 Ok(())
166 }
167
168 pub fn write_u128(
170 &mut self,
171 addr: u64,
172 size: usize,
173 bits: u128,
174 ) -> Result<(), EmulatorErrorKind> {
175 let width = size.min(16);
176 let Some((start, end)) = Self::range(addr, width) else {
177 return Err(EmulatorErrorKind::AddressOverflow(addr, width));
178 };
179 self.reserve_to(end)?;
180 for index in 0..width {
181 self.bytes[start + index] = (bits >> (index * 8)) as u8;
182 }
183 if !self.zero_filled {
184 self.written[start..end].fill(true);
185 }
186 Ok(())
187 }
188}
189
190#[derive(Debug, Default, Clone)]
192pub struct FlatSpaces {
193 spaces: Vec<FlatSpace>,
201 slots: FxHashMap<MemorySpaceId, usize>,
203 zero_filled: FxHashMap<SpaceId, bool>,
206 configured_space_count: Option<usize>,
207}
208
209impl FlatSpaces {
210 pub fn configure(&mut self, ctx: &Context<'_>) {
213 let count = ctx.space_count();
214 if self.configured_space_count == Some(count) {
215 return;
216 }
217 self.zero_filled.clear();
218 for index in 0..count {
219 let id = SpaceId::from(index);
220 let space = Space::from_id(ctx, id);
221 let zero =
224 matches!(space.ty, SpaceType::Register) || space.name.as_deref() == Some("x87");
225 self.zero_filled.insert(id, zero);
226 }
227 self.configured_space_count = Some(count);
228 }
229
230 pub fn slot(&mut self, space: MemorySpaceId) -> usize {
235 if let Some(&slot) = self.slots.get(&space) {
236 return slot;
237 }
238 let zero_filled = self.is_zero_filled(space);
239 self.spaces.push(FlatSpace::new(zero_filled));
240 let slot = self.spaces.len() - 1;
241 self.slots.insert(space, slot);
242 slot
243 }
244
245 pub fn base_ptr_at(&mut self, slot: usize, len: usize) -> Result<*mut u8, EmulatorErrorKind> {
249 self.spaces[slot].base_ptr(len)
250 }
251
252 fn is_zero_filled(&self, space: MemorySpaceId) -> bool {
253 match space {
254 MemorySpaceId::Temp(_) => true,
256 MemorySpaceId::Shared(id) => self.zero_filled.get(&id).copied().unwrap_or(false),
257 }
258 }
259
260 pub fn base_ptr(
262 &mut self,
263 space: MemorySpaceId,
264 len: usize,
265 ) -> Result<*mut u8, EmulatorErrorKind> {
266 self.entry(space).base_ptr(len)
267 }
268
269 pub fn get(&self, space: MemorySpaceId) -> Option<&FlatSpace> {
270 self.slots.get(&space).map(|&slot| &self.spaces[slot])
271 }
272
273 pub fn entry(&mut self, space: MemorySpaceId) -> &mut FlatSpace {
275 let slot = self.slot(space);
276 &mut self.spaces[slot]
277 }
278
279 pub fn read_u128(
280 &self,
281 space: MemorySpaceId,
282 addr: u64,
283 size: usize,
284 ) -> Result<u128, EmulatorErrorKind> {
285 match self.get(space) {
286 Some(flat) => flat.read_u128(addr, size),
287 None if self.is_zero_filled(space) => Ok(0),
288 None => Err(EmulatorErrorKind::UnknownSpace(space)),
289 }
290 }
291
292 pub fn read_bytes(
293 &self,
294 space: MemorySpaceId,
295 addr: u64,
296 size: usize,
297 ) -> Result<Vec<u8>, EmulatorErrorKind> {
298 match self.get(space) {
299 Some(flat) => flat.read_bytes(addr, size),
300 None if self.is_zero_filled(space) => Ok(vec![0; size]),
301 None => Err(EmulatorErrorKind::UnknownSpace(space)),
302 }
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use super::*;
309
310 #[test]
311 fn round_trips_a_little_endian_value() {
312 let mut flat = FlatSpace::new(true);
313 flat.write_u128(8, 4, 0xdead_beef).unwrap();
314 assert_eq!(flat.read_u128(8, 4).unwrap(), 0xdead_beef);
315 assert_eq!(flat.read_bytes(8, 4).unwrap(), vec![0xef, 0xbe, 0xad, 0xde]);
316 }
317
318 #[test]
319 fn a_zero_filled_space_reads_unwritten_bytes_as_zero() {
320 let flat = FlatSpace::new(true);
321 assert_eq!(flat.read_u128(0, 8).unwrap(), 0);
322 assert_eq!(flat.read_bytes(0, 4).unwrap(), vec![0; 4]);
323 }
324
325 #[test]
326 fn a_scratch_space_reports_an_unwritten_read() {
327 let mut flat = FlatSpace::new(false);
330 flat.write_bytes(0, &[1, 2]).unwrap();
331 assert!(flat.read_bytes(0, 2).is_ok());
332 assert!(matches!(
333 flat.read_bytes(0, 4),
334 Err(EmulatorErrorKind::MemoryReadError(2))
335 ));
336 }
337
338 #[test]
339 fn a_partially_written_scratch_read_names_the_missing_byte() {
340 let mut flat = FlatSpace::new(false);
341 flat.write_bytes(0, &[0; 8]).unwrap();
342 let mut flat2 = FlatSpace::new(false);
343 flat2.write_bytes(4, &[1, 2, 3, 4]).unwrap();
344 assert!(matches!(
346 flat2.read_bytes(0, 8),
347 Err(EmulatorErrorKind::MemoryReadError(0))
348 ));
349 assert!(flat.read_bytes(0, 8).is_ok());
350 }
351
352 #[test]
353 fn writes_grow_the_space_and_preserve_neighbours() {
354 let mut flat = FlatSpace::new(true);
355 flat.write_bytes(0, &[9; 4]).unwrap();
356 flat.write_bytes(64, &[7; 4]).unwrap();
357 assert_eq!(flat.read_bytes(0, 4).unwrap(), vec![9; 4]);
358 assert_eq!(flat.read_bytes(64, 4).unwrap(), vec![7; 4]);
359 assert_eq!(flat.read_bytes(32, 4).unwrap(), vec![0; 4]);
360 }
361
362 #[test]
363 fn an_absurd_address_is_refused_rather_than_allocated() {
364 let mut flat = FlatSpace::new(true);
365 assert!(matches!(
366 flat.write_bytes(u64::MAX - 8, &[1; 4]),
367 Err(EmulatorErrorKind::AddressOverflow(..))
368 ));
369 }
370
371 #[test]
372 fn a_wide_value_is_truncated_to_the_domain_width() {
373 let mut flat = FlatSpace::new(true);
374 flat.write_u128(0, 32, u128::MAX).unwrap();
375 assert_eq!(flat.read_u128(0, 16).unwrap(), u128::MAX);
377 assert_eq!(flat.read_bytes(16, 4).unwrap(), vec![0; 4]);
378 }
379}