A modular, extensible assembler supporting multiple CPU architectures through YAML-based CPU profiles. Currently supports 65C02 and Motorola 6800 with easy extensibility for additional architectures.
- YAML Format Support: CPU architectures defined in YAML format
- Multi-CPU Support: Currently supports 65C02 and Motorola 6800 architectures
- Easy Extensibility: Add new CPUs by creating YAML profiles - no code changes needed
- Two-Pass Assembly: Efficient symbol resolution and error detection
- Enhanced Error Reporting: Detailed warnings and error messages for common assembly mistakes
- Generic Validation Engine: Rule-based validation system that's fully CPU-agnostic
- Expression Evaluation: Support for complex expressions with operators and symbols
- Comprehensive Testing: Full test suite with profile validation
- Independent Testing: CPU profiles can be validated without running the assembler
- Clone the repository:
git clone https://github.com/yourusername/multi-cpu-assembler.git
cd multi-cpu-assembler- Set up the virtual environment:
python3 -m venv compiler/.venv
source compiler/.venv/bin/activate # On Windows: compiler\.venv\Scripts\activate
pip install sly PyYAMLAssemble a source file:
python compiler/main.py source_file.s -o output.bin --cpu 65c02Example assembly file (hello_65c02.s):
; Simple 65C02 program
.ORG $8000
START: LDA #$48 ; 'H'
JSR $FFD2 ; Print character
LDA #$45 ; 'E'
JSR $FFD2
LDA #$4C ; 'L'
JSR $FFD2
LDA #$4C ; 'L'
JSR $FFD2
LDA #$4F ; 'O'
JSR $FFD2
RTS
.END- Profiles:
compiler/cpu_profiles/65c02.yaml(YAML) - Instructions: 64 mnemonics, 178 total opcodes
- Addressing Modes: 14 modes (IMPLIED, IMMEDIATE, ABSOLUTE, etc.)
- Features: Full 65C02 instruction set with enhanced error checking
- Profiles:
compiler/cpu_profiles/6800.yaml(YAML) - Instructions: 27 mnemonics, 61 total opcodes
- Addressing Modes: 8 modes (INHERENT, IMMEDIATE, EXTENDED, etc.)
- Features: Complete 6800 instruction set with accumulator operations
New CPU architectures can be added by creating YAML profiles in compiler/cpu_profiles/. No code changes required! See TESTING.md for profile validation tools.
The assembler follows a clean, modular architecture with YAML-driven CPU profiles:
Project Root/
├── compiler/
│ ├── main.py (Entry Point)
│ ├── cpu_profile_base.py (YAML profile loader)
│ ├── core/ (Core assembler components)
│ │ ├── parser.py (Source parsing)
│ │ ├── assembler.py (Two-pass assembly)
│ │ ├── emitter.py (Output generation)
│ │ ├── diagnostics.py (Error reporting)
│ │ ├── expression_evaluator.py (Expression evaluation)
│ │ ├── expression_parser.py (Expression parsing)
│ │ ├── instruction.py (Instruction representation)
│ │ ├── program.py (Program representation)
│ │ └── symbol_table.py (Symbol management)
│ └── cpu_profiles/ (CPU definitions)
│ ├── 65c02.yaml (65C02 CPU definition)
│ ├── 6800.yaml (6800 CPU definition)
│ └── [new_cpu].yaml (Add your own CPU!)
├── tests/ (Test suite)
│ ├── test_assembler.py (Core assembler tests)
│ ├── test_yaml_cpu_profiles.py (Profile tests)
│ ├── test_end_to_end_65c02.py (65C02 integration tests)
│ ├── test_end_to_end_6800.py (6800 integration tests)
│ └── test_*.s (Test assembly files)
├── examples/ (Example programs)
│ ├── mcu65c02.s (65C02 LED blink example)
│ └── mcu6800.s (6800 PIA example)
└── docs/ (Documentation)
├── README.md (Main documentation)
├── TESTING.md (Testing guide)
├── CONTRIBUTING.md (Contribution guidelines)
└── YAML_MIGRATION.md (Migration guide)
- Parser: Converts assembly source into structured instructions with proper syntax validation
- Assembler: Performs two-pass assembly with symbol resolution and error handling
- Emitter: Generates binary output and assembly listings with address information
- Diagnostics: Centralized error and warning reporting with detailed messages
- Expression Evaluator: Handles complex expressions, symbol resolution, and mathematical operations
- Expression Parser: SLY-based parser for assembly expressions with operator precedence
- Instruction: Represents assembly instructions with metadata and machine code
- Program: Manages instruction sequences and assembly state
- Symbol Table: Handles label definitions, symbol resolution, and EQU directives
- ConfigCPUProfile: Loads and validates YAML CPU profiles with automatic format detection
- CPUProfileFactory: Simple factory that creates ConfigCPUProfile instances from YAML files
- CPU Profiles: YAML files defining opcodes, addressing modes, directives, and validation rules
- Rule-based System: Validates instructions without CPU-specific code
- Multiple Rule Types: Mode validation, range checking, register-specific rules
- Template-driven: All validation logic defined in YAML, not Python code
- Backward Compatible: Supports legacy validation format alongside new generic rules
- Unit Tests: Core component testing with mocking and isolation
- Integration Tests: End-to-end assembly workflow validation
- Profile Tests: YAML CPU profile validation and functionality testing
- Test Data: Comprehensive assembly files for various scenarios
multi-cpu-assembler/
├── compiler/ # Main assembler package
│ ├── main.py # CLI entry point and application bootstrap
│ ├── cpu_profile_base.py # YAML profile loader and factory
│ ├── core/ # Core assembler components
│ │ ├── assembler.py # Two-pass assembly engine
│ │ ├── parser.py # Assembly source parser
│ │ ├── emitter.py # Binary output generator
│ │ ├── diagnostics.py # Error reporting system
│ │ ├── expression_evaluator.py # Expression evaluation engine
│ │ ├── expression_parser.py # SLY-based expression parser
│ │ ├── instruction.py # Instruction representation
│ │ ├── program.py # Program state management
│ │ └── symbol_table.py # Symbol resolution and labels
│ ├── cpu_profiles/ # CPU architecture definitions
│ │ ├── 65c02.yaml # 65C02 CPU profile (178 opcodes)
│ │ ├── 6800.yaml # 6800 CPU profile (61 opcodes)
│ │ └── [new_cpu].yaml # Add your own CPU here!
│ └── .venv/ # Python virtual environment
├── tests/ # Comprehensive test suite
│ ├── test_assembler.py # Core assembler unit tests (4 tests)
│ ├── test_yaml_cpu_profiles.py # YAML profile tests (10 tests)
│ ├── test_end_to_end_65c02.py # 65C02 integration tests (5 tests)
│ ├── test_end_to_end_6800.py # 6800 integration tests (5 tests)
│ ├── test_comprehensive_65c02.s # Comprehensive 65C02 test file
│ ├── test_comprehensive_6800.s # Comprehensive 6800 test file
│ ├── test_simple_65c02.s # Simple 65C02 test file
│ └── test_simple.s # Generic test file
├── examples/ # Example assembly programs
│ ├── mcu65c02.s # 65C02 LED blink program
│ ├── mcu65c02.bin # Compiled 65C02 binary
│ ├── mcu6800.s # 6800 PIA control program
│ └── mcu6800.bin # Compiled 6800 binary
├── .github/ # GitHub configuration
│ ├── ISSUE_TEMPLATE/ # Issue templates
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── PULL_REQUEST_TEMPLATE.md # PR template
├── docs/ # Project documentation
│ ├── README.md # Main documentation (this file)
│ ├── TESTING.md # Testing procedures and guidelines
│ ├── CONTRIBUTING.md # Contribution guidelines
│ ├── AGENTS.md # Development agent guidelines
│ ├── YAML_MIGRATION.md # Profile format migration guide
│ └── GITHUB_ISSUES.md # Issue tracking templates
├── LICENSE # MIT License
├── .gitignore # Git ignore rules
└── setup_github.sh # GitHub setup script
compiler/: Main package containing the assembler implementationcompiler/core/: Core assembly components with clear separation of concernscompiler/cpu_profiles/: YAML-based CPU architecture definitionstests/: Complete test suite with unit and integration testsexamples/: Working assembly programs demonstrating CPU features.github/: GitHub templates and automation configurationdocs/: Comprehensive documentation for users and contributors
The assembler features a powerful, CPU-agnostic validation engine that uses rule-based validation defined entirely in YAML files. This means:
- No Hard-coded Logic: The Python code contains no CPU-specific validation logic
- Extensible Rules: Add new validation types without modifying Python code
- Flexible Conditions: Support for complex validation scenarios with exceptions
- Backward Compatible: Legacy validation format still supported
Supported Validation Rule Types:
error_if_mode_is- Error if instruction uses specific addressing modeserror_if_mode_is_not- Error if instruction doesn't use specific addressing modeswarning_if_mode_is- Warning if instruction uses specific addressing modeswarning_if_mode_is_not- Warning if instruction doesn't use specific addressing modeserror_if_operand_out_of_range- Error if operand value is outside valid rangewarning_if_operand_out_of_range- Warning if operand value is outside optimal rangeerror_if_register_used/warning_if_register_used- Register-specific validation
Example Validation Rule:
validation_rules:
- type: "warning_if_mode_is"
mnemonics: ["LDA", "STA", "LDX", "STX"]
modes: ["ABSOLUTE"]
message: "Instruction {mnemonic} uses absolute addressing. Consider using zero-page addressing for values under $0100."The assembler is designed for easy extension through YAML profiles. To add a new CPU:
- Create Profile: Add
new_cpu.yamlincompiler/cpu_profiles/ - Define CPU Info: Include name, description, data width, address width, endianness
- Specify Addressing Modes: List all addressing modes with enum values
- Add Opcodes: Define all instructions with their opcodes, cycles, and flags
- Define Directives: Specify assembler directives (EQU, .ORG, .BYTE, etc.)
- Add Validation Rules: Use generic rule-based validation system
- Validate: Use
python -m unittest tests.test_yaml_cpu_profilesto test
The simplified CPUProfileFactory automatically detects and loads any YAML profile files without requiring custom Python code.
Example YAML Structure:
cpu_info:
name: 'NEW_CPU'
description: New CPU Architecture
data_width: 8
address_width: 16
endianness: little
fill_byte: "0x00"
addressing_modes:
IMPLIED: 0
IMMEDIATE: 1
opcodes:
NOP:
IMPLIED: [0x00, 0, 2, ""]
directives:
EQU:
type: "symbol_define"
.ORG:
type: "origin_set"
validation_rules:
- type: "error_if_mode_is_not"
mnemonics: ["NOP"]
modes: ["IMPLIED"]
message: "Instruction {mnemonic} must use inherent addressing (no operands)."See TESTING.md for profile validation tools and detailed instructions.
# Run all tests
. compiler/.venv/bin/activate && python -m unittest discover tests/
# Run specific test file
. compiler/.venv/bin/activate && python -m unittest tests.test_yaml_cpu_profiles
# Run tests with verbose output
. compiler/.venv/bin/activate && python -m unittest discover tests/ -vSee TESTING.md for comprehensive testing documentation.
. compiler/.venv/bin/activate
# 65C02 example
python compiler/main.py examples/mcu65c02.s -o examples/mcu65c02.bin --cpu 65c02
# 6800 example
python compiler/main.py examples/mcu6800.s -o examples/mcu6800.bin --cpu 6800usage: main.py [-h] [--cpu {65c02,6800}] [--start-address START_ADDRESS]
[--output OUTPUT] [--log-file LOG_FILE]
source_file
Multi-CPU Assembler
positional arguments:
source_file Assembly source file to assemble
optional arguments:
-h, --help show this help message and exit
--cpu {65c02,6800} Target CPU architecture
--start-address START_ADDRESS
Starting address (default: 0x0000)
--output OUTPUT Output binary file
--log-file LOG_FILE Log file for detailed output
The assembler provides detailed error messages and warnings:
Warning on line 5: Label 'INVALID-LABEL' contains invalid characters. Labels should start with a letter or underscore and contain only letters, digits, and underscores.
Warning on line 8: Missing spaces around '+' operator in operand '#$10+$20'. Consider adding spaces for clarity.
Error on line 8: Could not determine addressing mode for operand: #$10+$20
We welcome contributions! See CONTRIBUTING.md for guidelines.
- New CPU Profiles: Add support for additional processors
- Output Formats: Intel HEX, Motorola S-record, ELF
- Macro System: Assembly macro support
- Conditional Assembly: IF/ELSE/ENDIF directives
- Performance: Optimization and benchmarking
- Documentation: Improve docs and examples
This project is licensed under the MIT License - see the LICENSE file for details.
This project includes comprehensive testing tools:
- Unit Tests: 24 tests covering YAML profiles, assembly workflow, and CLI
- Profile Validation: Standalone tools for validating CPU profiles
- Interactive Testing: Real-time testing of addressing modes and opcodes
- End-to-End Testing: Complete assembly workflow validation
- Test Coverage: 100% test pass rate with comprehensive error handling validation
See TESTING.md for detailed testing documentation and usage examples.
- Add Z80 CPU support (YAML profile)
- Implement macro system
- Add conditional assembly
- Support additional output formats (Intel HEX, S-record)
- IDE integration features
- Web-based interface for CPU profile creation
- Profile editor with real-time validation
- Built with SLY for expression parsing
- Inspired by classic assemblers and modern compiler design
- Thanks to contributors and the open source community