vcpu 0.2.0

A virtual cpu, modeled after the 6502
Documentation
use strum::Display;

use crate::{core::cpu::Cpu, error::CpuError};

#[derive(Debug)]
pub struct Instruction {
  pub opcode: OpCode,
  pub mode: AddressingMode,
  pub cycles: u8,
}

#[derive(Debug, Display)]
pub enum AddressingMode {
  Accumulator,
  Implied,
  Immediate(u8),
  Relative(u8),

  ZeroPage(u8),
  ZeroPageX(u16),
  ZeroPageY(u16),

  Absolute(u16),
  AbsoluteX(u16),
  AbsoluteY(u16),

  Indirect(u16),
  IndirectX(u16),
  IndirectY(u16),
}

impl AddressingMode {
  pub fn accumulator(_cpu: &mut Cpu) -> Result<Self, CpuError> {
    Ok(Self::Accumulator)
  }

  pub fn implied(_cpu: &mut Cpu) -> Result<Self, CpuError> {
    Ok(Self::Implied)
  }

  pub fn immediate(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let value = cpu.fetch()?;
    Ok(AddressingMode::Immediate(value))
  }

  pub fn relative(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let value = cpu.fetch()?;
    Ok(AddressingMode::Relative(value))
  }

  pub fn zero_page(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let value = cpu.fetch()?;
    Ok(AddressingMode::ZeroPage(value))
  }

  pub fn zero_page_x(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let first = cpu.fetch()?;
    let second = cpu.fetch()?;
    let value = u16::from_le_bytes([first, second]);
    Ok(AddressingMode::ZeroPageX(value))
  }

  pub fn zero_page_y(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let first = cpu.fetch()?;
    let second = cpu.fetch()?;
    let value = u16::from_le_bytes([first, second]);
    Ok(AddressingMode::ZeroPageY(value))
  }

  pub fn absolute(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let first = cpu.fetch()?;
    let second = cpu.fetch()?;
    let value = u16::from_le_bytes([first, second]);
    Ok(AddressingMode::Absolute(value))
  }

  pub fn absolute_x(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let first = cpu.fetch()?;
    let second = cpu.fetch()?;
    let value = u16::from_le_bytes([first, second]);
    Ok(AddressingMode::AbsoluteX(value))
  }

  pub fn absolute_y(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let first = cpu.fetch()?;
    let second = cpu.fetch()?;
    let value = u16::from_le_bytes([first, second]);
    Ok(AddressingMode::AbsoluteY(value))
  }

  pub fn indirect(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let first = cpu.fetch()?;
    let second = cpu.fetch()?;
    let value = u16::from_le_bytes([first, second]);
    Ok(AddressingMode::Indirect(value))
  }

  pub fn indirect_x(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let first = cpu.fetch()?;
    let second = cpu.fetch()?;
    let value = u16::from_le_bytes([first, second]);
    Ok(AddressingMode::IndirectX(value))
  }

  pub fn indirect_y(cpu: &mut Cpu) -> Result<Self, CpuError> {
    let first = cpu.fetch()?;
    let second = cpu.fetch()?;
    let value = u16::from_le_bytes([first, second]);
    Ok(AddressingMode::IndirectY(value))
  }
}

#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Display)]
pub enum OpCode {
  ADC,
  AND,
  ASL,
  BCC,
  BCS,
  BEQ,
  BIT,
  BMI,
  BNE,
  BPL,
  BRK,
  BVC,
  BVS,
  CLC,
  CLD,
  CLI,
  CLV,
  CMP,
  CPX,
  CPY,
  DEC,
  DEX,
  DEY,
  EOR,
  INC,
  INX,
  INY,
  JMP,
  JSR,
  LDA,
  LDX,
  LDY,
  LSR,
  NOP,
  ORA,
  PHA,
  PHP,
  PLA,
  PLP,
  ROL,
  ROR,
  RTI,
  RTS,
  SBC,
  SEC,
  SED,
  SEI,
  STA,
  STX,
  STY,
  TAX,
  TAY,
  TSX,
  TXA,
  TXS,
  TYA,
}