nand7400/assembler/
config.rs

1use super::parser::ast::{Argument, ArgumentKind};
2use serde::{Deserialize, Serialize};
3
4/// The main configuration type for the assembler.
5#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
6pub struct AssemblerConfig {
7    /// The opcodes to be used by the assembler.
8    pub opcodes: Vec<Opcode>,
9}
10
11/// Public API for the assembler configuration.
12impl AssemblerConfig {
13    /// Gets an opcode by its name.
14    pub fn get_opcode(&self, mnemonic: &str) -> Option<&Opcode> {
15        self.opcodes
16            .iter()
17            .find(|opcode| opcode.mnemonic == mnemonic)
18    }
19}
20
21/// An opcode to be parsed by the assembler.
22#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
23pub struct Opcode {
24    /// The name of the opcode.
25    pub mnemonic: String,
26
27    /// The binary representation of the opcode, as a byte.
28    pub binary: u8,
29
30    /// The list of arguments for the opcode. If this list is empty, then the opcode has no arguments.
31    /// Note that this does not map to the literal count of arguments (i.e. `len(args)`), but rather the
32    /// length of the arguments in bytes. For example, labels are 1 argument but map to 2 bytes.
33    pub args: Vec<OpcodeArg>,
34}
35
36/// The argument kind for an opcode.
37#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
38pub enum OpcodeArg {
39    /// A indirect number.
40    Indirect,
41
42    /// A direct/immediate number.
43    Immediate,
44}
45
46impl<T> From<&Argument<T>> for OpcodeArg {
47    fn from(arg: &Argument<T>) -> Self {
48        match arg.kind {
49            ArgumentKind::IndirectNumber(_) => Self::Indirect,
50            ArgumentKind::ImmediateNumber(_) | ArgumentKind::Label(_) => Self::Immediate,
51        }
52    }
53}