UNPKG

@asm80/core

Version:

Core ASM80 compiler / assembler

201 lines (159 loc) 6.21 kB
# CPU Directory This directory contains CPU-specific modules for the ASM80 assembler. Each module implements instruction encoding for a specific microprocessor family. ## Supported CPUs ### z80.js **Zilog Z80 Processor** - **CPU ID**: "z80" - **File Extension**: ".z80" - **Endianness**: Little endian - **Features**: Full Z80 instruction set including undocumented instructions, indexed addressing with IX/IY, block operations, interrupt modes ### i8080.js **Intel 8080/8085 Processor** - **CPU ID**: "i8080" - **File Extension**: ".a80" - **Endianness**: Little endian - **Features**: 8080 instruction set with 8085 extensions, undocumented 8085 instructions (JNK, JK, DSUB, etc.) ### c6502.js **MOS 6502/65C02 Processor** - **CPU ID**: "c6502" - **File Extension**: ".a65" - **Endianness**: Little endian - **Features**: 6502 instruction set, 65C02 extensions, illegal opcodes, comprehensive addressing modes ### m6800.js **Motorola 6800 Processor** - **CPU ID**: "m6800" - **File Extension**: ".a68" - **Endianness**: Big endian - **Features**: 6800 instruction set, dual accumulator architecture ### dummy.js **Test Processor** - **CPU ID**: "dummy" - **Purpose**: Non-existent processor used for testing the assembler framework - **Features**: Implements basic test instructions (NOP, P1, P2, PA2, PB2, PX2, PY2) with various addressing patterns ## CPU Module Interface Every CPU module must implement the following interface: ### Required Properties ```javascript export const CPUName = { endian: boolean, // false = little endian, true = big endian cpu: string, // CPU identifier (e.g., "z80", "i8080") ext: string, // File extension (e.g., "z80", "a80") // Required method parseOpcode: function(s, vars, Parser) { ... } // Optional instruction definitions (format varies by CPU) set: { ... }, // Main instruction definitions set2: { ... }, // Extended definitions (Z80 only) // ... other CPU-specific properties }; ``` ### parseOpcode Function The `parseOpcode(s, vars, Parser)` function is the core method that converts parsed assembly instructions into machine code. **Parameters:** - `s` - Instruction object containing: - `s.opcode` - Instruction mnemonic (string) - `s.params` - Array of parameters - `s.numline` - Source line number - Other properties from parser - `vars` - Object containing variables/labels for evaluation - `Parser` - Parser object with `evaluate()` function for expression evaluation **Return Value:** - `null` - If instruction is not recognized - Modified `s` object with: - `s.bytes` - Number of bytes the instruction occupies - `s.lens` - Array of bytes/functions for code generation - `s.wia` - Word in address position for relocation (optional) **Example Implementation:** ```javascript parseOpcode: function(s, vars, Parser) { if (!s.opcode) return null; // Simple NOP instruction if (s.opcode === "NOP") { s.bytes = 1; s.lens = [0x00]; return s; } // Instruction with immediate operand if (s.opcode === "LDA" && s.params && s.params.length === 1) { s.bytes = 2; s.lens = [ 0x3A, // Opcode function(vars) { return Parser.evaluate(s.params[0], vars) & 0xFF; } ]; s.wia = 1; // Address starts at byte 1 return s; } return null; // Instruction not recognized } ``` ### Code Generation Array (lens) The `lens` array contains the machine code bytes for the instruction: ```javascript s.lens = [ 0x3A, // Fixed opcode byte function(vars) { return value; }, // Function to evaluate parameter null, // Null indicates high byte of 16-bit value "addr16", // Special address markers ... ]; ``` **Types of lens elements:** - **Number**: Fixed byte value (0-255) - **Function**: `function(vars) { return value; }` - Evaluated during pass 2 - **null**: Placeholder for high byte of 16-bit values - **String**: Special markers like "addr16", "addr24", "addr32" ## Instruction Set Definition Patterns Different CPUs use different approaches for defining instruction sets: ### Array-based (Z80, M6800) ```javascript set: { INSTRUCTION: [type0, type1, type2, ...] // Values for different addressing modes } ``` ### Object-based (8080) ```javascript set: { 'INSTRUCTION': {o: opcode, t: "type"} // Opcode and addressing type } ``` ### Matrix-based (6502) ```javascript set: { INSTRUCTION: [imp, ima, imm, abs, abx, aby, zpg, zpx, zpy, ind, izx, izy, rel, izp] // Each position represents a specific addressing mode } ``` ## Adding a New CPU To add a new CPU to the system: 1. **Create CPU module** in `cpu/newcpu.js` 2. **Implement required interface** with `endian`, `cpu`, `ext` properties 3. **Implement parseOpcode function** following the interface specification 4. **Define instruction set** using appropriate pattern for your CPU 5. **Export CPU object** as named export 6. **Add to main module** in `asm.js` imports and CPU array ### Minimal CPU Template ```javascript export const NewCPU = { endian: false, // or true for big-endian cpu: "newcpu", // Unique identifier ext: "ncpu", // File extension parseOpcode: function(s, vars, Parser) { if (!s.opcode) return null; // Implement instruction parsing logic here // Return null for unrecognized instructions // Return modified s object for valid instructions return null; } }; ``` ## Error Handling - Return `null` from parseOpcode for unrecognized instructions - Use `Parser.evaluate()` to handle expressions and forward references - Set appropriate `s.bytes` to indicate instruction length - Handle addressing mode variants in CPU-specific ways ## Testing The dummy.js processor provides examples of: - Basic instruction parsing - Parameter evaluation with functions - Multi-byte instructions - Address relocation markers - Both little-endian (DUMMY) and big-endian (DUMMYE) variants