c64_assembler/generator/
dasm.rs1use crate::{
2 instruction::operation::Operation,
3 memory::{
4 address_mode::{AddressMode, Immediate},
5 define::{Define, Value},
6 user_count::UserCount,
7 ZeroPage,
8 },
9 validator::AssemblerResult,
10 Application, Function, Instructions, Module,
11};
12
13use super::Generator;
14
15pub struct DasmGenerator {
17 output: Vec<String>,
18 comment_column: usize,
19}
20
21impl Default for DasmGenerator {
22 fn default() -> Self {
23 DasmGenerator {
24 output: Vec::<String>::default(),
25 comment_column: 25,
26 }
27 }
28}
29
30impl Generator for DasmGenerator {
31 type Output = String;
32
33 fn generate(mut self, application: Application) -> AssemblerResult<Self::Output> {
34 self.line(format!("; --- Application: {} ---", application.name.to_uppercase()));
35 self.line("; NOTE: This file is generated, do not modify".to_string());
36 self.line_new();
37 self.line(" processor 6502".to_string());
38 self.line_new();
39
40 for define in &application.defines {
41 if !define.user_empty() {
42 self.add_define(define);
43 }
44 }
45 self.line_new();
46 self.line(format!(" org ${:04X}", application.entry_point));
47
48 for module in &application.modules {
49 self.module(&application, module);
50 }
51
52 Ok(self.output.join("\n"))
53 }
54}
55
56impl DasmGenerator {
57 fn module(&mut self, application: &Application, module: &Module) {
58 self.line_new();
59 self.line(format!("; --- Module begin: {} ---", module.name.to_uppercase()));
60 self.instructions(application, &module.instructions);
61 for function in &module.functions {
62 self.function(application, function);
63 }
64 self.line(format!("; --- Module end: {} ---", module.name.to_uppercase()));
65 }
66
67 fn function(&mut self, application: &Application, function: &Function) {
68 self.line_new();
69 self.line(format!("; --- Function begin: {} ---", function.name.to_uppercase()));
70 self.line_new();
71 for d in &function.documentation {
72 self.line(format!("; {}", d));
73 }
74 self.line(format!("{}:", function.name));
75 self.instructions(application, &function.instructions);
76
77 self.line(format!("; --- Function end: {} ---", function.name.to_uppercase()));
78 }
79
80 fn instructions(&mut self, _application: &Application, instructions: &Instructions) {
81 for instruction in &instructions.instructions {
82 let mut line: Vec<String> = vec![];
83 if let Operation::Label(_) = &instruction.operation {
84 self.line_new();
85 } else {
86 line.push(" ".to_string());
87 }
88
89 match &instruction.operation {
91 Operation::Raw(bytes) => {
92 line.push(format!("byte ${:02X}", bytes[0]));
93 for byte in bytes.iter().skip(1) {
94 line.push(format!(", ${:02X}", byte));
95 }
96 }
97 Operation::Label(label) => line.push(format!("{}:", label)),
98 _ => {
99 line.push(instruction.operation.definition().unwrap().instruction.to_string());
100 }
101 }
102
103 match &instruction.address_mode {
105 AddressMode::Implied => {}
106 AddressMode::Immediate(immediate) => match immediate {
107 Immediate::Byte(byte) => line.push(format!(" #${byte:02X}")),
108 Immediate::Low(address_reference) => line.push(format!(" #<{}", address_reference.name)),
109 Immediate::High(address_reference) => line.push(format!(" #>{}", address_reference.name)),
110 },
111 AddressMode::Absolute(address_reference) | AddressMode::Relative(address_reference) => {
112 line.push(format!(" {}", address_reference.name));
113 if address_reference.offset != 0 {
114 line.push(format!("+{}", address_reference.offset));
115 }
116 }
117 AddressMode::AbsoluteX(address_reference) => {
118 line.push(format!(" {}", address_reference.name));
119 if address_reference.offset != 0 {
120 line.push(format!("+{}", address_reference.offset));
121 }
122 line.push(",x".to_string());
123 }
124 AddressMode::AbsoluteY(address_reference) => {
125 line.push(format!(" {}", address_reference.name));
126 if address_reference.offset != 0 {
127 line.push(format!("+{}", address_reference.offset));
128 }
129 line.push(",y".to_string());
130 }
131 AddressMode::IndexedIndirect(address_reference) => {
132 line.push(format!(" ({}", address_reference.name));
133 if address_reference.offset != 0 {
134 line.push(format!("+{}", address_reference.offset));
135 }
136 line.push("),x".to_string());
137 }
138 AddressMode::IndirectIndexed(address_reference) => {
139 line.push(format!(" ({}", address_reference.name));
140 if address_reference.offset != 0 {
141 line.push(format!("+{}", address_reference.offset));
142 }
143 line.push("),y".to_string());
144 }
145 AddressMode::Accumulator => line.push(" A".to_string()),
146 AddressMode::Indirect(address_reference) => {
147 line.push(format!(" ({}", address_reference.name));
148 if address_reference.offset != 0 {
149 line.push(format!("+{}", address_reference.offset));
150 }
151 line.push(")".to_string());
152 }
153 }
154
155 if instruction.comments.is_empty() {
156 self.line(line.join(""));
157 } else {
158 let mut line_len = line.join("").len();
159 let add_comments_before =
160 line_len > self.comment_column || matches!(&instruction.operation, Operation::Label(_label));
161
162 if add_comments_before {
163 for comment in &instruction.comments {
164 self.line(format!(" ; {}", comment));
165 }
166 self.line(line.join(""))
167 } else {
168 for comment in &instruction.comments {
169 let inset = vec![" "; self.comment_column - line_len].join("");
170 line.push(format!("{}; {}", inset, comment));
171 self.line(line.join(""));
172 line.clear();
173 line_len = 0;
174 }
175 }
176 }
177 }
178 }
179
180 fn add_define(&mut self, define: &Define) {
181 let mut line = vec![];
182 line.push(define.name.clone());
183 line.push("=".to_string());
184 match &define.value {
185 Value::Address(address) => line.push(format!("${:04X}", address)),
186 Value::Zeropage(address) => line.push(format!("${:02X}", address.low())),
187 }
188
189 self.line(line.join(" "));
190 }
191}
192
193impl DasmGenerator {
194 fn line(&mut self, line: String) {
195 self.output.push(line);
196 }
197 fn line_new(&mut self) {
198 self.output.push(String::default());
199 }
200}