/// <summary> /// Reads the memory at the specified address /// </summary> /// <param name="addr">Memory address</param> /// <param name="noContention">Indicates non-contended read operation</param> /// <returns>Byte read from the memory</returns> public override byte Read(ushort addr, bool noContention = false) { var memIndex = addr & 0x3FFF; byte memValue; switch (addr & 0xC000) { case 0x0000: return(CurrentRomPage[memIndex]); case 0x4000: memValue = RamBanks[5][memIndex]; if (noContention || _screenDevice == null) { return(memValue); } _cpu?.Delay(_screenDevice.GetContentionValue(HostVm.CurrentFrameTact)); return(memValue); case 0x8000: return(RamBanks[2][memIndex]); default: memValue = RamBanks[_currentSlot3Bank][memIndex]; if ((_currentSlot3Bank & 0x01) == 0) { return(memValue); } // --- Bank 1, 3, 5, and 7 are contended _cpu?.Delay(_screenDevice.GetContentionValue(HostVm.CurrentFrameTact)); return(memValue); } }
/// <summary> /// Reads the memory at the specified address /// </summary> /// <param name="addr">Memory address</param> /// <returns>Byte read from the memory</returns> public byte Read(ushort addr) { var memIndex = addr & 0x3FFF; switch (addr & 0xC000) { case 0x0000: return(_currentRomPage[memIndex]); case 0x4000: if (_screenDevice != null) { _cpu?.Delay(_screenDevice.GetContentionValue(HostVm.CurrentFrameTact)); } return(_ramBanks[5][memIndex]); case 0x8000: return(_ramBanks[2][memIndex]); default: if ((_currentSlot3Bank & 0x01) != 0) { // --- Bank 1, 3, 5, and 7 are contended _cpu?.Delay(_screenDevice.GetContentionValue(HostVm.CurrentFrameTact)); } return(_ramBanks[_currentSlot3Bank][memIndex]); } }
/// <summary> /// Reads the memory at the specified address /// </summary> /// <param name="addr">Memory address</param> /// <returns>Byte read from the memory</returns> public byte Read(ushort addr) { var value = _memory[addr]; if ((addr & 0xC000) == 0x4000) { _cpu.Delay(_screenDevice.GetContentionValue(HostVm.CurrentFrameTact)); } return(value); }
/// <summary> /// Emulates memory contention /// </summary> /// <param name="addr">Contention address</param> public virtual void ContentionWait(ushort addr) { if ((addr & 0xC000) == 0x4000) { var delay = ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact); Cpu?.Delay(delay); } }
/// <summary> /// Reads the port with the specified address /// </summary> /// <param name="addr">Port address</param> /// <returns>Byte read from the port</returns> public virtual byte OnReadPort(ushort addr) { // --- Apply I/O contention delay var lowBit = (addr & 0x0001) != 0; var ulaHigh = (addr & 0xc000) == 0x4000; if (ulaHigh) { Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact - 1)); } else { if (!lowBit) { Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact)); } } return(0xFF); }
/// <summary> /// Applies the delay according to the current frame tact /// </summary> protected void ApplyDelay() { if (HostVm == null) { return; } var delay = ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact); Cpu.Delay(delay); HostVm.ContentionAccumulated += delay; }
/// <summary> /// Reads the memory at the specified address /// </summary> /// <param name="addr">Memory address</param> /// <param name="noContention">Indicates non-contended read operation</param> /// <returns>Byte read from the memory</returns> public override byte Read(ushort addr, bool noContention = false) { var memIndex = addr & 0x3FFF; byte memValue; switch (addr & 0xC000) { case 0x0000: return(SpecialMode ? RamBanks[_slots[0]][memIndex] : CurrentRomPage[memIndex]); case 0x4000: memValue = RamBanks[_slots[1]][memIndex]; if (noContention || _screenDevice == null) { return(memValue); } _cpu?.Delay(_screenDevice.GetContentionValue(HostVm.CurrentFrameTact)); return(memValue); case 0x8000: return(RamBanks[_slots[2]][memIndex]); default: var bankIndex = _slots[3]; memValue = RamBanks[bankIndex][memIndex]; if (bankIndex < 4) { return(memValue); } // --- Bank 4, 5, 6, and 7 are contended _cpu?.Delay(_screenDevice.GetContentionValue(HostVm.CurrentFrameTact)); return(memValue); } }
/// <summary> /// Emulates I/O contention /// </summary> /// <param name="addr">Contention address</param> public void ContentionWait(ushort addr) { Cpu.Delay(4); }
/// <summary> /// Emulates I/O contention /// </summary> /// <param name="addr">Contention address</param> public virtual void ContentionWait(ushort addr) { var lowBit = (addr & 0x0001) != 0; if ((addr & 0xc000) == 0x4000 || (addr & 0xc000) == 0xC000 && IsContendedBankPagedIn()) { if (lowBit) { // --- C:1 x 4 contention scheme Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact)); Cpu.Delay(1); Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact)); Cpu.Delay(1); Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact)); Cpu.Delay(1); Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact)); Cpu.Delay(1); } else { // --- C:1, C:3 contention scheme Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact)); Cpu.Delay(1); Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact)); Cpu.Delay(3); } } else { if (lowBit) { // --- N:4 contention scheme Cpu.Delay(4); } else { // --- N:1, C:3 contention scheme Cpu.Delay(1); Cpu.Delay(ScreenDevice.GetContentionValue(HostVm.CurrentFrameTact)); Cpu.Delay(3); } } }