#pragma once #include "ioport.hpp" namespace JabyEngine { namespace CD_IO { struct DataSector { static constexpr size_t SizeBytes = 2048; static constexpr size_t SizeWords = (SizeBytes/sizeof(uint32_t)); uint32_t data[SizeWords]; template static constexpr T words_to_sectors(T size) { return (size + static_cast(DataSector::SizeWords - 1))/static_cast(DataSector::SizeWords); } }; enum Index { Index0 = 0, Index1 = 1, Index2 = 2, Index3 = 3, }; struct CDDAVolume { typedef uint8_t Type; static constexpr uint8_t Off = 0x0; static constexpr uint8_t Default = 0x80; static constexpr uint8_t Max = 0xFF; }; __declare_io_value(Mode, uint8_t) { static constexpr auto DoubleSpeed = Bit(7); static constexpr auto SingleSpeed = !DoubleSpeed; static constexpr auto XADPCM = Bit(6); static constexpr auto WholeSector = Bit(5); static constexpr auto DataSector = !WholeSector; static constexpr auto UseXAFilter = Bit(3); static constexpr auto AudioPlayIRQ = Bit(2); static constexpr auto AutoPauseTrack = Bit(1); static constexpr auto CDDA = Bit(0); operator uint8_t() const { return this->raw; } }; __declare_io_value(IndexStatus, uint8_t) { static constexpr auto PortIndex = BitRange::from_to(0, 1); static constexpr auto HasXAFifoData = Bit(2); static constexpr auto IsParameterFifoEmpty = Bit(3); static constexpr auto HasParameterFifoSpace = Bit(4); static constexpr auto HasResponseFifoData = Bit(5); static constexpr auto HasDataFifoData = Bit(6); static constexpr auto IsTransmissionBusy = Bit(7); }; __declare_io_value(InterruptEnable, uint8_t) { static constexpr auto InterruptTypValue = BitRange::from_to(0, 2); static constexpr auto InterruptExtended = BitRange::from_to(0, 4); static constexpr auto UnknownIRQ = Bit(3); static constexpr auto CommandStartIRQ = Bit(4); }; typedef InterruptEnable InterruptFlag; __declare_io_value(Request, uint8_t) { static constexpr auto WantCommandStartIRQ = Bit(5); static constexpr auto WantData = Bit(7); static Request want_data() { return Request{static_cast(Request::WantData)}; } static Request reset() { return Request{0}; } }; __declare_io_value(SoundMapCoding, uint8_t) { static constexpr auto Stereo = Bit(0); static constexpr auto Mono = !Stereo; static constexpr auto SampleRate_18900hz = Bit(2); static constexpr auto SampleRate_37800hz = !SampleRate_18900hz; static constexpr auto BitsPerSample8 = Bit(4); static constexpr auto BitsPerSample4 = !BitsPerSample8; static constexpr auto Emphasis = Bit(6); }; __declare_io_value(AudioVolumeApply, uint8_t) { static constexpr auto Mute = Bit(0); static constexpr auto ApplyChanges = Bit(5); }; __declare_io_value(ResponseFifo, uint8_t) { }; __declare_io_value(CommandFifo, uint8_t) { }; __declare_io_value(DataFifo, uint8_t) { }; __declare_io_value(DataFifo16, uint16_t) { }; __declare_io_value(ParameterFifo, uint8_t) { }; __declare_io_value(SoundMapDataOut, uint8_t) { }; __declare_io_value(LeftCD2LeftSPU, CDDAVolume::Type) { }; __declare_io_value(LeftCD2RightSPU, CDDAVolume::Type) { }; __declare_io_value(RightCD2RightSPU, CDDAVolume::Type) { }; __declare_io_value(RightCD2LeftSPU, CDDAVolume::Type) { }; struct Interrupt { enum Type : uint8_t { None = 0, DataReady = 1, Complete = 2, Acknowledge = 3, DataEnd = 4, DiskError = 5 }; static void enable(IOPort& port) { port.write(port.read().set(InterruptEnable::InterruptTypValue.range_max())); } static void enable_extended(IOPort& port) { port.write(InterruptEnable::from(InterruptEnable::InterruptTypValue.range_max(), InterruptEnable::UnknownIRQ, InterruptEnable::CommandStartIRQ)); } static Type get_type(const IOPort& port) { return static_cast(port.read().get(InterruptFlag::InterruptTypValue)); } static void ack(IOPort& port) { port.write(port.read().set(InterruptFlag::InterruptTypValue.range_max())); } static void ack_extended(IOPort& port) { port.write(InterruptFlag::from(InterruptFlag::InterruptTypValue.range_max(), InterruptEnable::UnknownIRQ, InterruptEnable::CommandStartIRQ)); } }; struct Command { struct Desc { uint8_t id; Interrupt::Type complete_irq; }; static constexpr Desc GetStat{0x01, Interrupt::Type::Acknowledge}; static constexpr Desc SetLoc{0x02, Interrupt::Type::Acknowledge}; static constexpr Desc Play{0x03, Interrupt::Type::Acknowledge}; static constexpr Desc ReadN{0x06, Interrupt::Type::DataReady}; static constexpr Desc Pause{0x09, Interrupt::Type::Complete}; static constexpr Desc Init{0x0A, Interrupt::Type::Complete}; static constexpr Desc Filter{0x0D, Interrupt::Type::Acknowledge}; static constexpr Desc SetMode{0x0E, Interrupt::Type::Acknowledge}; static constexpr Desc GetLocP{0x11, Interrupt::Type::Acknowledge}; static constexpr Desc GetTN{0x13, Interrupt::Type::Acknowledge}; static constexpr Desc GetTD{0x14, Interrupt::Type::Acknowledge}; static constexpr Desc ReadS{0x1B, Interrupt::Type::DataReady}; }; static constexpr auto IORegister1Adr = 0x1F801801; static constexpr auto IORegister2Adr = 0x1F801802; static constexpr auto IORegister3Adr = 0x1F801803; __declare_io_port(, IndexStatus, 0x1F801800); struct PortIndex0 { __declare_io_port(inline const, ResponseFifo, IORegister1Adr); __declare_io_port(inline, CommandFifo, IORegister1Adr); __declare_io_port(inline const, DataFifo, IORegister2Adr); __declare_io_port(inline const, DataFifo16, IORegister2Adr); __declare_io_port(inline, ParameterFifo, IORegister2Adr); __declare_io_port(inline const, InterruptEnable, IORegister3Adr); __declare_io_port(inline, Request, IORegister3Adr); static void change_to() { IndexStatus.write({Index::Index0}); } }; struct PortIndex1 { __declare_io_port(inline const, ResponseFifo, IORegister1Adr); __declare_io_port(inline, SoundMapDataOut, IORegister1Adr); __declare_io_port(inline const, DataFifo, IORegister2Adr); __declare_io_port(inline const, DataFifo16, IORegister2Adr); __declare_io_port(inline, InterruptEnable, IORegister2Adr); __declare_io_port_w_type(inline, struct InterruptEnable, InterruptFlag, IORegister3Adr); static void change_to() { IndexStatus.write({Index::Index1}); } }; struct PortIndex2 { __declare_io_port(inline const, ResponseFifo, IORegister1Adr); __declare_io_port(inline, SoundMapCoding, IORegister1Adr); __declare_io_port(inline const, DataFifo, IORegister2Adr); __declare_io_port(inline const, DataFifo16, IORegister2Adr); __declare_io_port(inline, LeftCD2LeftSPU, IORegister2Adr); __declare_io_port(inline const, InterruptEnable, IORegister3Adr); __declare_io_port(inline, LeftCD2RightSPU, IORegister3Adr); static void change_to() { IndexStatus.write({Index::Index2}); } }; struct PortIndex3 { __declare_io_port(inline const, ResponseFifo, IORegister1Adr); __declare_io_port(inline, RightCD2RightSPU, IORegister1Adr); __declare_io_port(inline const, DataFifo, IORegister2Adr); __declare_io_port(inline const, DataFifo16, IORegister2Adr); __declare_io_port(inline, RightCD2LeftSPU, IORegister1Adr); __declare_io_port_w_type(inline const, struct InterruptEnable, InterruptFlag, IORegister3Adr); __declare_io_port( inline, AudioVolumeApply, IORegister3Adr); static void change_to() { IndexStatus.write({Index::Index3}); } }; #undef __declare_index_io_port #undef __declare_index_io_port_const } }