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 [
231 zero,
232 one,
233 of,
234 pc,
235 ssp,
236 sp,
237 fp,
238 hp,
239 err,
240 ggas,
241 cgas,
242 bal,
243 is,
244 ret,
245 retl,
246 flag,
247 rest @ ..,
248 ] = registers;
249 let r = SystemRegisters {
250 zero: RegMut(zero),
251 one: RegMut(one),
252 of: RegMut(of),
253 pc: RegMut(pc),
254 ssp: RegMut(ssp),
255 sp: RegMut(sp),
256 fp: RegMut(fp),
257 hp: RegMut(hp),
258 err: RegMut(err),
259 ggas: RegMut(ggas),
260 cgas: RegMut(cgas),
261 bal: RegMut(bal),
262 is: RegMut(is),
263 ret: RegMut(ret),
264 retl: RegMut(retl),
265 flag: RegMut(flag),
266 };
267 (r, ProgramRegisters(rest))
268}
269
270pub(crate) fn copy_registers(
272 system_registers: &SystemRegistersRef<'_>,
273 program_registers: &ProgramRegistersRef<'_>,
274) -> [Word; VM_REGISTER_COUNT] {
275 let mut out = [0u64; VM_REGISTER_COUNT];
276 out[..VM_REGISTER_SYSTEM_COUNT]
277 .copy_from_slice(&<[Word; VM_REGISTER_SYSTEM_COUNT]>::from(system_registers));
278 out[VM_REGISTER_SYSTEM_COUNT..].copy_from_slice(program_registers.0);
279 out
280}
281
282impl ProgramRegisters<'_> {
283 pub fn get_mut_two(
286 &mut self,
287 a: WriteRegKey,
288 b: WriteRegKey,
289 ) -> Option<(&mut Word, &mut Word)> {
290 if a == b {
291 return None
293 }
294
295 let swap = a > b;
297 let (a, b) = if swap { (b, a) } else { (a, b) };
298
299 let a = a.translate();
301
302 let b = b
304 .translate()
305 .checked_sub(a.saturating_add(1))
306 .expect("Cannot underflow as the values are ordered");
307
308 let [i, rest @ ..] = &mut self.0[a..] else {
310 return None
311 };
312
313 let j = &mut rest[b];
316
317 Some(if swap { (j, i) } else { (i, j) })
318 }
319}
320
321impl<'a> From<&'a SystemRegisters<'_>> for SystemRegistersRef<'a> {
322 fn from(value: &'a SystemRegisters<'_>) -> Self {
323 Self {
324 zero: Reg(value.zero.0),
325 one: Reg(value.one.0),
326 of: Reg(value.of.0),
327 pc: Reg(value.pc.0),
328 ssp: Reg(value.ssp.0),
329 sp: Reg(value.sp.0),
330 fp: Reg(value.fp.0),
331 hp: Reg(value.hp.0),
332 err: Reg(value.err.0),
333 ggas: Reg(value.ggas.0),
334 cgas: Reg(value.cgas.0),
335 bal: Reg(value.bal.0),
336 is: Reg(value.is.0),
337 ret: Reg(value.ret.0),
338 retl: Reg(value.retl.0),
339 flag: Reg(value.flag.0),
340 }
341 }
342}
343
344impl<'a> From<SystemRegisters<'a>> for SystemRegistersRef<'a> {
345 fn from(value: SystemRegisters<'a>) -> Self {
346 Self {
347 zero: Reg(value.zero.0),
348 one: Reg(value.one.0),
349 of: Reg(value.of.0),
350 pc: Reg(value.pc.0),
351 ssp: Reg(value.ssp.0),
352 sp: Reg(value.sp.0),
353 fp: Reg(value.fp.0),
354 hp: Reg(value.hp.0),
355 err: Reg(value.err.0),
356 ggas: Reg(value.ggas.0),
357 cgas: Reg(value.cgas.0),
358 bal: Reg(value.bal.0),
359 is: Reg(value.is.0),
360 ret: Reg(value.ret.0),
361 retl: Reg(value.retl.0),
362 flag: Reg(value.flag.0),
363 }
364 }
365}
366
367impl<'a> From<&'a ProgramRegisters<'_>> for ProgramRegistersRef<'a> {
368 fn from(value: &'a ProgramRegisters<'_>) -> Self {
369 Self(value.0)
370 }
371}
372
373impl<'a> From<ProgramRegisters<'a>> for ProgramRegistersRef<'a> {
374 fn from(value: ProgramRegisters<'a>) -> Self {
375 Self(value.0)
376 }
377}
378
379impl TryFrom<RegId> for WriteRegKey {
380 type Error = PanicReason;
381
382 fn try_from(r: RegId) -> Result<Self, Self::Error> {
383 Self::new(r)
384 }
385}
386
387impl core::ops::Index<WriteRegKey> for ProgramRegisters<'_> {
388 type Output = Word;
389
390 fn index(&self, index: WriteRegKey) -> &Self::Output {
391 &self.0[index.translate()]
392 }
393}
394
395impl core::ops::IndexMut<WriteRegKey> for ProgramRegisters<'_> {
396 fn index_mut(&mut self, index: WriteRegKey) -> &mut Self::Output {
397 &mut self.0[index.translate()]
398 }
399}
400
401impl<'a> From<&SystemRegistersRef<'a>> for [Word; VM_REGISTER_SYSTEM_COUNT] {
402 fn from(value: &SystemRegistersRef<'a>) -> Self {
403 let SystemRegistersRef {
404 zero,
405 one,
406 of,
407 pc,
408 ssp,
409 sp,
410 fp,
411 hp,
412 err,
413 ggas,
414 cgas,
415 bal,
416 is,
417 ret,
418 retl,
419 flag,
420 } = value;
421 [
422 *zero.0, *one.0, *of.0, *pc.0, *ssp.0, *sp.0, *fp.0, *hp.0, *err.0, *ggas.0,
423 *cgas.0, *bal.0, *is.0, *ret.0, *retl.0, *flag.0,
424 ]
425 }
426}
427
428#[derive(Debug, Clone, Copy)]
429pub(crate) enum ProgramRegistersSegment {
430 Low,
432 High,
434}
435
436impl ProgramRegisters<'_> {
437 pub(crate) fn segment(&self, segment: ProgramRegistersSegment) -> &[Word] {
439 match segment {
440 ProgramRegistersSegment::Low => &self.0[..24],
441 ProgramRegistersSegment::High => &self.0[24..],
442 }
443 }
444
445 pub(crate) fn segment_mut(
447 &mut self,
448 segment: ProgramRegistersSegment,
449 ) -> &mut [Word] {
450 match segment {
451 ProgramRegistersSegment::Low => &mut self.0[..24],
452 ProgramRegistersSegment::High => &mut self.0[24..],
453 }
454 }
455}