c64_assembler/builder/
finalize.rs

1use std::collections::HashMap;
2
3use crate::{
4    instruction::operation::Operation,
5    memory::{
6        address_mode::{AddressMode, Immediate},
7        user_count::UserCount,
8        Address,
9    },
10    validator::AssemblerResult,
11    Application, Instructions,
12};
13
14pub fn finalize(application: &mut Application) -> AssemblerResult<()> {
15    defines_update_user_count(application);
16    functions_update_user_count(application);
17    update_label_addresses(application)
18}
19
20fn defines_update_user_count(application: &mut Application) {
21    let mut define_users = HashMap::new();
22    for define in &application.defines {
23        let user_count = count_users(application, &define.name);
24        if user_count > 0 {
25            define_users.insert(define.name.clone(), user_count);
26        }
27    }
28
29    for (define_name, user_count) in define_users {
30        let define = application.define_mut(&define_name);
31        for _ in 0..user_count {
32            define.user_increase();
33        }
34    }
35}
36
37fn functions_update_user_count(application: &mut Application) {
38    let mut function_users = HashMap::new();
39    for module in &application.modules {
40        for function in &module.functions {
41            let user_count = count_users(application, &function.name);
42            if user_count > 0 {
43                function_users.insert(function.name.clone(), user_count);
44            }
45        }
46    }
47
48    for module in &mut application.modules {
49        for function in &mut module.functions {
50            if let Some(user_count) = function_users.get(&function.name) {
51                for _ in 0..*user_count {
52                    function.user_increase();
53                }
54            }
55        }
56    }
57}
58
59fn count_users(application: &Application, name: &String) -> usize {
60    let mut result = 0;
61    for module in &application.modules {
62        result += count_users_instructions(&module.instructions, name);
63        for function in &module.functions {
64            result += count_users_instructions(&function.instructions, name);
65        }
66    }
67    result
68}
69
70fn count_users_instructions(instructions: &Instructions, name: &String) -> usize {
71    let mut result = 0;
72    for instruction in &instructions.instructions {
73        match &instruction.address_mode {
74            AddressMode::Absolute(address_reference)
75            | AddressMode::AbsoluteX(address_reference)
76            | AddressMode::AbsoluteY(address_reference)
77            | AddressMode::Indirect(address_reference)
78            | AddressMode::IndexedIndirect(address_reference)
79            | AddressMode::IndirectIndexed(address_reference)
80            | AddressMode::Immediate(Immediate::Low(address_reference))
81            | AddressMode::Immediate(Immediate::High(address_reference))
82            | AddressMode::Relative(address_reference) => {
83                if &address_reference.name == name {
84                    result += 1;
85                }
86            }
87
88            AddressMode::Immediate(Immediate::Byte(_))
89            | crate::memory::address_mode::AddressMode::Implied
90            | AddressMode::Accumulator => {}
91        }
92    }
93    result
94}
95
96fn update_label_addresses(application: &mut Application) -> AssemblerResult<()> {
97    // First go over all labels and add dummy addresses to the application address lookup.
98    // This will ensure that the correct instruction byte size can be determined.
99    let mut label_addresses = HashMap::<String, Address>::default();
100    let mut function_addresses = HashMap::<String, Address>::default();
101
102    let mut init_label_addresses = |instructions: &Instructions| {
103        for instruction in &instructions.instructions {
104            if let Operation::Label(label) = &instruction.operation {
105                label_addresses.insert(label.clone(), 0xFFFF);
106            }
107        }
108    };
109    for module in &application.modules {
110        init_label_addresses(&module.instructions);
111        for function in &module.functions {
112            function_addresses.insert(function.name.clone(), 0xFFFF);
113            init_label_addresses(&function.instructions);
114        }
115    }
116    application.address_lookup.extend(label_addresses);
117    application.address_lookup.extend(function_addresses);
118
119    // Now go over all the labels again and determine the correct address.
120    let mut label_addresses = HashMap::<String, Address>::default();
121    let mut function_addresses = HashMap::<String, Address>::default();
122    let mut current_address = application.entry_point;
123
124    let mut update_label_addresses_instructions =
125        |current_address: &mut Address, instructions: &Instructions| -> AssemblerResult<()> {
126            for instruction in &instructions.instructions {
127                if let Operation::Label(label) = &instruction.operation {
128                    label_addresses.insert(label.clone(), *current_address);
129                }
130                let byte_size = instruction.byte_size(application)?;
131                *current_address += byte_size;
132            }
133            Ok(())
134        };
135
136    for module in &application.modules {
137        update_label_addresses_instructions(&mut current_address, &module.instructions)?;
138        for function in &module.functions {
139            function_addresses.insert(function.name.clone(), current_address);
140            update_label_addresses_instructions(&mut current_address, &function.instructions)?;
141        }
142    }
143
144    application.address_lookup.extend(label_addresses);
145    application.address_lookup.extend(function_addresses);
146    Ok(())
147}