avra_lib/builder/
mod.rs

1//! Contains zero, first and second pass builder of AVRA-rs
2
3pub mod pass0;
4pub mod pass1;
5pub mod pass2;
6
7use crate::{
8    builder::{
9        pass0::build_pass_0 as pass0, pass1::build_pass_1 as pass1, pass2::build_pass_2 as pass2,
10    },
11    context::{CommonContext, Context},
12    parser::{parse_file, parse_str, ParseResult, Paths},
13};
14
15use failure::{bail, Error};
16use std::path::PathBuf;
17
18#[derive(Clone, PartialEq, Eq, Debug)]
19pub struct BuildResult {
20    pub code: Vec<u8>,
21    pub eeprom: Vec<u8>,
22
23    pub flash_size: u32,
24    pub eeprom_size: u32,
25    pub ram_size: u32,
26    pub ram_filling: u32,
27
28    pub messages: Vec<String>,
29}
30
31fn build_from_parsed(
32    parsed: ParseResult,
33    common_context: &CommonContext,
34) -> Result<BuildResult, Error> {
35    let passed_0 = pass0(parsed, common_context)?;
36
37    let passed_1 = pass1(passed_0, common_context)?;
38
39    let passed_2 = pass2(passed_1, common_context)?;
40
41    let device = common_context.get_device();
42
43    if passed_2.code.len() as u32 > device.flash_size * 2 {
44        bail!(
45            "Flash size overdue by {} bytes",
46            passed_2.code.len() as u32 - device.flash_size * 2
47        )
48    }
49
50    if passed_2.eeprom.len() as u32 > device.eeprom_size {
51        bail!(
52            "Eeprom size overdue by {} bytes",
53            passed_2.eeprom.len() as u32 - device.eeprom_size
54        )
55    }
56
57    if passed_2.ram_filling > device.ram_size {
58        bail!(
59            "RAM size overdue by {} bytes",
60            passed_2.ram_filling - device.ram_size
61        )
62    }
63
64    Ok(BuildResult {
65        code: passed_2.code,
66        eeprom: passed_2.eeprom,
67        flash_size: device.flash_size,
68        eeprom_size: device.eeprom_size,
69        ram_size: device.ram_size,
70        ram_filling: passed_2.ram_filling,
71        messages: passed_2.messages,
72    })
73}
74
75pub fn build_str(source: &str) -> Result<BuildResult, Error> {
76    let common_context = CommonContext::new();
77
78    let parsed = parse_str(source, &common_context)?;
79
80    build_from_parsed(parsed, &common_context)
81}
82
83pub fn build_file(path: PathBuf, paths: Paths) -> Result<BuildResult, Error> {
84    let common_context = CommonContext::new();
85
86    let parsed = parse_file(path, paths, &common_context)?;
87
88    build_from_parsed(parsed, &common_context)
89}
90
91#[cfg(test)]
92mod builder_tests {
93    use super::*;
94    use crate::utility::get_standard_includes;
95    use maplit::btreeset;
96    use std::path::PathBuf;
97
98    #[test]
99    fn check_empty() {
100        let built = build_str("").unwrap();
101
102        assert_eq!(
103            built,
104            BuildResult {
105                code: vec![],
106                eeprom: vec![],
107                flash_size: 4194304,
108                eeprom_size: 65536,
109                ram_size: 8388608,
110                ram_filling: 0,
111                messages: vec![],
112            }
113        );
114    }
115
116    #[test]
117    fn check_main_options() {
118        let asm_code = "
119        .cseg
120        .org 0x0
121        .equ end = 0x42
122        push r0
123m_begin:
124        mov r17, r0
125        subi r17, (-1)
126        brpl m0
127        rjmp m_begin
128
129m0:     pop r1
130        ldi r30, low (data)
131        ldi r31, high(data)
132        lpm r16, Z+
133        rjmp m1
134data:   .db 15, 26, \"Hello, World\", end
135data_w:
136        .dw 0xff44, end, 0xda4e
137m1:
138        ldi r18, data_w
139        ";
140
141        let built = build_str(asm_code).unwrap();
142
143        let code = vec![
144            0xf, 0x92, 0x10, 0x2d, 0x1f, 0x5f, 0xa, 0xf4, 0xfc, 0xcf, 0x1f, 0x90, 0xea, 0xe0, 0xf0,
145            0xe0, 0x5, 0x91, 0xb, 0xc0, 0xf, 0x1a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57,
146            0x6f, 0x72, 0x6c, 0x64, 0x42, 0x0, 0x44, 0xff, 0x42, 0x0, 0x4e, 0xda, 0x22, 0xe1,
147        ];
148
149        let build_success_result = BuildResult {
150            code: code.clone(),
151            eeprom: vec![],
152            flash_size: 4194304,
153            eeprom_size: 65536,
154            ram_size: 8388608,
155            ram_filling: 0,
156            messages: vec![],
157        };
158
159        assert_eq!(built, build_success_result);
160
161        let build_success_result = BuildResult {
162            code: code.clone(),
163            eeprom: vec![],
164            flash_size: 2048,
165            eeprom_size: 256,
166            ram_size: 512,
167            ram_filling: 0,
168            messages: vec![
169                "info: This simple test displays basic assembler constructions. in line: 1"
170                    .to_string(),
171            ],
172        };
173
174        let built = build_file(
175            PathBuf::from("tests/builder_simple.asm"),
176            btreeset! { PathBuf::from("includes") },
177        )
178        .unwrap();
179
180        assert_eq!(built, build_success_result);
181
182        let built = build_file(
183            PathBuf::from("tests/builder_simple.asm"),
184            btreeset! { get_standard_includes() },
185        )
186        .unwrap();
187
188        assert_eq!(built, build_success_result);
189    }
190}