#ifndef __JABYENGINE_CD_IO_HPP__ #define __JABYENGINE_CD_IO_HPP__ #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; }; typedef struct IndexStatus : public ComplexBitMap { 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); } IndexStatus_t; struct InterruptEnable : public ComplexBitMap { 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; struct Request : public ComplexBitMap { static constexpr auto WantCommandStartIRQ = Bit(5); static constexpr auto WantData = Bit(7); }; struct SoundMapCoding : public ComplexBitMap { 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); }; struct AudioVolumeApply : public ComplexBitMap { static constexpr auto Mute = Bit(0); static constexpr auto ApplyChanges = Bit(5); }; typedef VolatilePOD ResponseFifo_t; typedef VolatilePOD CommandFifo_t; typedef VolatilePOD DataFifo_t; typedef VolatilePOD DataFifo16_t; typedef VolatilePOD ParameterFifo_t; typedef VolatilePOD SoundMapDataOut_t; typedef VolatilePOD VolumeRegister_t; typedef VolatileBitMapPOD InterruptEnableRegister_t; typedef VolatileBitMapPOD InterruptFlagRegister_t; typedef VolatileBitMapPOD RequestRegister_t; typedef VolatileBitMapPOD SoundMapCodingInfo_t; typedef VolatileBitMapPOD AudioVolumeApplyChange_t; struct Interrupt { enum Type : uint8_t { None = 0, DataReady = 1, Complete = 2, Acknowledge = 3, DataEnd = 4, DiskError = 5 }; static void enable(InterruptEnableRegister_t& port) { port.write(InterruptEnable::InterruptTypValue.max()); } static void enable_extended(InterruptEnableRegister_t& port) { port.write({InterruptEnable::with(InterruptEnable::InterruptTypValue.max(), InterruptEnable::UnknownIRQ, InterruptEnable::CommandStartIRQ)}); } static Type get_type(const InterruptFlagRegister_t& port) { return static_cast(port.read().get_value(InterruptFlag::InterruptTypValue)); } static void ack(InterruptFlagRegister_t& port) { port.write(InterruptFlag::InterruptTypValue.max()); } static void ack_extended(InterruptFlagRegister_t& port) { port.write({InterruptFlag::with(InterruptFlag::InterruptTypValue.max(), InterruptEnable::UnknownIRQ, InterruptEnable::CommandStartIRQ)}); } }; struct Command { struct Info { uint8_t id; Interrupt::Type complete_irq; }; static constexpr Info GetStat{0x01, Interrupt::Type::Acknowledge}; static constexpr Info SetLoc{0x02, Interrupt::Type::Acknowledge}; static constexpr Info ReadN{0x06, Interrupt::Type::DataReady}; static constexpr Info Pause{0x09, Interrupt::Type::Complete}; static constexpr Info Init{0x0A, Interrupt::Type::Complete}; static constexpr Info SetMode{0x0E, Interrupt::Type::Acknowledge}; }; static constexpr auto IORegister1Adr = 0x1F801801; static constexpr auto IORegister2Adr = 0x1F801802; static constexpr auto IORegister3Adr = 0x1F801803; __declare_io_port_global(IndexStatus_t, IndexStatus, 0x1F801800); #define __declare_index_io_port(type, name, adr) __cast_io_adr_with_type(inline, type, name, adr) #define __declare_index_io_port_const(type, name, adr) __cast_io_adr_with_type(const inline, type, name, adr) struct PortIndex0 { __declare_index_io_port_const(ResponseFifo_t, ResponseFifo, IORegister1Adr); __declare_index_io_port( CommandFifo_t, CommandFifo, IORegister1Adr); __declare_index_io_port_const(DataFifo_t, DataFifo, IORegister2Adr); __declare_index_io_port_const(DataFifo16_t, DataFifo16, IORegister2Adr); __declare_index_io_port( ParameterFifo_t, ParameterFifo, IORegister2Adr); __declare_index_io_port_const(InterruptEnableRegister_t, InterruptEnableRegister, IORegister3Adr); __declare_index_io_port( RequestRegister_t, RequestRegister, IORegister3Adr); static void change_to() { IndexStatus.write({static_cast(Index::Index0)}); } }; struct PortIndex1 { __declare_index_io_port_const(ResponseFifo_t, ResponseFifo, IORegister1Adr); __declare_index_io_port( SoundMapDataOut_t, SoundMapDataOut, IORegister1Adr); __declare_index_io_port_const(DataFifo_t, DataFifo, IORegister2Adr); __declare_index_io_port_const(DataFifo16_t, DataFifo16, IORegister2Adr); __declare_index_io_port( InterruptEnableRegister_t, InterruptEnableRegister, IORegister2Adr); __declare_index_io_port(InterruptFlagRegister_t, InterruptFlagRegister, IORegister3Adr); static void change_to() { IndexStatus.write({static_cast(Index::Index1)}); } }; struct PortIndex2 { __declare_index_io_port_const(ResponseFifo_t, ResponseFifo, IORegister1Adr); __declare_index_io_port( SoundMapCodingInfo_t, SoundMapCodingInfo, IORegister1Adr); __declare_index_io_port_const(DataFifo_t, DataFifo, IORegister2Adr); __declare_index_io_port_const(DataFifo16_t, DataFifo16, IORegister2Adr); __declare_index_io_port( VolumeRegister_t, LeftCD2LeftSPU, IORegister2Adr); __declare_index_io_port_const(InterruptEnableRegister_t, InterruptEnableRegister, IORegister3Adr); __declare_index_io_port( VolumeRegister_t, LeftCD2RightSPU, IORegister3Adr); static void change_to() { IndexStatus.write({static_cast(Index::Index2)}); } }; struct PortIndex3 { __declare_index_io_port_const(ResponseFifo_t, ResponseFifo, IORegister1Adr); __declare_index_io_port( VolumeRegister_t, RightCD2RightSPU, IORegister1Adr); __declare_index_io_port_const(DataFifo_t, DataFifo, IORegister2Adr); __declare_index_io_port_const(DataFifo16_t, DataFifo16, IORegister2Adr); __declare_index_io_port( VolumeRegister_t, RightCD2LeftSPU, IORegister1Adr); __declare_index_io_port_const(InterruptFlagRegister_t, InterruptFlagRegister, IORegister3Adr); __declare_index_io_port( AudioVolumeApplyChange_t, AudioVolumeApplyChange, IORegister3Adr); static void change_to() { IndexStatus.write({static_cast(Index::Index3)}); } }; #undef __declare_index_io_port #undef __declare_index_io_port_const } } #endif //!__JABYENGINE_CD_IO_HPP__