c64_assembler/builder/
finalize.rs1use 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 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 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}