src/cpu/cpu.cc
/*
 * Runs the memory operation encoded by the given CPU operation.
 */
Runs the memory operation encoded by the given CPU operation.
Runs the memory operation encoded by the given CPU operation .
void Cpu::RunMemoryOperation(CpuOperation &op) {
  CpuReg mem_addr = GET_MEM_ADDR(op);
  CpuReg mem_op1 = GET_MEM_OP1(op);
  CpuReg mem_op2 = GET_MEM_OP2(op);
  (void)mem_op2; 
  DoubleWord mem_offset = GET_MEM_OFST(op);
  MemoryOpcode mem_op = GET_MEM_OP(op);
  DataWord *regfile = reinterpret_cast<DataWord*>(regs_);
  switch (mem_op) {
    case MEM_READZP: {
      regfile[mem_op1 + 1] = 0;
      [[fallthrough]];
    }
    case MEM_READ: {
      regfile[mem_op1] = memory_->Read(READ_ADDR_REG(mem_addr, mem_offset));
      break;
    }
    case MEM_WRITE: {
      memory_->Write(READ_ADDR_REG(mem_addr, 0), regfile[mem_op1]);
      break;
    }
    case MEM_BRK: {
      regs_->p |= P_FLAG_B;
      irq_ready_ = false;
      [[fallthrough]];
    }
    case MEM_IRQ: {
      memory_->Write(READ_ADDR_REG(REG_S, 0), regs_->p);
      if (nmi_edge_) {
        inst_buffer_[0] = MEM_READ | MEM_ADDR(REG_VEC) | MEM_OP1(REG_PCL)
                        | MEM_OFST(0) | DAT_SET | DAT_MASK(P_FLAG_I);
        inst_buffer_[1] = MEM_READ | MEM_ADDR(REG_VEC) | MEM_OP1(REG_PCH)
                        | MEM_OFST(1);
        inst_buffer_[2] = MEM_FETCH | PC_INC;
        current_sequence_ = inst_buffer_;
        inst_pointer_ = 0;
      } else {
        inst_buffer_[0] = MEM_READ | MEM_ADDR(REG_VEC) | MEM_OP1(REG_PCL)
                        | MEM_OFST(4) | DAT_SET | DAT_MASK(P_FLAG_I);
        inst_buffer_[1] = MEM_READ | MEM_ADDR(REG_VEC) | MEM_OP1(REG_PCH)
                        | MEM_OFST(5);
        inst_buffer_[2] = MEM_FETCH | PC_INC;
        current_sequence_ = inst_buffer_;
        inst_pointer_ = 0;
      }
      regs_->p &= P_MASK;
      break;
    }
    case MEM_PHP: {
      memory_->Write(READ_ADDR_REG(REG_S, 0), regs_->p | P_FLAG_B);
      break;
    }
    case MEM_PLP: {
      regs_->p = memory_->Read(READ_ADDR_REG(REG_S, 0)) & P_MASK;
      break;
    }
    case MEM_FETCH: {
      Fetch(op);
      break;
    }
    case MEM_BRANCH: {
      DataWord flag = (regs_->inst >> 6U) & 0x03U;
      bool cond = regs_->inst & 0x20U;
      DataWord status = regs_->p;
      flag = (flag & 2U) ? ((status >> (flag & 1U)) & 1U)
                         : ((status >> ((~flag) & 0x07U)) & 1U);
      bool taken = ((static_cast<bool>(flag)) == cond);
      DoubleWord res = regs_->pc_lo + regs_->temp1;
      regs_->temp2 = (regs_->temp1 & 0x80) ? (GET_WORD_HI(res) + 0xFFU)
                                           :  GET_WORD_HI(res);
      if (!taken) {
        op |= PC_INC;
        Fetch(op);
      } else if (regs_->temp2) {
        regs_->pc_lo = GET_WORD_LO(res);
        inst_buffer_[0] = DAT_ADD | DAT_SRC(REG_TMP2) | DAT_DST(REG_PCH);
        inst_buffer_[1] = MEM_FETCH | PC_INC;
        current_sequence_ = inst_buffer_;
        inst_pointer_ = 0;
      } else {
        regs_->pc_lo = GET_WORD_LO(res);
        inst_buffer_[0] = MEM_FETCH | PC_INC;
        current_sequence_ = inst_buffer_;
        inst_pointer_ = 0;
      }
      break;
    }
    case MEM_NOP:
    default: {
      break;
    }
  }
  return;
}
void Cpu :: RunMemoryOperation ( CpuOperation & op ) { CpuReg mem_addr = GET_MEM_ADDR ( op ) ; CpuReg mem_op1 = GET_MEM_OP1 ( op ) ; CpuReg mem_op2 = GET_MEM_OP2 ( op ) ; ( void ) mem_op2 ; DoubleWord mem_offset = GET_MEM_OFST ( op ) ; MemoryOpcode mem_op = GET_MEM_OP ( op ) ; DataWord * regfile = reinterpret_cast < DataWord * > ( regs_ ) ; switch ( mem_op ) { case MEM_READZP : { regfile [ mem_op1 + 1 ] = 0 ; [[ fallthrough ]] ; } case MEM_READ : { regfile [ mem_op1 ] = memory_ -> Read ( READ_ADDR_REG ( mem_addr , mem_offset ) ) ; break ; } case MEM_WRITE : { memory_ -> Write ( READ_ADDR_REG ( mem_addr , 0 ) , regfile [ mem_op1 ] ) ; break ; } case MEM_BRK : { regs_ -> p |= P_FLAG_B ; irq_ready_ = false ; [[ fallthrough ]] ; } case MEM_IRQ : { memory_ -> Write ( READ_ADDR_REG ( REG_S , 0 ) , regs_ -> p ) ; if ( nmi_edge_ ) { inst_buffer_ [ 0 ] = MEM_READ | MEM_ADDR ( REG_VEC ) | MEM_OP1 ( REG_PCL ) | MEM_OFST ( 0 ) | DAT_SET | DAT_MASK ( P_FLAG_I ) ; inst_buffer_ [ 1 ] = MEM_READ | MEM_ADDR ( REG_VEC ) | MEM_OP1 ( REG_PCH ) | MEM_OFST ( 1 ) ; inst_buffer_ [ 2 ] = MEM_FETCH | PC_INC ; current_sequence_ = inst_buffer_ ; inst_pointer_ = 0 ; } else { inst_buffer_ [ 0 ] = MEM_READ | MEM_ADDR ( REG_VEC ) | MEM_OP1 ( REG_PCL ) | MEM_OFST ( 4 ) | DAT_SET | DAT_MASK ( P_FLAG_I ) ; inst_buffer_ [ 1 ] = MEM_READ | MEM_ADDR ( REG_VEC ) | MEM_OP1 ( REG_PCH ) | MEM_OFST ( 5 ) ; inst_buffer_ [ 2 ] = MEM_FETCH | PC_INC ; current_sequence_ = inst_buffer_ ; inst_pointer_ = 0 ; } regs_ -> p &= P_MASK ; break ; } case MEM_PHP : { memory_ -> Write ( READ_ADDR_REG ( REG_S , 0 ) , regs_ -> p | P_FLAG_B ) ; break ; } case MEM_PLP : { regs_ -> p = memory_ -> Read ( READ_ADDR_REG ( REG_S , 0 ) ) & P_MASK ; break ; } case MEM_FETCH : { Fetch ( op ) ; break ; } case MEM_BRANCH : { DataWord flag = ( regs_ -> inst >> 6U ) & 0x03U ; bool cond = regs_ -> inst & 0x20U ; DataWord status = regs_ -> p ; flag = ( flag & 2U ) ? ( ( status >> ( flag & 1U ) ) & 1U ) : ( ( status >> ( ( ~ flag ) & 0x07U ) ) & 1U ) ; bool taken = ( ( static_cast < bool > ( flag ) ) == cond ) ; DoubleWord res = regs_ -> pc_lo + regs_ -> temp1 ; regs_ -> temp2 = ( regs_ -> temp1 & 0x80 ) ? ( GET_WORD_HI ( res ) + 0xFFU ) : GET_WORD_HI ( res ) ; if ( ! taken ) { op |= PC_INC ; Fetch ( op ) ; } else if ( regs_ -> temp2 ) { regs_ -> pc_lo = GET_WORD_LO ( res ) ; inst_buffer_ [ 0 ] = DAT_ADD | DAT_SRC ( REG_TMP2 ) | DAT_DST ( REG_PCH ) ; inst_buffer_ [ 1 ] = MEM_FETCH | PC_INC ; current_sequence_ = inst_buffer_ ; inst_pointer_ = 0 ; } else { regs_ -> pc_lo = GET_WORD_LO ( res ) ; inst_buffer_ [ 0 ] = MEM_FETCH | PC_INC ; current_sequence_ = inst_buffer_ ; inst_pointer_ = 0 ; } break ; } case MEM_NOP : default : { break ; } } return ; }
Runs the memory operation encoded by the given CPU operation.
Runs the memory operation encoded by the given CPU operation .
// Decodes the information necessary to complete the memory operation. // Used for undefined instructions, which are not implemented. // Performs the encoded memory operation. /*
     * Clears the high byte of the address pointed to by mem_op1, then
     * passes off to MEM_READ to perform the read of the low address byte.
     */ /*
     * Reads the value from the address specified by the addressing register
     * plus the offset into the register specified by mem_op1.
     */ /*
     * Writes the value specified by mem_op1 & mem_op2 into the address
     * given from the addressing register.
     */ /*
     * Sets the B flag in P and lowers the irq_ready signal, then passes
     * off to MEM_IRQ to queue the next cycles according to hijacking behavior.
     */ /*
     * Pushes the state register on the stack, then adds the next cycles of
     * the interrupt according to hijacking behavior. The B flag is then
     * masked out of P.
     */ // Allows an NMI to hijack the instruction. /*
     * Pushes the status register onto the stack with the B flag set.
     */ /*
     * Pulls the status register from the stack, clearing the B flag.
     */ /*
     * Fetches the next instructions and queues its cycles.
     */ /*
     * Executes a branch instruction.
     * Branch instructions are of the form xxy10000, and are broken into
     * three cases:
     * 1) If the flag indicated by xx has value y, then the relative address
     * is added to the PC.
     * 2) If case 1 results in a page crossing on the pc, an extra cycle is
     * added.
     * 3) If xx does not have value y, this micro op is the same as MEM_FETCH.
     */ // Calculate whether or not the branch was taken. // Black magic that pulls the proper flag from the status reg. // Add the reletive address to pc_lo. Reletive addressing is signed. // Effectively sign extends the MDR in the carry out. // Execute the proper cycles according to the above results. // Case 3. We must force a PC increment since this is now a fetch. // Case 2. // Case 1. /* Does nothing */