c64_assembler/generator/
program.rs1use c64_assembler_6502::{
2 instruction::InstructionDef,
3 opcodes::{NO_ZEROPAGE, NO_ZEROPAGE_X, NO_ZEROPAGE_Y},
4};
5
6use crate::{
7 instruction::{operation::Operation, Instruction},
8 memory::{
9 address_mode::{AddressMode, Immediate},
10 Address, ZeroPage,
11 },
12 validator::{AssemblerResult, Error},
13 Application, Instructions, Module,
14};
15
16use super::Generator;
17
18const PROGRAM_HEADER_BYTE_SIZE: Address = 2;
19
20#[derive(Default, Debug)]
22pub struct ProgramGenerator {
23 output: Vec<u8>,
24}
25
26impl Generator for ProgramGenerator {
27 type Output = Vec<u8>;
28
29 fn generate(mut self, application: Application) -> AssemblerResult<Self::Output> {
30 self.add_u16(application.entry_point);
31 for module in &application.modules {
32 self.generate_module(&application, module)?;
33 }
34 Ok(self.output)
35 }
36}
37
38impl ProgramGenerator {
39 fn generate_module(&mut self, application: &Application, module: &Module) -> AssemblerResult<()> {
40 self.generate_instructions(application, &module.instructions)?;
41 for function in &module.functions {
42 self.generate_instructions(application, &function.instructions)?;
43 }
44 Ok(())
45 }
46
47 fn generate_instructions(&mut self, application: &Application, instructions: &Instructions) -> AssemblerResult<()> {
48 for instruction in &instructions.instructions {
49 self.generate_instruction(application, instruction)?;
50 }
51 Ok(())
52 }
53
54 fn generate_instruction(&mut self, application: &Application, instruction: &Instruction) -> AssemblerResult<()> {
55 match (&instruction.operation.definition(), &instruction.operation) {
56 (Some(definition), _) => self.add_byte_code(application, &instruction.address_mode, definition),
57 (None, Operation::Label(_)) => {
58 Ok(())
60 }
61 (None, Operation::Raw(bytes)) => {
62 self.add_bytes(bytes);
63 Ok(())
64 }
65
66 (_, _) => Err(Error::InternalCompilerError),
67 }
68 }
69
70 fn add_byte_code(
71 &mut self,
72 application: &Application,
73 address_mode: &AddressMode,
74 instruction: &InstructionDef,
75 ) -> AssemblerResult<()> {
76 match address_mode {
77 AddressMode::Implied => {
78 self.add_u8(instruction.implied);
79 }
80 AddressMode::Immediate(Immediate::Byte(byte)) => {
81 self.add_u8(instruction.immediate);
82 self.add_u8(*byte);
83 }
84 AddressMode::Immediate(Immediate::Low(address_reference)) => {
85 self.add_u8(instruction.immediate);
86 self.add_u8(application.address(address_reference).low());
87 }
88 AddressMode::Immediate(Immediate::High(address_reference)) => {
89 self.add_u8(instruction.immediate);
90 self.add_u8(application.address(address_reference).high());
91 }
92 AddressMode::Accumulator => {
93 self.add_u8(instruction.accumulator);
94 }
95 AddressMode::Absolute(address_reference) => {
96 let address = application.address(address_reference);
97 if instruction.zeropage != NO_ZEROPAGE && address.is_zeropage() {
98 self.add_u8(instruction.zeropage);
99 self.add_u8(application.address(address_reference).low());
100 } else {
101 self.add_u8(instruction.absolute);
102 self.add_u16(address);
103 }
104 }
105 AddressMode::AbsoluteX(address_reference) => {
106 let address = application.address(address_reference);
107 if instruction.zeropage_x != NO_ZEROPAGE_X && address.is_zeropage() {
108 self.add_u8(instruction.zeropage_x);
109 self.add_u8(address.low());
110 } else {
111 self.add_u8(instruction.absolute_x);
112 self.add_u16(address);
113 }
114 }
115 AddressMode::AbsoluteY(address_reference) => {
116 let address = application.address(address_reference);
117 if instruction.zeropage_y != NO_ZEROPAGE_Y && address.is_zeropage() {
118 self.add_u8(instruction.zeropage_y);
119 self.add_u8(address.low());
120 } else {
121 self.add_u8(instruction.absolute_y);
122 self.add_u16(address);
123 }
124 }
125 AddressMode::Relative(address_reference) => {
126 let current_instruction =
127 application.entry_point + self.output.len() as Address - PROGRAM_HEADER_BYTE_SIZE;
128 let address = application.address(address_reference);
129 let next_instruction = current_instruction + address_mode.byte_size(application)?;
130 let relative_address = (address as i32 - next_instruction as i32) as i8;
131
132 self.add_u8(instruction.relative);
133 self.add_u8(relative_address as u8);
134 }
135 AddressMode::Indirect(address_reference) => {
136 let address = application.address(address_reference);
137 self.add_u8(instruction.indirect);
138 self.add_u16(address);
139 }
140 AddressMode::IndexedIndirect(address_reference) => {
141 let address = application.address(address_reference);
142 assert!(address.is_zeropage());
143 self.add_u8(instruction.indexed_indirect);
144 self.add_u8(address.low());
145 }
146 AddressMode::IndirectIndexed(address_reference) => {
147 let address = application.address(address_reference);
148 self.add_u8(instruction.indirect_indexed);
149 self.add_u8(address.low());
150 }
151 };
152 Ok(())
153 }
154}
155
156impl ProgramGenerator {
157 fn add_u8(&mut self, byte: u8) {
158 self.output.push(byte);
159 }
160
161 fn add_u16(&mut self, address: Address) {
162 self.add_u8(address.low());
163 self.add_u8(address.high());
164 }
165
166 fn add_bytes(&mut self, bytes: &[u8]) {
167 for byte in bytes {
168 self.output.push(*byte);
169 }
170 }
171}
172
173pub fn print_hexdump(bytes: &[u8]) {
175 let mut address = 0;
176 bytes.chunks(16).for_each(|chunk| {
177 let mut line = Vec::new();
178
179 line.push(format!("{:04X}: ", address));
180 address += 16;
181
182 chunk.chunks(4).for_each(|chunk| {
183 chunk.iter().for_each(|byte| {
184 line.push(format!("{:02X}", byte));
185 });
186 line.push("".to_string());
187 });
188 println!("{}", line.join(" ").trim_end());
189 });
190}