1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
//! Microcode implementation //! //! The μOp is the smallest executable atom into sets of which instructions degenerate, //! implementing an 8-bit stack-based language. //! //! # Examples //! //! Ignoring error handling, a simple emulator without I/O port support can be implemented as such //! (as in the `emulate_dumb` example): //! //! ``` //! # use pir_8_emu::isa::instruction::{InstructionLoadImmediateWideRegisterPair, InstructionMadrDirection, InstructionRegisterPair, Instruction}; //! # use pir_8_emu::isa::{GeneralPurposeRegister, SpecialPurposeRegister}; //! # use pir_8_emu::micro::{MicroOp, NEXT_INSTRUCTION}; //! # use pir_8_emu::vm::{Memory, Ports}; //! let mut ports = Ports::new(); //! let mut registers = GeneralPurposeRegister::defaults(); //! let mut pc = SpecialPurposeRegister::new("Program Counter", "PC"); //! let mut sp = SpecialPurposeRegister::new("Stack Pointer", "SP"); //! let mut adr = SpecialPurposeRegister::new("Memory Address", "ADR"); //! let mut ins = SpecialPurposeRegister::new("Instruction", "INS"); //! //! let mut memory = Memory::from(&[Instruction::LoadImmediateWide { rr: InstructionLoadImmediateWideRegisterPair::Adr }.into(), //! 0x01, //! 0x10, //! Instruction::LoadIndirect { rrr: 0b100 }.into(), //! Instruction::LoadImmediateByte { rrr: 0b101 }.into(), //! 0x69, //! Instruction::Move { qqq: 0b100, rrr: 0b110 }.into(), //! Instruction::Move { qqq: 0b101, rrr: 0b100 }.into(), //! Instruction::Move { qqq: 0b110, rrr: 0b101 }.into(), //! Instruction::Halt.into()][..]); //! memory[0x0110] = 0xA1; //! //! let mut stack = vec![]; //! 'outside: loop { //! let ops = NEXT_INSTRUCTION; //! let ops = &ops.0[..ops.1]; //! for op in ops { //! if !op.perform(&mut stack, &mut memory, &mut ports, &mut registers, //! &mut pc, &mut sp, &mut adr, &mut ins).unwrap() { //! break 'outside; //! } //! } //! //! let instr = Instruction::from(*ins); //! let ops = MicroOp::from_instruction(instr); //! let ops = &ops.0[..ops.1]; //! for op in ops { //! if !op.perform(&mut stack, &mut memory, &mut ports, &mut registers, &mut pc, //! &mut sp, &mut adr, &mut ins).unwrap() { //! break 'outside; //! } //! } //! } //! //! assert_eq!(*registers[0b100], 0x69); //! assert_eq!(*registers[0b101], 0xA1); //! ``` mod from_instruction; mod display; mod perform; mod error; mod op; pub use self::from_instruction::MicroOpBlock; pub use self::error::MicroOpPerformError; pub use self::display::DisplayMicroOp; pub use self::op::MicroOp; /// μOps to perform to get to the next instruction. pub static NEXT_INSTRUCTION: (MicroOpBlock, usize) = ([// forcebreak MicroOp::LoadImmediate, MicroOp::LoadInstruction, MicroOp::Nop, MicroOp::Nop, MicroOp::Nop, MicroOp::Nop], 2);