avra_lib/builder/
pass2.rs

1//! Contains second pass builder of AVRA-rs
2
3use crate::{
4    builder::pass1::BuildResultPass1,
5    context::{CommonContext, Context},
6    directive::GetData,
7    expr::Expr,
8    instruction::{process, register::Reg8},
9    parser::{DataDefine, Item, Segment, SegmentType},
10};
11
12use std::str::FromStr;
13
14use failure::{bail, Error};
15
16#[derive(Clone, PartialEq, Eq, Debug)]
17pub struct BuildResultPass2 {
18    pub code_start_address: u32,
19    pub code: Vec<u8>,
20    pub eeprom_start_address: u32,
21    pub eeprom: Vec<u8>,
22    pub ram_filling: u32,
23    pub messages: Vec<String>,
24}
25
26pub fn build_pass_2(
27    pass1: BuildResultPass1,
28    common_context: &CommonContext,
29) -> Result<BuildResultPass2, Error> {
30    let mut code = vec![];
31    let code_start_address = 0x0;
32    let mut eeprom = vec![];
33    let eeprom_start_address = 0x0;
34
35    for segment in pass1.segments {
36        // TODO: Rewrite to correct ordering of segment offsets and sizes
37        match segment.t {
38            SegmentType::Code => {
39                // pad to address
40                for _ in (code_start_address as i32)..segment.address as i32 - code.len() as i32 / 2
41                {
42                    // Pushing nop command for spaces
43                    code.extend(vec![0x00, 0x00]);
44                }
45            }
46            SegmentType::Eeprom => {
47                // pad to address
48                for _ in (eeprom_start_address as i32)..segment.address as i32 - eeprom.len() as i32
49                {
50                    // Pushing empty data for spaces
51                    eeprom.extend(vec![0x00]);
52                }
53            }
54            // Data not writed anywhere
55            SegmentType::Data => {}
56        }
57
58        let fragment = pass_2_internal(&segment, common_context)?;
59
60        match segment.t {
61            SegmentType::Code => {
62                code.extend(fragment);
63            }
64            SegmentType::Eeprom => {
65                eeprom.extend(fragment);
66            }
67            // Data not writed anywhere
68            SegmentType::Data => {}
69        }
70    }
71
72    Ok(BuildResultPass2 {
73        code_start_address,
74        code,
75        eeprom_start_address,
76        eeprom,
77        ram_filling: pass1.ram_filling,
78        messages: pass1.messages,
79    })
80}
81
82fn pass_2_internal(segment: &Segment, common_context: &CommonContext) -> Result<Vec<u8>, Error> {
83    let mut code_fragment = vec![];
84
85    let mut cur_address = segment.address;
86
87    for (line, item) in segment.items.iter() {
88        common_context.set_special("pc".to_string(), Expr::Const(cur_address as i64));
89        match item {
90            Item::Instruction(op, op_args) => {
91                if common_context.get_device().check_operation(op) {
92                    let complete_op = match process(&op, &op_args, cur_address, common_context) {
93                        Ok(ok) => ok,
94                        Err(e) => bail!("{}, {}", e, line),
95                    };
96                    cur_address += complete_op.len() as u32 / 2;
97                    code_fragment.extend(complete_op);
98                } else {
99                    bail!(
100                        "instruction {} is not allowed for current device, {}",
101                        op,
102                        line
103                    )
104                }
105            }
106            Item::Data(item_type, items) => {
107                let data = match item_type {
108                    DataDefine::Db => items.get_bytes(common_context),
109                    DataDefine::Dw => items.get_words(common_context),
110                    DataDefine::Dd => items.get_double_words(common_context),
111                    DataDefine::Dq => items.get_quad_words(common_context),
112                }?;
113                cur_address += if let SegmentType::Code = segment.t {
114                    data.len() as u32 / 2
115                } else {
116                    data.len() as u32
117                };
118                code_fragment.extend(data);
119            }
120            Item::ReserveData(size) => {
121                cur_address += *size as u32;
122                for _ in 0..*size {
123                    code_fragment.push(0x0);
124                }
125            }
126            Item::Def(alias, Expr::Ident(register)) => {
127                if let Some(_) = common_context.set_def(
128                    alias.to_lowercase(),
129                    Reg8::from_str(register.to_lowercase().as_str()).unwrap(),
130                ) {
131                    // TODO: add display current string of mistake and previous location
132                    bail!("Identifier {} is used twice, {}", alias, line);
133                }
134            }
135            Item::Undef(alias) => {
136                if let None = common_context.defs.borrow_mut().remove(alias) {
137                    bail!("Identifier {} isn't defined, {}", alias, line);
138                }
139            }
140            Item::Set(name, expr) => {
141                let value = expr.run(common_context)?;
142                if common_context.exist(name) {
143                    let mut sets = common_context.sets.borrow_mut();
144                    if let Some(_) = sets.get(name) {
145                        sets.insert(name.clone(), Expr::Const(value));
146                    } else {
147                        // TODO: add display current string of mistake and previous location
148                        bail!("Identifier {} is used twice, {}", name, line);
149                    }
150                } else {
151                    common_context
152                        .sets
153                        .borrow_mut()
154                        .insert(name.clone(), Expr::Const(value));
155                }
156            }
157            _ => {}
158        }
159    }
160
161    Ok(code_fragment)
162}
163
164#[cfg(test)]
165mod builder_tests {
166    use super::*;
167    use crate::{
168        builder::{
169            pass0::{build_pass_0, BuildResultPass0},
170            pass1::build_pass_1,
171        },
172        parser::parse_str,
173    };
174
175    #[test]
176    fn check_empty() {
177        let common_context = CommonContext::new();
178        let build_result = build_pass_2(
179            build_pass_1(BuildResultPass0::new(), &common_context).unwrap(),
180            &common_context,
181        );
182        assert_eq!(
183            build_result.unwrap(),
184            BuildResultPass2 {
185                code_start_address: 0x0,
186                code: vec![],
187                eeprom_start_address: 0x0,
188                eeprom: vec![],
189                ram_filling: 0,
190                messages: vec![],
191            }
192        );
193    }
194
195    #[test]
196    fn check_no_args() {
197        let common_context = CommonContext::new();
198        let parse_result = parse_str(
199            "
200        nop
201        ret
202        seh
203        clh
204        ",
205            &common_context,
206        );
207        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
208
209        let build_result = build_pass_2(
210            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
211            &common_context,
212        );
213        assert_eq!(
214            build_result.unwrap(),
215            BuildResultPass2 {
216                code_start_address: 0x0,
217                code: vec![0x00, 0x00, 0x08, 0x95, 0x58, 0x94, 0xd8, 0x94],
218                eeprom_start_address: 0x0,
219                eeprom: vec![],
220                ram_filling: 0,
221                messages: vec![],
222            }
223        );
224    }
225
226    #[test]
227    fn check_one_arg() {
228        let common_context = CommonContext::new();
229        let parse_result = parse_str(
230            "
231        push r0
232        lsl r0
233        swap r0
234        pop r1
235        ",
236            &common_context,
237        );
238        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
239
240        let build_result = build_pass_2(
241            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
242            &common_context,
243        );
244        assert_eq!(
245            build_result.unwrap(),
246            BuildResultPass2 {
247                code_start_address: 0x0,
248                code: vec![0xf, 0x92, 0x0, 0xc, 0x2, 0x94, 0x1f, 0x90],
249                eeprom_start_address: 0x0,
250                eeprom: vec![],
251                ram_filling: 0,
252                messages: vec![],
253            }
254        );
255
256        let common_context = CommonContext::new();
257        let parse_result = parse_str(
258            "
259        tst r1
260error:
261        brpl exit
262exit:
263        rjmp error
264        ",
265            &common_context,
266        );
267        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
268
269        let build_result = build_pass_2(
270            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
271            &common_context,
272        );
273        assert_eq!(
274            build_result.unwrap(),
275            BuildResultPass2 {
276                code_start_address: 0x0,
277                code: vec![0x11, 0x20, 0x2, 0xf4, 0xfe, 0xcf],
278                eeprom_start_address: 0x0,
279                eeprom: vec![],
280                ram_filling: 0,
281                messages: vec![],
282            }
283        );
284    }
285
286    #[test]
287    fn check_two_args() {
288        let common_context = CommonContext::new();
289        let parse_result = parse_str(
290            "
291        ldi r16, 1 << 2 | 1 << 1
292        mov r0, r16
293        subi r16, (-1)
294        sts data, r16
295data:
296        ",
297            &common_context,
298        );
299        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
300
301        let build_result = build_pass_2(
302            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
303            &common_context,
304        );
305        assert_eq!(
306            build_result.unwrap(),
307            BuildResultPass2 {
308                code_start_address: 0x0,
309                code: vec![0x6, 0xe0, 0x0, 0x2e, 0xf, 0x5f, 0x0, 0x93, 0x5, 0x0],
310                eeprom_start_address: 0x0,
311                eeprom: vec![],
312                ram_filling: 0,
313                messages: vec![],
314            }
315        );
316
317        let common_context = CommonContext::new();
318        let parse_result = parse_str(
319            "
320        ld r17, X
321        ld r18, Y+
322        ld r19, -Z
323        st X+, r19
324        ",
325            &common_context,
326        );
327        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
328
329        let build_result = build_pass_2(
330            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
331            &common_context,
332        );
333        assert_eq!(
334            build_result.unwrap(),
335            BuildResultPass2 {
336                code_start_address: 0x0,
337                code: vec![0x1c, 0x91, 0x29, 0x91, 0x32, 0x91, 0x3d, 0x93],
338                eeprom_start_address: 0x0,
339                eeprom: vec![],
340                ram_filling: 0,
341                messages: vec![],
342            }
343        );
344
345        let common_context = CommonContext::new();
346        let parse_result = parse_str(
347            "
348        ldd r25, Z+2
349        std Z+6, r24
350        ",
351            &common_context,
352        );
353        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
354
355        let build_result = build_pass_2(
356            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
357            &common_context,
358        );
359        assert_eq!(
360            build_result.unwrap(),
361            BuildResultPass2 {
362                code_start_address: 0x0,
363                code: vec![0x92, 0x81, 0x86, 0x83],
364                eeprom_start_address: 0x0,
365                eeprom: vec![],
366                ram_filling: 0,
367                messages: vec![],
368            }
369        );
370    }
371
372    #[test]
373    fn check_db_dw_dd_dq() {
374        let common_context = CommonContext::new();
375        let parse_result = parse_str(
376            "
377        .equ end = 0
378        ldi r16, data
379data:   .db 15, 26, \"Hello, World\", end  
380        ",
381            &common_context,
382        );
383        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
384
385        let build_result = build_pass_2(
386            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
387            &common_context,
388        );
389        assert_eq!(
390            build_result.unwrap(),
391            BuildResultPass2 {
392                code_start_address: 0x0,
393                code: vec![
394                    0x1, 0xe0, 0xf, 0x1a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57, 0x6f,
395                    0x72, 0x6c, 0x64, 0x0, 0x0
396                ],
397                eeprom_start_address: 0x0,
398                eeprom: vec![],
399                ram_filling: 0,
400                messages: vec![],
401            }
402        );
403
404        let common_context = CommonContext::new();
405        let parse_result = parse_str(
406            "
407        .equ end = 0
408        ldi r18, data_w 
409data_w:
410        .dw 0xff44, end, 0xda4e
411        ",
412            &common_context,
413        );
414        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
415
416        let build_result = build_pass_2(
417            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
418            &common_context,
419        );
420        assert_eq!(
421            build_result.unwrap(),
422            BuildResultPass2 {
423                code_start_address: 0x0,
424                code: vec![0x21, 0xe0, 0x44, 0xff, 0x0, 0x0, 0x4e, 0xda],
425                eeprom_start_address: 0x0,
426                eeprom: vec![],
427                ram_filling: 0,
428                messages: vec![],
429            }
430        );
431
432        let common_context = CommonContext::new();
433        let parse_result = parse_str(
434            "
435        ldi r18, data_d
436data_d:
437        .dd 0x12345678, 0x9abcdef0
438        ",
439            &common_context,
440        );
441        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
442
443        let build_result = build_pass_2(
444            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
445            &common_context,
446        );
447        assert_eq!(
448            build_result.unwrap(),
449            BuildResultPass2 {
450                code_start_address: 0x0,
451                code: vec![0x21, 0xe0, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a],
452                eeprom_start_address: 0x0,
453                eeprom: vec![],
454                ram_filling: 0,
455                messages: vec![],
456            }
457        );
458
459        let common_context = CommonContext::new();
460        let parse_result = parse_str(
461            "
462        ldi r18, data_q
463data_q:
464        .dq 0x1, 0x1000000000011000
465        ",
466            &common_context,
467        );
468        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
469
470        let build_result = build_pass_2(
471            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
472            &common_context,
473        );
474        assert_eq!(
475            build_result.unwrap(),
476            BuildResultPass2 {
477                code_start_address: 0x0,
478                code: vec![
479                    0x21, 0xe0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x1, 0x0, 0x0,
480                    0x0, 0x0, 0x10
481                ],
482                eeprom_start_address: 0x0,
483                eeprom: vec![],
484                ram_filling: 0,
485                messages: vec![],
486            }
487        );
488    }
489
490    #[test]
491    fn check_cseg_org() {
492        let common_context = CommonContext::new();
493        let parse_result = parse_str(
494            "
495        nop
496        .org 0x2
497        seh
498        .cseg
499        .org 0x5
500        clh
501        ",
502            &common_context,
503        );
504        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
505
506        let build_result = build_pass_2(
507            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
508            &common_context,
509        );
510        assert_eq!(
511            build_result.unwrap(),
512            BuildResultPass2 {
513                code_start_address: 0x0,
514                code: vec![0x00, 0x00, 0x00, 0x00, 0x58, 0x94, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x94],
515                eeprom_start_address: 0x0,
516                eeprom: vec![],
517                ram_filling: 0,
518                messages: vec![],
519            }
520        );
521    }
522
523    #[test]
524    fn check_eseg() {
525        let common_context = CommonContext::new();
526        let parse_result = parse_str(
527            "
528        .equ end = 0
529        ldi r18, data_w 
530        .eseg
531data_w:
532        .dw 0xff44, end, 0xda4e
533        ",
534            &common_context,
535        );
536        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
537
538        let build_result = build_pass_2(
539            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
540            &common_context,
541        );
542        assert_eq!(
543            build_result.unwrap(),
544            BuildResultPass2 {
545                code_start_address: 0x0,
546                code: vec![0x20, 0xe0],
547                eeprom_start_address: 0x0,
548                eeprom: vec![0x44, 0xff, 0x0, 0x0, 0x4e, 0xda],
549                ram_filling: 0,
550                messages: vec![],
551            }
552        );
553    }
554
555    #[test]
556    fn check_dseg() {
557        let common_context = CommonContext::new();
558        let parse_result = parse_str(
559            "
560.dseg
561data: .byte 1
562counter:
563    .byte 2
564        .cseg
565        lds r18, data
566        lds r16, counter
567        lds r17, counter+1
568        ",
569            &common_context,
570        );
571        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
572
573        let build_result = build_pass_2(
574            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
575            &common_context,
576        );
577        assert_eq!(
578            build_result.unwrap(),
579            BuildResultPass2 {
580                code_start_address: 0x0,
581                code: vec![0x20, 0x91, 0x60, 0x0, 0x0, 0x91, 0x61, 0x0, 0x10, 0x91, 0x62, 0x0],
582                eeprom_start_address: 0x0,
583                eeprom: vec![],
584                ram_filling: 3,
585                messages: vec![],
586            }
587        );
588    }
589
590    #[test]
591    fn relatives_branch() {
592        let common_context = CommonContext::new();
593        let parse_result = parse_str(
594            "
595        subi r16, 1
596        breq pc-1
597        rjmp pc
598        ",
599            &common_context,
600        );
601        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
602
603        let build_result = build_pass_2(
604            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
605            &common_context,
606        );
607        assert_eq!(
608            build_result.unwrap(),
609            BuildResultPass2 {
610                code_start_address: 0x0,
611                code: vec![0x1, 0x50, 0xf1, 0xf3, 0xff, 0xcf],
612                eeprom_start_address: 0x0,
613                eeprom: vec![],
614                ram_filling: 0,
615                messages: vec![],
616            }
617        );
618    }
619
620    #[test]
621    fn avr8l_lds_sts() {
622        let common_context = CommonContext::new();
623        let parse_result = parse_str(
624            "
625        .device ATtiny20
626        .dseg
627counter: .byte 1
628        .cseg
629        lds r18, counter
630        inc r18
631        sts counter, r18
632        ",
633            &common_context,
634        );
635        let post_parse_result = build_pass_0(parse_result.unwrap(), &common_context);
636
637        let build_result = build_pass_2(
638            build_pass_1(post_parse_result.unwrap(), &common_context).unwrap(),
639            &common_context,
640        );
641        assert_eq!(
642            build_result.unwrap(),
643            BuildResultPass2 {
644                code_start_address: 0x0,
645                code: vec![0x20, 0xa1, 0x23, 0x95, 0x20, 0xa9],
646                eeprom_start_address: 0x0,
647                eeprom: vec![],
648                ram_filling: 1,
649                messages: vec![],
650            }
651        );
652    }
653}