portal_solutions_mos6502_assembler/
lib.rs1#![no_std]
2extern crate alloc;
3
4use alloc::{collections::btree_map::BTreeMap, string::{String, ToString}, vec::Vec};
5use portal_solutions_mos6502_model::*;
6
7
8enum Data {
9 LiteralByte(u8),
10 LabelOffsetLe(String),
11 LiteralOffsetLe(Address),
12 LiteralAddressLe(Address),
13 LabelOffsetLo(String),
14 LabelOffsetHi(String),
15 LabelRelativeOffset(String),
16}
17
18struct DataAtOffset {
19 data: Data,
20 offset: Address,
21}
22
23pub struct Block {
24 cursor_offset: Address,
25 program: Vec<DataAtOffset>,
26 labels: BTreeMap<String, Address>,
27}
28
29pub trait ArgOperand {
30 type Operand: operand::Trait;
31 fn program(self, block: &mut Block);
32}
33
34impl ArgOperand for &'static str {
35 type Operand = operand::Address;
36 fn program(self, block: &mut Block) {
37 block.label_offset_le(self);
38 }
39}
40
41impl ArgOperand for String {
42 type Operand = operand::Address;
43 fn program(self, block: &mut Block) {
44 block.label_offset_le(self);
45 }
46}
47
48impl ArgOperand for Address {
49 type Operand = operand::Address;
50 fn program(self, block: &mut Block) {
51 block.literal_address_le(self);
52 }
53}
54
55impl ArgOperand for u8 {
56 type Operand = operand::Byte;
57 fn program(self, block: &mut Block) {
58 block.literal_byte(self);
59 }
60}
61
62impl ArgOperand for i8 {
63 type Operand = operand::Byte;
64 fn program(self, block: &mut Block) {
65 block.literal_byte(self as u8);
66 }
67}
68
69pub struct Addr(pub Address);
70
71impl ArgOperand for Addr {
72 type Operand = operand::Address;
73 fn program(self, block: &mut Block) {
74 block.literal_address_le(self.0);
75 }
76}
77
78impl ArgOperand for i32 {
82 type Operand = operand::Byte;
83 fn program(self, block: &mut Block) {
84 assert!(self >= -128 && self <= 255, "{} is not a valid byte", self);
87 block.literal_byte((self as i8) as u8);
88 }
89}
90
91impl ArgOperand for () {
92 type Operand = operand::None;
93 fn program(self, _block: &mut Block) {}
94}
95
96pub struct LabelOffsetLo(pub &'static str);
97pub struct LabelOffsetHi(pub &'static str);
98pub struct LabelRelativeOffset(pub &'static str);
99pub struct LabelRelativeOffsetOwned(pub String);
100
101impl ArgOperand for LabelOffsetLo {
102 type Operand = operand::Byte;
103 fn program(self, block: &mut Block) {
104 block.label_offset_lo(self.0);
105 }
106}
107
108impl ArgOperand for LabelOffsetHi {
109 type Operand = operand::Byte;
110 fn program(self, block: &mut Block) {
111 block.label_offset_hi(self.0);
112 }
113}
114
115impl ArgOperand for LabelRelativeOffset {
116 type Operand = operand::Byte;
117 fn program(self, block: &mut Block) {
118 block.label_relative_offset(self.0);
119 }
120}
121
122impl ArgOperand for LabelRelativeOffsetOwned {
123 type Operand = operand::Byte;
124 fn program(self, block: &mut Block) {
125 block.label_relative_offset(self.0.as_str());
126 }
127}
128
129#[derive(Debug, Clone)]
130pub enum Error {
131 OffsetOutOfBounds,
132 UndeclaredLabel(String),
133 BranchTargetOutOfRange(String),
134}
135
136impl Block {
137 pub fn new() -> Self {
138 Self {
139 cursor_offset: 0,
140 program: Vec::new(),
141 labels: BTreeMap::new(),
142 }
143 }
144 pub fn set_offset(&mut self, offset: Address) {
145 self.cursor_offset = offset;
146 }
147 pub fn literal_byte(&mut self, byte: u8) {
148 self.program.push(DataAtOffset {
149 data: Data::LiteralByte(byte),
150 offset: self.cursor_offset,
151 });
152 self.cursor_offset = self.cursor_offset.wrapping_add(1);
153 }
154 pub fn literal_offset_le(&mut self, offset: Address) {
155 self.program.push(DataAtOffset {
156 data: Data::LiteralOffsetLe(offset),
157 offset: self.cursor_offset,
158 });
159 self.cursor_offset = self.cursor_offset.wrapping_add(2);
160 }
161 pub fn literal_address_le(&mut self, offset: Address) {
162 self.program.push(DataAtOffset {
163 data: Data::LiteralAddressLe(offset),
164 offset: self.cursor_offset,
165 });
166 self.cursor_offset = self.cursor_offset.wrapping_add(2);
167 }
168 pub fn label_offset_le<S: AsRef<str>>(&mut self, label: S) {
169 let string = label.as_ref().to_string();
170 self.program.push(DataAtOffset {
171 data: Data::LabelOffsetLe(string),
172 offset: self.cursor_offset,
173 });
174 self.cursor_offset = self.cursor_offset.wrapping_add(2);
175 }
176 pub fn label_offset_lo<S: AsRef<str>>(&mut self, label: S) {
177 let string = label.as_ref().to_string();
178 self.program.push(DataAtOffset {
179 data: Data::LabelOffsetLo(string),
180 offset: self.cursor_offset,
181 });
182 self.cursor_offset = self.cursor_offset.wrapping_add(1);
183 }
184 pub fn label_offset_hi<S: AsRef<str>>(&mut self, label: S) {
185 let string = label.as_ref().to_string();
186 self.program.push(DataAtOffset {
187 data: Data::LabelOffsetHi(string),
188 offset: self.cursor_offset,
189 });
190 self.cursor_offset = self.cursor_offset.wrapping_add(1);
191 }
192 pub fn label_relative_offset<S: AsRef<str>>(&mut self, label: S) {
193 let string = label.as_ref().to_string();
194 self.program.push(DataAtOffset {
195 data: Data::LabelRelativeOffset(string),
196 offset: self.cursor_offset,
197 });
198 self.cursor_offset = self.cursor_offset.wrapping_add(1);
199 }
200 pub fn label<S: AsRef<str>>(&mut self, s: S) {
201 let string = s.as_ref().to_string();
202 if self.labels.insert(string, self.cursor_offset).is_some() {
203 panic!("Multiple definitions of label {}", s.as_ref());
204 }
205 }
206 pub fn inst<
207 I: AssemblerInstruction,
208 A: ArgOperand<Operand = <I::AddressingMode as addressing_mode::Trait>::Operand>,
209 >(
210 &mut self,
211 instruction: I,
212 arg: A,
213 ) {
214 let _ = instruction;
215 self.literal_byte(I::opcode());
216 arg.program(self);
217 }
218 pub fn infinite_loop(&mut self) {
219 let offset = self.cursor_offset;
220 self.literal_byte(assembler_instruction::Jmp::<addressing_mode::Absolute>::opcode());
221 self.literal_offset_le(offset);
222 }
223 pub fn assemble(
224 &self,
225 base: Address,
226 size: usize,
227 buffer: &mut Vec<u8>,
228 ) -> Result<AssembledBlock, Error> {
229 let mut labels = BTreeMap::new();
230 for (label, address) in self.labels.iter() {
231 labels.insert(label.clone(), address + base);
232 }
233 buffer.resize(size, 0);
234 for &DataAtOffset { offset, ref data } in self.program.iter() {
235 match data {
236 &Data::LiteralByte(byte) => {
237 if offset as usize >= size {
238 return Err(Error::OffsetOutOfBounds);
239 }
240 buffer[offset as usize] = byte;
241 }
242 Data::LabelOffsetLe(label) => {
243 if let Some(&label_offset) = self.labels.get(label) {
244 if offset as usize + 1 >= size {
245 return Err(Error::OffsetOutOfBounds);
246 }
247 let address = label_offset + base;
248 buffer[offset as usize] = address::lo(address);
249 buffer[offset as usize + 1] = address::hi(address);
250 } else {
251 return Err(Error::UndeclaredLabel(label.clone()));
252 }
253 }
254 Data::LiteralOffsetLe(literal_offset) => {
255 if offset as usize + 1 >= size {
256 return Err(Error::OffsetOutOfBounds);
257 }
258 let address = literal_offset + base;
259 buffer[offset as usize] = address::lo(address);
260 buffer[offset as usize + 1] = address::hi(address);
261 }
262 &Data::LiteralAddressLe(address) => {
263 buffer[offset as usize] = address::lo(address);
264 buffer[offset as usize + 1] = address::hi(address);
265 }
266 Data::LabelOffsetLo(label) => {
267 if let Some(&label_offset) = self.labels.get(label) {
268 if offset as usize + 1 >= size {
269 return Err(Error::OffsetOutOfBounds);
270 }
271 let address = label_offset + base;
272 buffer[offset as usize] = address::lo(address);
273 } else {
274 return Err(Error::UndeclaredLabel(label.clone()));
275 }
276 }
277 Data::LabelOffsetHi(label) => {
278 if let Some(&label_offset) = self.labels.get(label) {
279 if offset as usize + 1 >= size {
280 return Err(Error::OffsetOutOfBounds);
281 }
282 let address = label_offset + base;
283 buffer[offset as usize] = address::hi(address);
284 } else {
285 return Err(Error::UndeclaredLabel(label.clone()));
286 }
287 }
288 Data::LabelRelativeOffset(label) => {
289 if let Some(&label_offset) = self.labels.get(label) {
290 let delta = label_offset as i16 - offset as i16 - 1;
291 if delta < -128 || delta > 127 {
292 return Err(Error::BranchTargetOutOfRange(label.clone()));
293 }
294 buffer[offset as usize] = (delta as i8) as u8;
295 } else {
296 return Err(Error::UndeclaredLabel(label.clone()));
297 }
298 }
299 }
300 }
301 Ok(AssembledBlock { labels })
302 }
303}
304
305pub struct AssembledBlock {
306 labels: BTreeMap<String, Address>,
307}
308
309impl AssembledBlock {
310 pub fn address_of_label(&self, label: &str) -> Option<Address> {
311 self.labels.get(label).cloned()
312 }
313}