1use core::ops::{
6 Deref,
7 DerefMut,
8};
9
10use fuel_asm::{
11 PanicReason,
12 RegId,
13 Word,
14};
15
16use crate::consts::{
17 VM_REGISTER_COUNT,
18 VM_REGISTER_PROGRAM_COUNT,
19 VM_REGISTER_SYSTEM_COUNT,
20};
21
22#[cfg(test)]
23mod tests;
24
25#[derive(Debug, PartialEq, Eq)]
26pub struct RegMut<'r, const INDEX: u8>(&'r mut Word);
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub struct Reg<'r, const INDEX: u8>(&'r Word);
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
34pub struct WriteRegKey(RegId);
37
38impl WriteRegKey {
39 pub fn new(k: impl Into<RegId>) -> Result<Self, PanicReason> {
42 let k = k.into();
43
44 if k >= RegId::WRITABLE {
45 Ok(Self(k))
46 } else {
47 Err(PanicReason::ReservedRegisterNotWritable)
48 }
49 }
50
51 #[allow(clippy::arithmetic_side_effects)] fn translate(self) -> usize {
57 self.0.to_u8() as usize - VM_REGISTER_SYSTEM_COUNT
58 }
59}
60
61impl<'r, const INDEX: u8> RegMut<'r, INDEX> {
62 pub fn new(reg: &'r mut Word) -> Self {
64 Self(reg)
65 }
66}
67
68impl<'r, const INDEX: u8> Reg<'r, INDEX> {
69 pub fn new(reg: &'r Word) -> Self {
71 Self(reg)
72 }
73}
74
75impl<const INDEX: u8> Deref for Reg<'_, INDEX> {
76 type Target = Word;
77
78 fn deref(&self) -> &Self::Target {
79 self.0
80 }
81}
82
83impl<const INDEX: u8> Deref for RegMut<'_, INDEX> {
84 type Target = Word;
85
86 fn deref(&self) -> &Self::Target {
87 self.0
88 }
89}
90
91impl<const INDEX: u8> DerefMut for RegMut<'_, INDEX> {
92 fn deref_mut(&mut self) -> &mut Self::Target {
93 self.0
94 }
95}
96
97impl<'a, const INDEX: u8> From<RegMut<'a, INDEX>> for Reg<'a, INDEX> {
98 fn from(reg: RegMut<'a, INDEX>) -> Self {
99 Self(reg.0)
100 }
101}
102
103impl<const INDEX: u8> RegMut<'_, INDEX> {
104 pub fn as_ref(&self) -> Reg<INDEX> {
106 Reg(self.0)
107 }
108}
109
110impl<const INDEX: u8> RegMut<'_, INDEX> {
111 pub fn as_mut(&mut self) -> RegMut<INDEX> {
113 RegMut(self.0)
114 }
115}
116
117macro_rules! impl_keys {
118 ( $($i:ident, $f:ident $(,$f_mut:ident)?)* ) => {
119 $(
120 #[doc = "Register index key for use with Reg and RegMut."]
121 pub const $i: u8 = RegId::$i.to_u8();
122 )*
123 #[doc = "Get register reference by name."]
124 pub trait GetReg {
125 $(
126 #[doc = "Get register reference for this key."]
127 fn $f(&self) -> Reg<'_, $i>;
128 )*
129 }
130 #[doc = "Get register mutable reference by name."]
131 pub trait GetRegMut {
132 $(
133 $(
134 #[doc = "Get mutable register reference for this key."]
135 fn $f_mut(&mut self) -> RegMut<'_, $i>;
136 )?
137 )*
138 }
139 impl GetReg for [Word; VM_REGISTER_COUNT] {
140 $(
141 fn $f(&self) -> Reg<'_, $i> {
142 Reg(&self[$i as usize])
143 }
144 )*
145 }
146 impl GetRegMut for [Word; VM_REGISTER_COUNT] {
147 $(
148 $(
149 fn $f_mut(&mut self) -> RegMut<'_, $i> {
150 RegMut(&mut self[$i as usize])
151 }
152 )?
153 )*
154 }
155 };
156}
157
158impl_keys! {
159 ZERO, zero
160 ONE, one
161 OF, of, of_mut
162 PC, pc, pc_mut
163 SSP, ssp, ssp_mut
164 SP, sp, sp_mut
165 FP, fp, fp_mut
166 HP, hp, hp_mut
167 ERR, err, err_mut
168 GGAS, ggas, ggas_mut
169 CGAS, cgas, cgas_mut
170 BAL, bal, bal_mut
171 IS, is, is_mut
172 RET, ret, ret_mut
173 RETL, retl, retl_mut
174 FLAG, flag, flag_mut
175}
176
177pub(crate) struct SystemRegisters<'a> {
180 pub(crate) zero: RegMut<'a, ZERO>,
181 pub(crate) one: RegMut<'a, ONE>,
182 pub(crate) of: RegMut<'a, OF>,
183 pub(crate) pc: RegMut<'a, PC>,
184 pub(crate) ssp: RegMut<'a, SSP>,
185 pub(crate) sp: RegMut<'a, SP>,
186 pub(crate) fp: RegMut<'a, FP>,
187 pub(crate) hp: RegMut<'a, HP>,
188 pub(crate) err: RegMut<'a, ERR>,
189 pub(crate) ggas: RegMut<'a, GGAS>,
190 pub(crate) cgas: RegMut<'a, CGAS>,
191 pub(crate) bal: RegMut<'a, BAL>,
192 pub(crate) is: RegMut<'a, IS>,
193 pub(crate) ret: RegMut<'a, RET>,
194 pub(crate) retl: RegMut<'a, RETL>,
195 pub(crate) flag: RegMut<'a, FLAG>,
196}
197
198pub(crate) struct SystemRegistersRef<'a> {
200 pub(crate) zero: Reg<'a, ZERO>,
201 pub(crate) one: Reg<'a, ONE>,
202 pub(crate) of: Reg<'a, OF>,
203 pub(crate) pc: Reg<'a, PC>,
204 pub(crate) ssp: Reg<'a, SSP>,
205 pub(crate) sp: Reg<'a, SP>,
206 pub(crate) fp: Reg<'a, FP>,
207 pub(crate) hp: Reg<'a, HP>,
208 pub(crate) err: Reg<'a, ERR>,
209 pub(crate) ggas: Reg<'a, GGAS>,
210 pub(crate) cgas: Reg<'a, CGAS>,
211 pub(crate) bal: Reg<'a, BAL>,
212 pub(crate) is: Reg<'a, IS>,
213 pub(crate) ret: Reg<'a, RET>,
214 pub(crate) retl: Reg<'a, RETL>,
215 pub(crate) flag: Reg<'a, FLAG>,
216}
217
218pub(crate) struct ProgramRegisters<'a>(pub &'a mut [Word; VM_REGISTER_PROGRAM_COUNT]);
220
221pub(crate) struct ProgramRegistersRef<'a>(pub &'a [Word; VM_REGISTER_PROGRAM_COUNT]);
223
224pub(crate) fn split_registers(
228 registers: &mut [Word; VM_REGISTER_COUNT],
229) -> (SystemRegisters<'_>, ProgramRegisters<'_>) {
230 let [zero, one, of, pc, ssp, sp, fp, hp, err, ggas, cgas, bal, is, ret, retl, flag, rest @ ..] =
231 registers;
232 let r = SystemRegisters {
233 zero: RegMut(zero),
234 one: RegMut(one),
235 of: RegMut(of),
236 pc: RegMut(pc),
237 ssp: RegMut(ssp),
238 sp: RegMut(sp),
239 fp: RegMut(fp),
240 hp: RegMut(hp),
241 err: RegMut(err),
242 ggas: RegMut(ggas),
243 cgas: RegMut(cgas),
244 bal: RegMut(bal),
245 is: RegMut(is),
246 ret: RegMut(ret),
247 retl: RegMut(retl),
248 flag: RegMut(flag),
249 };
250 (r, ProgramRegisters(rest))
251}
252
253pub(crate) fn copy_registers(
255 system_registers: &SystemRegistersRef<'_>,
256 program_registers: &ProgramRegistersRef<'_>,
257) -> [Word; VM_REGISTER_COUNT] {
258 let mut out = [0u64; VM_REGISTER_COUNT];
259 out[..VM_REGISTER_SYSTEM_COUNT]
260 .copy_from_slice(&<[Word; VM_REGISTER_SYSTEM_COUNT]>::from(system_registers));
261 out[VM_REGISTER_SYSTEM_COUNT..].copy_from_slice(program_registers.0);
262 out
263}
264
265impl ProgramRegisters<'_> {
266 pub fn get_mut_two(
269 &mut self,
270 a: WriteRegKey,
271 b: WriteRegKey,
272 ) -> Option<(&mut Word, &mut Word)> {
273 if a == b {
274 return None
276 }
277
278 let swap = a > b;
280 let (a, b) = if swap { (b, a) } else { (a, b) };
281
282 let a = a.translate();
284
285 let b = b
287 .translate()
288 .checked_sub(a.saturating_add(1))
289 .expect("Cannot underflow as the values are ordered");
290
291 let [i, rest @ ..] = &mut self.0[a..] else {
293 return None
294 };
295
296 let j = &mut rest[b];
299
300 Some(if swap { (j, i) } else { (i, j) })
301 }
302}
303
304impl<'a> From<&'a SystemRegisters<'_>> for SystemRegistersRef<'a> {
305 fn from(value: &'a SystemRegisters<'_>) -> Self {
306 Self {
307 zero: Reg(value.zero.0),
308 one: Reg(value.one.0),
309 of: Reg(value.of.0),
310 pc: Reg(value.pc.0),
311 ssp: Reg(value.ssp.0),
312 sp: Reg(value.sp.0),
313 fp: Reg(value.fp.0),
314 hp: Reg(value.hp.0),
315 err: Reg(value.err.0),
316 ggas: Reg(value.ggas.0),
317 cgas: Reg(value.cgas.0),
318 bal: Reg(value.bal.0),
319 is: Reg(value.is.0),
320 ret: Reg(value.ret.0),
321 retl: Reg(value.retl.0),
322 flag: Reg(value.flag.0),
323 }
324 }
325}
326
327impl<'a> From<SystemRegisters<'a>> for SystemRegistersRef<'a> {
328 fn from(value: SystemRegisters<'a>) -> Self {
329 Self {
330 zero: Reg(value.zero.0),
331 one: Reg(value.one.0),
332 of: Reg(value.of.0),
333 pc: Reg(value.pc.0),
334 ssp: Reg(value.ssp.0),
335 sp: Reg(value.sp.0),
336 fp: Reg(value.fp.0),
337 hp: Reg(value.hp.0),
338 err: Reg(value.err.0),
339 ggas: Reg(value.ggas.0),
340 cgas: Reg(value.cgas.0),
341 bal: Reg(value.bal.0),
342 is: Reg(value.is.0),
343 ret: Reg(value.ret.0),
344 retl: Reg(value.retl.0),
345 flag: Reg(value.flag.0),
346 }
347 }
348}
349
350impl<'a> From<&'a ProgramRegisters<'_>> for ProgramRegistersRef<'a> {
351 fn from(value: &'a ProgramRegisters<'_>) -> Self {
352 Self(value.0)
353 }
354}
355
356impl<'a> From<ProgramRegisters<'a>> for ProgramRegistersRef<'a> {
357 fn from(value: ProgramRegisters<'a>) -> Self {
358 Self(value.0)
359 }
360}
361
362impl TryFrom<RegId> for WriteRegKey {
363 type Error = PanicReason;
364
365 fn try_from(r: RegId) -> Result<Self, Self::Error> {
366 Self::new(r)
367 }
368}
369
370impl core::ops::Index<WriteRegKey> for ProgramRegisters<'_> {
371 type Output = Word;
372
373 fn index(&self, index: WriteRegKey) -> &Self::Output {
374 &self.0[index.translate()]
375 }
376}
377
378impl core::ops::IndexMut<WriteRegKey> for ProgramRegisters<'_> {
379 fn index_mut(&mut self, index: WriteRegKey) -> &mut Self::Output {
380 &mut self.0[index.translate()]
381 }
382}
383
384impl<'a> From<&SystemRegistersRef<'a>> for [Word; VM_REGISTER_SYSTEM_COUNT] {
385 fn from(value: &SystemRegistersRef<'a>) -> Self {
386 let SystemRegistersRef {
387 zero,
388 one,
389 of,
390 pc,
391 ssp,
392 sp,
393 fp,
394 hp,
395 err,
396 ggas,
397 cgas,
398 bal,
399 is,
400 ret,
401 retl,
402 flag,
403 } = value;
404 [
405 *zero.0, *one.0, *of.0, *pc.0, *ssp.0, *sp.0, *fp.0, *hp.0, *err.0, *ggas.0,
406 *cgas.0, *bal.0, *is.0, *ret.0, *retl.0, *flag.0,
407 ]
408 }
409}
410
411#[derive(Debug, Clone, Copy)]
412pub(crate) enum ProgramRegistersSegment {
413 Low,
415 High,
417}
418
419impl ProgramRegisters<'_> {
420 pub(crate) fn segment(&self, segment: ProgramRegistersSegment) -> &[Word] {
422 match segment {
423 ProgramRegistersSegment::Low => &self.0[..24],
424 ProgramRegistersSegment::High => &self.0[24..],
425 }
426 }
427
428 pub(crate) fn segment_mut(
430 &mut self,
431 segment: ProgramRegistersSegment,
432 ) -> &mut [Word] {
433 match segment {
434 ProgramRegistersSegment::Low => &mut self.0[..24],
435 ProgramRegistersSegment::High => &mut self.0[24..],
436 }
437 }
438}