1pub mod operation;
2pub mod register;
3
4use std::fmt;
5
6use crate::expr::Expr;
7
8use crate::instruction::{
9 operation::{BranchT, Operation},
10 register::{Reg16, Reg8},
11};
12
13use crate::context::Context;
14use byteorder::{ByteOrder, LittleEndian};
15use failure::{bail, Error};
16
17#[derive(Clone, PartialEq, Eq, Debug)]
19pub enum IndexOps {
20 None(Reg16),
22 PostIncrement(Reg16),
24 PostIncrementE(Reg16, Expr),
26 PreDecrement(Reg16),
28}
29
30impl fmt::Display for IndexOps {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 match self {
33 IndexOps::None(r16) => write!(f, "{}", r16),
34 IndexOps::PostIncrement(r16) => write!(f, "{}+", r16),
35 IndexOps::PreDecrement(r16) => write!(f, "-{}", r16),
36 IndexOps::PostIncrementE(r16, expr) => write!(f, "{}+{}", r16, expr),
37 }
38 }
39}
40
41#[derive(Clone, PartialEq, Eq, Debug)]
42pub enum InstructionOps {
43 R8(Reg8),
44 Index(IndexOps),
45 E(Expr),
46}
47
48impl fmt::Display for InstructionOps {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 match self {
51 InstructionOps::R8(r8) => write!(f, "{}", r8),
52 InstructionOps::Index(index) => write!(f, "{}", index),
53 InstructionOps::E(expr) => write!(f, "{}", expr),
54 }
55 }
56}
57
58impl InstructionOps {
59 fn get_r8(&self, constants: &dyn Context) -> Result<Reg8, Error> {
60 match self {
61 Self::R8(reg8) => Ok(*reg8),
62 Self::E(Expr::Ident(name)) => match constants.get_def(name).map(|x| x.clone()) {
63 Some(reg8) => Ok(reg8),
64 None => bail!("No found {} in .defs", name),
65 },
66 _ => {
67 bail!("Argument must be R0-R16");
68 }
69 }
70 }
71
72 fn get_expr(&self) -> Result<Expr, Error> {
73 match self {
74 Self::E(expr) => Ok(expr.clone()),
75 _ => {
76 bail!("Argument must be valid expression");
77 }
78 }
79 }
80
81 fn get_index(&self) -> Result<IndexOps, Error> {
82 match self {
83 Self::Index(index) => Ok(index.clone()),
84 _ => {
85 bail!("Argument must be valid expression");
86 }
87 }
88 }
89}
90
91pub fn process(
94 op: &Operation,
95 op_args: &Vec<InstructionOps>,
96 current_address: u32,
97 constants: &dyn Context,
98) -> Result<Vec<u8>, Error> {
99 let mut finalized_opcode = vec![];
100
101 let mut opcode = op.info(constants).op_code;
102 let mut opcode_2part = 0u16;
103 let mut long_opcode = false;
104
105 match op {
106 Operation::Add
107 | Operation::Adc
108 | Operation::Sub
109 | Operation::Sbc
110 | Operation::And
111 | Operation::Or
112 | Operation::Eor
113 | Operation::Cpse
114 | Operation::Cp
115 | Operation::Cpc
116 | Operation::Mov
117 | Operation::Mul => {
118 let d = op_args[0].get_r8(constants)?;
119 opcode |= d.number() << 4;
120
121 let r = op_args[1].get_r8(constants)?;
122 opcode |= (r.number() & 0x10) << 5 | r.number() & 0x0f;
123 }
124 Operation::Adiw | Operation::Sbiw => {
125 let d = op_args[0].get_r8(constants)?;
126 let d = d.number();
127 if !(d == 24 || d == 26 || d == 28 || d == 30) {
128 bail!("{:?} can only use registers R24, R26, R28 or R30", op);
129 }
130 opcode |= ((d - 24) / 2) << 4;
131
132 let k = op_args[1].get_expr()?;
133 let k = k.get_byte(constants)? as i8;
134 if k < 0 || k > 63 {
135 bail!("Constant out of range (0 <= k <= 63");
136 }
137 let k = k as u16;
138 opcode |= (k & 0x30) << 2 | k & 0x0f;
139 }
140 Operation::Subi
141 | Operation::Sbci
142 | Operation::Andi
143 | Operation::Ori
144 | Operation::Sbr
145 | Operation::Cbr
146 | Operation::Cpi
147 | Operation::Ldi => {
148 let d = op_args[0].get_r8(constants)?;
149 if d.number() < 16 {
150 bail!("{:?} can only use a high register (r16 - r31)", op);
151 }
152 opcode |= (d.number() & 0x0f) << 4;
153
154 let k = op_args[1].get_expr()?;
155 let mut k: u16 = k.get_byte(constants)? as u16;
156 match op {
157 Operation::Cbr => {
158 k = 0xff - k;
159 }
160 _ => {}
161 }
162 opcode |= (k & 0xf0) << 4 | (k & 0x0f);
163 }
164 Operation::Com
165 | Operation::Neg
166 | Operation::Inc
167 | Operation::Dec
168 | Operation::Push
169 | Operation::Pop
170 | Operation::Lsr
171 | Operation::Ror
172 | Operation::Asr
173 | Operation::Swap => {
174 let r = op_args[0].get_r8(constants)?;
175 opcode |= r.number() << 4;
176 }
177 Operation::Tst | Operation::Clr | Operation::Lsl | Operation::Rol => {
178 let r = op_args[0].get_r8(constants)?;
179 opcode |= r.number() << 4;
180 opcode |= (r.number() & 0x10) << 5 | r.number() & 0x0f;
181 }
182 Operation::Ser => {
183 let r = op_args[0].get_r8(constants)?;
184 if r.number() < 16 {
185 bail!("{:?} can only use a high register (r16 - r31)", op);
186 }
187 opcode |= (r.number() & 0x0f) << 4;
188 }
189 Operation::Muls => {
190 let d = op_args[0].get_r8(constants)?;
191 if d.number() < 16 {
192 bail!("{:?} can only use a high register (r16 - r31)", op);
193 }
194 opcode |= (d.number() & 0x0f) << 4;
195
196 let r = op_args[1].get_r8(constants)?;
197 if r.number() < 16 {
198 bail!("{:?} can only use a high register (r16 - r31)", op);
199 }
200 opcode |= r.number() & 0x0f;
201 }
202 Operation::Mulsu | Operation::Fmul | Operation::Fmuls | Operation::Fmulsu => {
203 let d = op_args[0].get_r8(constants)?;
204 if d.number() < 16 {
205 bail!("{:?} can only use registers (r16 - r23)", op);
206 }
207 opcode |= (d.number() & 0x07) << 4;
208
209 let r = op_args[1].get_r8(constants)?;
210 if r.number() < 16 {
211 bail!("{:?} can only use registers (r16 - r23)", op);
212 }
213 opcode |= r.number() & 0x07;
214 }
215 Operation::Rjmp | Operation::Rcall => {
216 let k = op_args[0].get_expr()?;
217 let k = k.run(constants)?;
218 let rel = k - (current_address as i64 + 1);
219 if rel < -2048 || rel > 2047 {
220 bail!("Relative address out of range (-2048 <= k <= 2047)");
221 }
222 opcode |= (rel as u16) & 0x0fff;
223 }
224 Operation::Jmp | Operation::Call => {
225 let k = op_args[0].get_expr()?;
226 let k = k.run(constants)?;
227 if k < 0 || k > 4194303 {
228 bail!("Address out of range (0 <= k <= 4194303)");
229 }
230
231 let k = k as u64;
232 opcode |= ((k & 0x3e0000) >> 13 | (k & 0x010000) >> 16) as u16;
233 opcode_2part = (k & 0xffff) as u16;
234
235 long_opcode = true;
236 }
237 Operation::Br(s) => {
238 let mut index = 0;
239 opcode |= match s {
240 BranchT::Bs | BranchT::Bc => {
241 let s = op_args[index].get_expr()?;
242 index += 1;
243 s.get_bit_index(constants)? as u16
244 }
245 _ => 0,
246 };
247 let s = s.number();
248 opcode |= s;
249
250 let k = op_args[index].get_expr()?;
251 let k = k.run(constants)?;
252 let rel = k - (current_address as i64 + 1);
253 if rel < -64 || rel > 63 {
254 bail!("Relative address out of range (-64 <= k <= 63)");
255 }
256 opcode |= ((rel as u16) & 0x7f) << 3;
257 }
258 Operation::Movw => {
259 let d = op_args[0].get_r8(constants)?;
260 if d.number() < 16 && d.number() % 2 != 0 {
261 bail!("{:?} can only use a even numbered for Rd", op);
262 }
263 opcode |= (d.number() / 2) << 4;
264
265 let r = op_args[1].get_r8(constants)?;
266 if r.number() < 16 && r.number() % 2 != 0 {
267 bail!("{:?} can only use a even numbered for Rr", op);
268 }
269 opcode |= r.number() / 2;
270 }
271
272 Operation::Lds | Operation::Sts => {
273 let (r, k) = if let Operation::Lds = op {
274 (op_args[0].get_r8(constants)?, op_args[1].get_expr()?)
275 } else {
276 (op_args[1].get_r8(constants)?, op_args[0].get_expr()?)
277 };
278 opcode |= r.number() << 4;
279
280 let k = k.run(constants)?;
281
282 if constants.get_device().is_avr8l() {
283 if k < 40 || k > 0xbf {
284 bail!("Address out of range (0x40 <= k <= 0xbf)");
285 }
286
287 let k = k as u16;
288 opcode |= (k & 0x40) << 2 | (k & 0x30) << 5 | (k & 0x0f);
289 } else {
290 if k < 0 || k > 65535 {
291 bail!("Address out of range (0 <= k <= 65535)");
292 }
293
294 opcode_2part = (k as u16) & 0xffff;
295
296 long_opcode = true;
297 }
298 }
299 Operation::Ld | Operation::St | Operation::Ldd | Operation::Std => {
300 let (r, i) = match op {
301 Operation::Ld | Operation::Ldd => {
302 (op_args[0].get_r8(constants)?, op_args[1].get_index()?)
303 }
304 Operation::St | Operation::Std => {
305 (op_args[1].get_r8(constants)?, op_args[0].get_index()?)
306 }
307 _ => {
308 bail!("Unsupported variant!");
309 }
310 };
311 opcode |= r.number() << 4;
312
313 let reg_value = |i| match i {
314 Reg16::X => 0b1100,
315 Reg16::Y => 0b1000,
316 Reg16::Z => 0b0000,
317 };
318
319 opcode |= match i {
320 IndexOps::None(r16) => {
321 0b00 | if r16 == Reg16::X { 0x1000 } else { 0x0 } | reg_value(r16)
322 }
323 IndexOps::PostIncrement(r16) => 0b01 | 0x1000 | reg_value(r16),
324 IndexOps::PreDecrement(r16) => 0b10 | 0x1000 | reg_value(r16),
325 IndexOps::PostIncrementE(r16, expr) => {
326 let mut op = match r16 {
327 Reg16::X => {
328 bail!("Index regist must be Y or Z");
329 }
330 Reg16::Y => 0b1000,
331 Reg16::Z => 0b0000,
332 };
333 let k = expr.get_byte(constants)? as i8;
334 if k < 0 || k > 63 {
335 bail!("K out of range (0 <= P <= 63");
336 }
337 let k = k as u16;
338 op |= (k & 0x20) << 8 | (k & 0x18) << 7 | k & 0x07;
339 op
340 }
341 };
342 }
343 Operation::Lpm | Operation::Elpm => {
344 if op_args.len() == 0 {
345 opcode = if let Operation::Lpm = op {
346 0b_0101_1100_1000
347 } else {
348 0b_0101_1101_1000
349 }
350 } else {
351 let r = op_args[0].get_r8(constants)?;
352 opcode |= r.number() << 4;
353
354 let i = op_args[1].get_index()?;
355
356 opcode |= match i {
357 IndexOps::None(Reg16::Z) => 0b100,
358 IndexOps::PostIncrement(Reg16::Z) => 0b101,
359 _ => {
360 bail!("Other options are not allowed to lpm/elpm");
361 }
362 };
363
364 opcode |= if let Operation::Elpm = op { 0b10 } else { 0b0 };
365 }
366 }
367 Operation::In | Operation::Out => {
368 let (r, k) = if let Operation::In = op {
369 (op_args[0].get_r8(constants)?, op_args[1].get_expr()?)
370 } else {
371 (op_args[1].get_r8(constants)?, op_args[0].get_expr()?)
372 };
373 opcode |= r.number() << 4;
374
375 let k = k.get_byte(constants)? as i8;
376 if k < 0 || k > 63 {
377 bail!("I/O out of range (0 <= P <= 63");
378 }
379 let k = k as u16;
380 opcode |= (k & 0x30) << 5 | k & 0x0f;
381 }
382 Operation::Sbrc | Operation::Sbrs | Operation::Bst | Operation::Bld => {
383 opcode |= op_args[0].get_r8(constants)?.number() << 4;
384
385 let b = op_args[1].get_expr()?;
386 let b: u16 = b.get_bit_index(constants)? as u16;
387
388 opcode |= b;
389 }
390 Operation::Sbi | Operation::Cbi | Operation::Sbis | Operation::Sbic => {
391 let k = op_args[0].get_expr()?.get_byte(constants)? as i8;
392 if k < 0 || k > 31 {
393 bail!("I/O out of range (0 <= P <= 31");
394 }
395 let k = k as u16;
396
397 opcode |= k << 3;
398
399 let b = op_args[1].get_expr()?;
400 let b: u16 = b.get_bit_index(constants)? as u16;
401
402 opcode |= b;
403 }
404 Operation::Bset | Operation::Bclr => {
405 let k = op_args[0].get_expr()?;
406 let k: u16 = k.get_bit_index(constants)? as u16;
407 opcode |= k << 4;
408 }
409 Operation::Se(k) | Operation::Cl(k) => {
410 let k = k.number();
411 opcode |= k << 4;
412 }
413 _ => {}
414 }
415 let mut result = [0, 0];
417 LittleEndian::write_u16(&mut result, opcode);
418 finalized_opcode.extend(&result);
419
420 if long_opcode {
422 let mut result = [0, 0];
423 LittleEndian::write_u16(&mut result, opcode_2part);
424 finalized_opcode.extend(&result);
425 }
426
427 Ok(finalized_opcode)
428}
429
430#[cfg(test)]
431mod parser_tests {
432 use super::*;
433 use crate::{
434 document::{document, Document},
435 expr::{BinaryExpr, BinaryOperator, Expr},
436 instruction::operation::{BranchT, Operation, SFlags},
437 };
438
439 #[test]
440 fn operation_test() {
441 assert_eq!(document::operation("mov"), Ok(Operation::Mov));
442
443 assert_eq!(document::operation("breq"), Ok(Operation::Br(BranchT::Eq)));
444
445 assert_eq!(document::operation("sei"), Ok(Operation::Se(SFlags::I)));
446
447 assert_eq!(document::operation("clt"), Ok(Operation::Cl(SFlags::T)));
448
449 assert_eq!(
450 document::operation("outi"),
451 Ok(Operation::Custom("outi".to_string()))
452 );
453
454 assert_eq!(
455 document::operation("brtt"),
456 Ok(Operation::Custom("brtt".to_string()))
457 );
458 }
459
460 #[test]
461 fn reg8_test() {
462 assert_eq!(document::reg8("r0"), Ok(Reg8::R0));
463
464 assert_eq!(document::reg8("r21"), Ok(Reg8::R21));
465 }
466
467 #[test]
468 fn reg8_rev_convert_test() {
469 assert_eq!((Reg8::R0).to_string(), String::from("r0"));
470
471 assert_eq!((Reg8::R21).to_string(), String::from("r21"));
472 }
473
474 #[test]
475 fn reg16_test() {
476 assert_eq!(document::reg16("X"), Ok(Reg16::X));
477
478 assert_eq!(document::reg16("Y"), Ok(Reg16::Y));
479
480 assert_eq!(document::reg16("Z"), Ok(Reg16::Z));
481 }
482
483 #[test]
484 fn reg16_rev_convert_test() {
485 assert_eq!((Reg16::X).to_string(), String::from("x"));
486
487 assert_eq!((Reg16::Y).to_string(), String::from("y"));
488
489 assert_eq!((Reg16::Z).to_string(), String::from("z"));
490 }
491
492 #[test]
493 fn index_ops_test() {
494 assert_eq!(document::index_ops("X"), Ok(IndexOps::None(Reg16::X)));
495
496 assert_eq!(
497 document::index_ops("-Y"),
498 Ok(IndexOps::PreDecrement(Reg16::Y))
499 );
500
501 assert_eq!(
502 document::index_ops("X+"),
503 Ok(IndexOps::PostIncrement(Reg16::X))
504 );
505
506 assert_eq!(
507 document::index_ops("Z+4"),
508 Ok(IndexOps::PostIncrementE(Reg16::Z, Expr::Const(4)))
509 );
510 }
511
512 #[test]
513 fn index_ops_rev_convert_test() {
514 assert_eq!((IndexOps::None(Reg16::X)).to_string(), String::from("x"));
515
516 assert_eq!(
517 (IndexOps::PreDecrement(Reg16::Y)).to_string(),
518 String::from("-y")
519 );
520
521 assert_eq!(
522 (IndexOps::PostIncrement(Reg16::X)).to_string(),
523 String::from("x+")
524 );
525
526 assert_eq!(
527 (IndexOps::PostIncrementE(Reg16::Z, Expr::Const(4))).to_string(),
528 String::from("z+4")
529 );
530 }
531
532 #[test]
533 fn instruction_ops_test() {
534 assert_eq!(
535 document::instruction_ops("r0"),
536 Ok(InstructionOps::R8(Reg8::R0))
537 );
538
539 assert_eq!(
540 document::instruction_ops("t"),
541 Ok(InstructionOps::E(Expr::Ident("t".to_string())))
542 );
543
544 assert_eq!(
545 document::instruction_ops("Y+24"),
546 Ok(InstructionOps::Index(IndexOps::PostIncrementE(
547 Reg16::Y,
548 Expr::Const(24)
549 )))
550 );
551
552 assert_eq!(
553 document::instruction_ops("zl"),
554 Ok(InstructionOps::E(Expr::Ident("zl".to_string())))
555 );
556 }
557
558 #[test]
559 fn op_list_test() {
560 assert_eq!(document::op_list(""), Ok(vec![]));
561
562 assert_eq!(
563 document::op_list("a\t, b,c ,\td"),
564 Ok(vec![
565 InstructionOps::E(Expr::Ident("a".to_string())),
566 InstructionOps::E(Expr::Ident("b".to_string())),
567 InstructionOps::E(Expr::Ident("c".to_string())),
568 InstructionOps::E(Expr::Ident("d".to_string())),
569 ])
570 );
571
572 assert_eq!(
573 document::op_list("a,b,c,d"),
574 Ok(vec![
575 InstructionOps::E(Expr::Ident("a".to_string())),
576 InstructionOps::E(Expr::Ident("b".to_string())),
577 InstructionOps::E(Expr::Ident("c".to_string())),
578 InstructionOps::E(Expr::Ident("d".to_string())),
579 ])
580 );
581 }
582
583 #[test]
584 fn instruction_line_test() {
585 assert_eq!(
586 document::instruction_line("cli"),
587 Ok(Document::CodeLine(
588 Box::new(None),
589 Operation::Cl(SFlags::I),
590 vec![]
591 ))
592 );
593
594 assert_eq!(
595 document::instruction_line("push r0"),
596 Ok(Document::CodeLine(
597 Box::new(None),
598 Operation::Push,
599 vec![InstructionOps::R8(Reg8::R0)]
600 ))
601 );
602
603 assert_eq!(
604 document::instruction_line("ldi r16, 1 << 4 | 1 << 2"),
605 Ok(Document::CodeLine(
606 Box::new(None),
607 Operation::Ldi,
608 vec![
609 InstructionOps::R8(Reg8::R16),
610 InstructionOps::E(Expr::Binary(Box::new(BinaryExpr {
611 left: Expr::Binary(Box::new(BinaryExpr {
612 left: Expr::Const(1),
613 operator: BinaryOperator::ShiftLeft,
614 right: Expr::Const(4)
615 })),
616 operator: BinaryOperator::BitwiseOr,
617 right: Expr::Binary(Box::new(BinaryExpr {
618 left: Expr::Const(1),
619 operator: BinaryOperator::ShiftLeft,
620 right: Expr::Const(2)
621 }))
622 })))
623 ]
624 ))
625 );
626
627 assert_eq!(
628 document::instruction_line("ldi r18, high(t)"),
629 Ok(Document::CodeLine(
630 Box::new(None),
631 Operation::Ldi,
632 vec![
633 InstructionOps::R8(Reg8::R18),
634 InstructionOps::E(Expr::Func(
635 Box::new(Expr::Ident("high".to_string())),
636 Box::new(Expr::Ident("t".to_string()))
637 ))
638 ]
639 ))
640 );
641
642 assert_eq!(
643 document::instruction_line("ld r19, X+"),
644 Ok(Document::CodeLine(
645 Box::new(None),
646 Operation::Ld,
647 vec![
648 InstructionOps::R8(Reg8::R19),
649 InstructionOps::Index(IndexOps::PostIncrement(Reg16::X))
650 ]
651 ))
652 );
653
654 assert_eq!(
655 document::instruction_line("outi UDR0, r16, 1 << 4 | 1 << 2"),
656 Ok(Document::CodeLine(
657 Box::new(None),
658 Operation::Custom("outi".to_string()),
659 vec![
660 InstructionOps::E(Expr::Ident("UDR0".to_string())),
661 InstructionOps::R8(Reg8::R16),
662 InstructionOps::E(Expr::Binary(Box::new(BinaryExpr {
663 left: Expr::Binary(Box::new(BinaryExpr {
664 left: Expr::Const(1),
665 operator: BinaryOperator::ShiftLeft,
666 right: Expr::Const(4)
667 })),
668 operator: BinaryOperator::BitwiseOr,
669 right: Expr::Binary(Box::new(BinaryExpr {
670 left: Expr::Const(1),
671 operator: BinaryOperator::ShiftLeft,
672 right: Expr::Const(2)
673 }))
674 })))
675 ]
676 ))
677 );
678
679 assert_eq!(
680 document::instruction_line("sei ; enable interrupts"),
681 Ok(Document::CodeLine(
682 Box::new(None),
683 Operation::Se(SFlags::I),
684 vec![]
685 ))
686 );
687
688 assert_eq!(
689 document::instruction_line("exit: ret"),
690 Ok(Document::CodeLine(
691 Box::new(Some(Document::Label("exit".to_string()))),
692 Operation::Ret,
693 vec![]
694 ))
695 );
696
697 assert_eq!(
698 document::instruction_line("fail: reti; exit from interrupt"),
699 Ok(Document::CodeLine(
700 Box::new(Some(Document::Label("fail".to_string()))),
701 Operation::Reti,
702 vec![]
703 ))
704 );
705 }
706}