1use core::fmt::Display;
7
8use bytes::BufMut;
9
10use crate::{
11 cast::CastSign,
12 error::AssemblerError,
13 resolver::{ResolvedAddr, Resolver},
14 LabelRef,
15};
16
17#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
23pub enum LoadOperand<L> {
24 Pop,
26 Imm(i32),
28 FrameAddr(u32),
31 ImmLabel(LabelRef<L>, u8),
41 DerefLabel(LabelRef<L>),
43 Branch(L),
54}
55
56#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
58pub enum StoreOperand<L> {
59 Push,
61 Discard,
63 FrameAddr(u32),
66 DerefLabel(LabelRef<L>),
68}
69
70#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
72pub(crate) enum RawOperand {
73 Null,
75 Imm8(i8),
77 Imm16(i16),
79 Imm32(i32),
81 Addr8(u8),
83 Addr16(u16),
85 Addr32(u32),
87 Stack,
89 Frame8(u8),
91 Frame16(u16),
93 Frame32(u32),
95 Ram8(u8),
97 Ram16(u16),
99 Ram32(u32),
101}
102
103impl<L> LoadOperand<L> {
104 pub fn map<F, M>(self, mut f: F) -> LoadOperand<M>
106 where
107 F: FnMut(L) -> M,
108 {
109 match self {
110 LoadOperand::Pop => LoadOperand::Pop,
111 LoadOperand::Imm(x) => LoadOperand::Imm(x),
112 LoadOperand::FrameAddr(p) => LoadOperand::FrameAddr(p),
113 LoadOperand::ImmLabel(l, shift) => LoadOperand::ImmLabel(l.map(f), shift),
114 LoadOperand::DerefLabel(l) => LoadOperand::DerefLabel(l.map(f)),
115 LoadOperand::Branch(l) => LoadOperand::Branch(f(l)),
116 }
117 }
118}
119
120impl<L> LoadOperand<L>
121where
122 L: Clone,
123{
124 pub(crate) fn resolve<R>(
127 &self,
128 position: u32,
129 resolver: &R,
130 ) -> Result<RawOperand, AssemblerError<L>>
131 where
132 R: Resolver<Label = L>,
133 {
134 Ok(match self {
135 LoadOperand::Pop => RawOperand::Stack,
136 LoadOperand::Imm(x) => {
137 if *x == 0 {
138 RawOperand::Null
139 } else if let Ok(x) = i8::try_from(*x) {
140 RawOperand::Imm8(x)
141 } else if let Ok(x) = i16::try_from(*x) {
142 RawOperand::Imm16(x)
143 } else {
144 RawOperand::Imm32(*x)
145 }
146 }
147 LoadOperand::FrameAddr(x) => {
148 if let Ok(x) = u8::try_from(*x) {
149 RawOperand::Frame8(x)
150 } else if let Ok(x) = u16::try_from(*x) {
151 RawOperand::Frame16(x)
152 } else {
153 RawOperand::Frame32(*x)
154 }
155 }
156 LoadOperand::ImmLabel(l, shift) => {
157 let unshifted_addr = l.resolve_absolute(resolver)?;
158 if unshifted_addr.trailing_zeros() < (*shift).into() {
159 return Err(AssemblerError::InsufficientAlignment {
160 label: l.0.clone(),
161 offset: l.1,
162 shift: *shift,
163 });
164 }
165
166 let addr = (unshifted_addr >> *shift).cast_sign();
167
168 if addr == 0 {
169 RawOperand::Null
170 } else if let Ok(x) = i8::try_from(addr) {
171 RawOperand::Imm8(x)
172 } else if let Ok(x) = i16::try_from(addr) {
173 RawOperand::Imm16(x)
174 } else {
175 RawOperand::Imm32(addr)
176 }
177 }
178 LoadOperand::DerefLabel(l) => match l.resolve(resolver)? {
179 ResolvedAddr::Rom(addr) => {
180 if let Ok(x) = u8::try_from(addr) {
181 RawOperand::Addr8(x)
182 } else if let Ok(x) = u16::try_from(addr) {
183 RawOperand::Addr16(x)
184 } else {
185 RawOperand::Addr32(addr)
186 }
187 }
188 ResolvedAddr::Ram(ramaddr) => {
189 if let Ok(x) = u8::try_from(ramaddr) {
192 RawOperand::Ram8(x)
193 } else if let Ok(x) = u16::try_from(ramaddr) {
194 RawOperand::Ram16(x)
195 } else {
196 RawOperand::Ram32(ramaddr)
197 }
198 }
199 },
200 LoadOperand::Branch(l) => {
201 let target = resolver.resolve_absolute(l)?;
202
203 let null_offset = (target.cast_sign())
212 .wrapping_sub(position.cast_sign())
213 .wrapping_add(2);
214
215 let i8_offset = null_offset.wrapping_sub(1);
216 if let Ok(x) = i8::try_from(i8_offset) {
217 if x != 0 && x != 1 {
218 return Ok(RawOperand::Imm8(x));
219 }
220 }
221
222 let i16_offset = null_offset.wrapping_sub(2);
223 if let Ok(x) = i16::try_from(i16_offset) {
224 if x != 0 && x != 1 {
225 return Ok(RawOperand::Imm16(x));
226 }
227 }
228
229 let i32_offset = null_offset.wrapping_sub(4);
230 assert!(i32_offset != 0 && i32_offset != 1);
233 return Ok(RawOperand::Imm32(i32_offset));
234 }
235 })
236 }
237
238 pub(crate) fn worst_len(&self) -> usize {
241 match self {
242 LoadOperand::Pop => 0,
243 LoadOperand::Imm(x) => {
244 if *x == 0 {
245 0
246 } else if i8::try_from(*x).is_ok() {
247 1
248 } else if i16::try_from(*x).is_ok() {
249 2
250 } else {
251 4
252 }
253 }
254 LoadOperand::FrameAddr(x) => {
255 if u8::try_from(*x).is_ok() {
256 1
257 } else if u16::try_from(*x).is_ok() {
258 2
259 } else {
260 4
261 }
262 }
263 LoadOperand::ImmLabel(_, _) => 4,
264 LoadOperand::DerefLabel(_) => 4,
265 LoadOperand::Branch(_) => 4,
266 }
267 }
268}
269
270impl<L> Display for LoadOperand<L>
271where
272 L: Display,
273{
274 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
275 match self {
276 LoadOperand::Pop => f.write_str("pop")?,
277 LoadOperand::Imm(x) => write!(f, "{x:#x}")?,
278 LoadOperand::FrameAddr(a) => {
279 write!(f, "${}", a / 4)?;
280 if a % 4 != 0 {
281 write!(f, ".{}", a % 4)?;
282 }
283 }
284 LoadOperand::ImmLabel(LabelRef(label, offset), shift) => {
285 write!(f, "({label}")?;
286 if *offset != 0 {
287 write!(f, "{offset:+#x}")?;
288 }
289 if *shift != 0 {
290 write!(f, ">>{shift}")?;
291 }
292 write!(f, ")")?;
293 }
294 LoadOperand::DerefLabel(LabelRef(label, offset)) => {
295 write!(f, "[{label}")?;
296 if *offset != 0 {
297 write!(f, "{offset:+#x}")?;
298 }
299 write!(f, "]")?;
300 }
301 LoadOperand::Branch(label) => {
302 write!(f, "~({label})")?;
303 }
304 };
305 Ok(())
306 }
307}
308
309impl<L> StoreOperand<L> {
310 pub fn map<F, M>(self, f: F) -> StoreOperand<M>
312 where
313 F: FnMut(L) -> M,
314 {
315 match self {
316 StoreOperand::Push => StoreOperand::Push,
317 StoreOperand::Discard => StoreOperand::Discard,
318 StoreOperand::FrameAddr(x) => StoreOperand::FrameAddr(x),
319 StoreOperand::DerefLabel(l) => StoreOperand::DerefLabel(l.map(f)),
320 }
321 }
322}
323
324impl<L> StoreOperand<L>
325where
326 L: Clone,
327{
328 pub(crate) fn resolve<R>(
333 &self,
334 _position: u32,
335 resolver: &R,
336 ) -> Result<RawOperand, AssemblerError<L>>
337 where
338 R: Resolver<Label = L>,
339 {
340 Ok(match self {
341 StoreOperand::Push => RawOperand::Stack,
342 StoreOperand::Discard => RawOperand::Null,
343 StoreOperand::FrameAddr(x) => {
344 if let Ok(x) = u8::try_from(*x) {
345 RawOperand::Frame8(x)
346 } else if let Ok(x) = u16::try_from(*x) {
347 RawOperand::Frame16(x)
348 } else {
349 RawOperand::Frame32(*x)
350 }
351 }
352 StoreOperand::DerefLabel(l) => match l.resolve(resolver)? {
353 ResolvedAddr::Rom(addr) => {
354 if let Ok(x) = u8::try_from(addr) {
355 RawOperand::Addr8(x)
356 } else if let Ok(x) = u16::try_from(addr) {
357 RawOperand::Addr16(x)
358 } else {
359 RawOperand::Addr32(addr)
360 }
361 }
362 ResolvedAddr::Ram(addr) => {
363 if let Ok(x) = u8::try_from(addr) {
364 RawOperand::Ram8(x)
365 } else if let Ok(x) = u16::try_from(addr) {
366 RawOperand::Ram16(x)
367 } else {
368 RawOperand::Ram32(addr)
369 }
370 }
371 },
372 })
373 }
374
375 pub(crate) fn worst_len(&self) -> usize {
378 match self {
379 StoreOperand::Push => 0,
380 StoreOperand::Discard => 0,
381 StoreOperand::FrameAddr(x) => {
382 if u8::try_from(*x).is_ok() {
383 1
384 } else if u16::try_from(*x).is_ok() {
385 2
386 } else {
387 4
388 }
389 }
390 StoreOperand::DerefLabel(_) => 4,
391 }
392 }
393}
394
395impl<L> Display for StoreOperand<L>
396where
397 L: Display,
398{
399 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
400 match self {
401 StoreOperand::Push => f.write_str("push")?,
402 StoreOperand::Discard => f.write_str("discard")?,
403 StoreOperand::FrameAddr(a) => {
404 write!(f, "${}", a / 4)?;
405 if a % 4 != 0 {
406 write!(f, ".{}", a % 4)?;
407 }
408 }
409 StoreOperand::DerefLabel(LabelRef(label, offset)) => {
410 write!(f, "[{label}")?;
411 if *offset != 0 {
412 write!(f, "{offset:+#x}")?;
413 }
414 write!(f, "]")?;
415 }
416 }
417 Ok(())
418 }
419}
420
421impl RawOperand {
422 pub(crate) fn len(&self) -> usize {
424 match self {
425 RawOperand::Null => 0,
426 RawOperand::Imm8(_) => 1,
427 RawOperand::Imm16(_) => 2,
428 RawOperand::Imm32(_) => 4,
429 RawOperand::Addr8(_) => 1,
430 RawOperand::Addr16(_) => 2,
431 RawOperand::Addr32(_) => 4,
432 RawOperand::Stack => 0,
433 RawOperand::Frame8(_) => 1,
434 RawOperand::Frame16(_) => 2,
435 RawOperand::Frame32(_) => 4,
436 RawOperand::Ram8(_) => 1,
437 RawOperand::Ram16(_) => 2,
438 RawOperand::Ram32(_) => 4,
439 }
440 }
441
442 pub(crate) fn mode(&self) -> u8 {
444 match self {
445 RawOperand::Null => 0,
446 RawOperand::Imm8(_) => 1,
447 RawOperand::Imm16(_) => 2,
448 RawOperand::Imm32(_) => 3,
449 RawOperand::Addr8(_) => 5,
450 RawOperand::Addr16(_) => 6,
451 RawOperand::Addr32(_) => 7,
452 RawOperand::Stack => 8,
453 RawOperand::Frame8(_) => 9,
454 RawOperand::Frame16(_) => 0xa,
455 RawOperand::Frame32(_) => 0xb,
456 RawOperand::Ram8(_) => 0xd,
457 RawOperand::Ram16(_) => 0xe,
458 RawOperand::Ram32(_) => 0xf,
459 }
460 }
461
462 pub(crate) fn serialize<B: BufMut>(&self, mut buf: B) {
464 match self {
465 RawOperand::Null => {}
466 RawOperand::Imm8(x) => buf.put_i8(*x),
467 RawOperand::Imm16(x) => buf.put_i16(*x),
468 RawOperand::Imm32(x) => buf.put_i32(*x),
469 RawOperand::Addr8(x) => buf.put_u8(*x),
470 RawOperand::Addr16(x) => buf.put_u16(*x),
471 RawOperand::Addr32(x) => buf.put_u32(*x),
472 RawOperand::Stack => {}
473 RawOperand::Frame8(x) => buf.put_u8(*x),
474 RawOperand::Frame16(x) => buf.put_u16(*x),
475 RawOperand::Frame32(x) => buf.put_u32(*x),
476 RawOperand::Ram8(x) => buf.put_u8(*x),
477 RawOperand::Ram16(x) => buf.put_u16(*x),
478 RawOperand::Ram32(x) => buf.put_u32(*x),
479 }
480 }
481}
482
483#[inline]
485pub fn f32_to_imm<L>(x: f32) -> LoadOperand<L> {
486 LoadOperand::Imm(x.to_bits().cast_sign())
487}
488
489#[allow(clippy::as_conversions, clippy::cast_possible_truncation)]
491#[inline]
492pub fn f64_to_imm<L>(x: f64) -> (LoadOperand<L>, LoadOperand<L>) {
493 let n = x.to_bits();
494 let high = (n >> 32) as u32;
495 let low = n as u32;
496 (
497 LoadOperand::Imm(high.cast_sign()),
498 LoadOperand::Imm(low.cast_sign()),
499 )
500}