- Everything has been rewritten - Modularity is improved somewhat - No dependency injection in preprocessor/parser, though - There are now early and late constant evaluation engines - This engine allows for by-value access to already-assembled code - Performs basic math operations, remainder, bitwise logic, bit shifts, negation, and bit inversion - Also allows for indexing into already-generated code using pointer-arithmetic syntax: `*(&main + 10)`. This is subject to change? It's clunky, and only allows word-aligned access. However, this rewrite is taking far too long, so I'll call the bikeshedding here. - Pretty sure this constant evaluation is computationally equivalent to Deadfish?
109 lines
3.9 KiB
Rust
109 lines
3.9 KiB
Rust
// © 2023 John Breaux
|
|
//! A bare-bones toy assembler for the TI MSP430, for use in MicroCorruption
|
|
//!
|
|
//! This project aims to assemble any valid msp430 instructions, while being lenient about the
|
|
//! syntax. After all, a real-world parser is going to face all kinds of malformed input, and it
|
|
//! would be nice to support that kind of input (or, if it's completely unsalvageable, provide a
|
|
//! useful message to the author.)
|
|
//!
|
|
//! The [`Parser`](preamble::Parser) will ignore whitespace, excluding newlines,
|
|
//! unless syntactically relevant. It will also discard comma-separators between operands of a
|
|
//! two-operand instruction.
|
|
//!
|
|
//! It returns an AST structured as follows
|
|
//! ```text
|
|
//! Root
|
|
//! ├─ Line
|
|
//! │ └─ Empty
|
|
//! ├─ Line
|
|
//! │ └─ Comment
|
|
//! ├─ Line
|
|
//! │ └─ Directive // Pre- or Post-processor directive
|
|
//! ├─ Linel
|
|
//! │ └─ Label // Label definition
|
|
//! ├─ Line
|
|
//! │ └─ Instruction
|
|
//! │ ├─ Opcode
|
|
//! │ └─ Encoding::Single
|
|
//! │ ├─ Width
|
|
//! │ └─ PrimaryOperand
|
|
//! │ ├─ Identifier // Label, for relative-addressed data/code
|
|
//! │ ├─ Register // Direct, indexed, indirect or indirect-post-increment register.
|
|
//! │ └─ Number // Index, absolute address or immediate value.
|
|
//! ├─ Line
|
|
//! │ └─ Instruction
|
|
//! │ ├─ Opcode
|
|
//! │ └─ Encoding::Double
|
|
//! │ ├─ Width
|
|
//! │ ├─ PrimaryOperand
|
|
//! │ ├─ Identifier // Label, for relative-addressed data/code
|
|
//! │ │ ├─ Register // Direct, indexed, indirect or indirect-post-increment register.
|
|
//! │ │ └─ Number // Index, absolute address or immediate value.
|
|
//! │ └─ SecondaryOperand
|
|
//! │ ├─ Identifier // Label, for relative-addressed data/code
|
|
//! │ ├─ Register // Direct or indexed register
|
|
//! │ └─ Number // Index or absolute address
|
|
//! ├─ Line
|
|
//! │ └─ Instruction
|
|
//! │ ├─ Opcode
|
|
//! │ └─ Encoding::Jump
|
|
//! │ └─ JumpTarget
|
|
//! │ ├─ Identifier // Label
|
|
//! │ └─ Number // Even, PC-relative offset in range (-1024..=1022)
|
|
//! └─ Line
|
|
//! └─ EndOfFile
|
|
//! ```
|
|
|
|
pub mod util {
|
|
use std::{
|
|
fmt::{Debug, Display},
|
|
ops::{Index, Range},
|
|
};
|
|
/// A <code> [Clone] + [Copy] + [!Iterator](Iterator) <\code> version of a [Range]
|
|
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub struct Span<Idx> {
|
|
pub start: Idx,
|
|
pub end: Idx,
|
|
}
|
|
impl<Idx> From<Span<Idx>> for Range<Idx> {
|
|
fn from(value: Span<Idx>) -> Self {
|
|
value.start..value.end
|
|
}
|
|
}
|
|
impl<Idx> From<Range<Idx>> for Span<Idx> {
|
|
fn from(value: Range<Idx>) -> Self {
|
|
Self { start: value.start, end: value.end }
|
|
}
|
|
}
|
|
impl<T> Index<Span<usize>> for [T] {
|
|
type Output = [T];
|
|
fn index(&self, index: Span<usize>) -> &Self::Output {
|
|
self.index(Range::from(index))
|
|
}
|
|
}
|
|
impl Index<Span<usize>> for str {
|
|
type Output = str;
|
|
fn index(&self, index: Span<usize>) -> &Self::Output {
|
|
self.index(Range::from(index))
|
|
}
|
|
}
|
|
impl<Idx: Debug> Debug for Span<Idx> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{:?}..{:?}", self.start, self.end)
|
|
}
|
|
}
|
|
impl<Idx: Display> Display for Span<Idx> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}..{}", self.start, self.end)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod lexer;
|
|
|
|
pub mod preprocessor;
|
|
|
|
pub mod parser;
|
|
|
|
pub mod assembler;
|