Skip to content

Latest commit

 

History

History
243 lines (224 loc) · 9.84 KB

comm.md

File metadata and controls

243 lines (224 loc) · 9.84 KB

impl AddressingMode { /// load loads a byte from memory based on the addressing mode. It returns a tuple; the byte being fetched, and a boolean /// indicating if there is a page cross while loading the byte. pub(super) fn load(&self, cpu: &mut Six502) -> (u8, bool) { match self { AddressingMode::Acc_Addrs => { cpu.atom(|c| { // comeback }); (cpu.a, false) } AddressingMode::Abs_Addrs => { let (mut p1, mut p2, mut v) = (0, 0, 0); cpu.atom(|c| p1 = c.load_u8_bump_pc()); cpu.atom(|c| p2 = c.load_u8_bump_pc()); cpu.atom(|c| { let addr = u16::from_le_bytes([p1, p2]); v = c.load_with_addr_u8(addr); });

            // let addr = cpu.load_u16_bump_pc();
            (v, false)
        }
        AddressingMode::AbsX_Idxd => {
            let (mut p1, mut p2, mut v) = (0, 0, 0);
            let mut over = false;
            cpu.atom(|c| p1 = c.load_u8_bump_pc());
            let x = cpu.x;
            cpu.atom(|c| {
                p2 = c.load_u8_bump_pc();
                (p1, over) = p1.overflowing_add(x);
            });

            if over {
                cpu.atom(|c| {
                    p1 += 1;
                    let addr = u16::from_le_bytes([p1, p2]);
                    v = c.load_with_addr_u8(addr);
                });
            } else {
                let addr = u16::from_le_bytes([p1, p2]);
                v = c.load_with_addr_u8(addr);
            };

            // let op = cpu.load_u16_bump_pc();

            // // check if it'll overflow into the zero page
            // let lb_op = op as u8;
            // let (_, carry) = lb_op.overflowing_add(cpu.x);

            (v, false)
        }
        AddressingMode::AbsY_Idxd => {
            let op = cpu.load_u16_bump_pc();

            // check if it'll overflow into the zero page
            let lb_op = op as u8;
            let (_, carry) = lb_op.overflowing_add(cpu.y);
            (cpu.load_with_addr_u8(op + (cpu.y as u16)), carry)
        }

        AddressingMode::Immediate => {
            let mut v = 0;
            cpu.atom(|c| v = c.load_u8_bump_pc());
            (v, false)
        }
        AddressingMode::Zero_Page => {
            let (mut addr, mut v) = (0, 0);
            cpu.atom(|c| {
                addr = c.load_u8_bump_pc();
            });
            cpu.atom(|c| {
                let addr = addr as u16;
                v = c.load_with_addr_u8(addr);
            });
            // let addr = cpu.load_u8_bump_pc();
            (v, false)
        }
        //without carry
        AddressingMode::ZP_X_Idxd => {
            let addr = cpu.load_u8_bump_pc();
            (cpu.load_with_addr_u8((addr.wrapping_add(cpu.x)) as u16), false)
        } //without carry. that's why we add the `u8`s before converting to `u16`, so it won't carry into the high-byte

        //   If the base address plus X or Y exceeds the value that
        //   can be stored in a single byte, no carry is generated, therefore there is no page crossing phenomena
        //    A wrap-around will occur within Page Zero
        AddressingMode::ZP_Y_Idxd => {
            let addr = cpu.load_u8_bump_pc();
            (cpu.load_with_addr_u8((addr.wrapping_add(cpu.y)) as u16), false)
        }
        // The major use of indexed indirect is in picking up data from a table or list of addresses to perform an operation.
        AddressingMode::X_Idx_Ind => {
            let v = cpu.load_u8_bump_pc();
            // zero page addition. Never crosses page. wraps around
            let comp = cpu.x.wrapping_add(v);
            let lo_addr = cpu.load_with_addr_u8(comp as u16);
            let hi_addr = cpu.load_with_addr_u8((comp + 1) as u16);
            // say comp is 0x05 effective address becomes 0x0605
            let eff_addr = u16::from_le_bytes([lo_addr, hi_addr]);
            (cpu.load_with_addr_u8(eff_addr), false) // never crosses pae as the indexing is done in the zero page
        }
        AddressingMode::Ind_Y_Idx => {
            let y = cpu.y;
            let v = cpu.load_u8_bump_pc();
            let lo_addr = cpu.load_with_addr_u8(v as u16);
            let hi_addr = cpu.load_with_addr_u8((v + 1) as u16);
            // say v is 0x05 effective address becomes 0x0605
            let eff_addr = u16::from_le_bytes([lo_addr, hi_addr]);
            let (_, carry) = lo_addr.overflowing_add(y);
            (cpu.load_with_addr_u8(eff_addr.wrapping_add(y as u16)), carry) // might cross page
        }
        AddressingMode::Impl_Addr => {
            // basically, nothing happens here, except tha the opcode fetched in last cycle is decoded.
            // so we just tick. the new opcode is decoded, and the pc os not incremented
            cpu.tick();
            // in the next cycle, the old opcode is executed and the opcode ignored in the above is decoded
            (0, false)
        }
        AddressingMode::Rel_Addrs => {
            let (mut off) = (0);
            cpu.atom(|c| {
                off = c.load_u8_bump_pc() as i8 as u16;
            });
            let mut overflowed = false;
            // comeback to deal with page transiions
            cpu.atom(|c| {
                (c.pc, overflowed) = c.pc.overflowing_add(off);
            });
            if overflowed {
                cpu.tick();
            }
            (0, false)
        }
        AddressingMode::Ind_Addrs => todo!(),
        AddressingMode::None => todo!(),
    }


pub(super) fn store(&self, cpu: &mut Six502, v: u8) -> bool {
    match self {
        AddressingMode::Acc_Addrs => {
            cpu.a = v;
            false
        }
        AddressingMode::Abs_Addrs => {
            let addr = cpu.load_u16_bump_pc();
            cpu.addr_bus = addr;
            cpu.store_u8(addr);
            false
        }

        AddressingMode::AbsX_Idxd => {
            let op = cpu.load_u16_bump_pc();

            // check if it'll overflow into the zero page
            let lb_op = op as u8;
            let (_, carry) = lb_op.overflowing_add(cpu.x);
            let addr = cpu.load_u16_bump_pc();
            cpu.addr_bus = addr + (cpu.x as u16);
            cpu.store_u8(v);
            carry
        }
        AddressingMode::AbsY_Idxd => {
            let op = cpu.load_u16_bump_pc();
            // check if it'll overflow into the zero page
            let lb_op = op as u8; // truncates
            let (_, carry) = lb_op.overflowing_add(cpu.y);
            let addr = cpu.load_u16_bump_pc();
            cpu.addr_bus = addr + (cpu.y as u16);
            cpu.store_u8(v);
            carry
        }

        AddressingMode::Immediate => false, // do nothing
        // AddressingMode::Indirect => false,
        AddressingMode::Zero_Page => {
            let addr = cpu.load_u8_bump_pc();
            cpu.addr_bus = addr as u16;
            cpu.store_u8(v);
            false
        }

        //   If the base address plus X or Y exceeds the value that
        //   can be stored in a single byte, no carry is generated, therefore there is no page crossing phenomena
        //    A wrap-around will occur within Page Zero
        AddressingMode::ZP_X_Idxd => {
            let addr = cpu.load_u8_bump_pc();
            cpu.addr_bus = (addr.wrapping_add(cpu.x)) as u16;
            cpu.store_u8( v);
            false
        }
        AddressingMode::ZP_Y_Idxd => {
            let addr = cpu.load_u8_bump_pc();
            cpu.addr_bus = (addr.wrapping_add(cpu.y)) as u16;
            cpu.store_u8(v);
            false
        }

        AddressingMode::X_Idx_Ind => {
            let v = cpu.load_u8_bump_pc();
            // zero page addition. Never crosses page. wraps around
            let comp = cpu.x.wrapping_add(v);
            cpu.addr_bus = comp as u16;
            let lo_addr = cpu.load_u8();
            cpu.addr_bus = comp.wrapping_add(1) as u16;
            let hi_addr = cpu.load_u8();
            let eff_addr = u16::from_le_bytes([lo_addr, hi_addr]);
            cpu.addr_bus = eff_addr;
            cpu.store_u8(v);
            false // never crosses page as the indexing is done in the zero page
        }
        AddressingMode::Ind_Y_Idx => {
            let v = cpu.load_u8_bump_pc();
            let y = cpu.y;
            cpu.addr_bus = v as u16;
            let lo_addr = cpu.load_u8();
            cpu.addr_bus = (v + 1) as u16;
            let hi_addr = cpu.load_u8();
            // say v is 0x05 effective address becomes 0x0605
            let eff_addr = u16::from_le_bytes([lo_addr, hi_addr]);
            let (_, carry) = lo_addr.overflowing_add(y);
            cpu.addr_bus = eff_addr.wrapping_add(y as u16);
            cpu.store_u8(v);
            carry // might cross page
        }
        AddressingMode::Impl_Addr => todo!(),
        AddressingMode::Rel_Addrs => todo!(),
        AddressingMode::Ind_Addrs => todo!(),
        AddressingMode::None => todo!(),
    }

} }

fn load_with_addr_u8(&mut self, addr: u16) -> u8 {
    self.bus.load_u8(addr)
}

fn store_with_addr_u8(&mut self, addr: u16, v: u8) {
    self.bus.store_u8(addr, v);
}