241 lines
9.6 KiB
C++
241 lines
9.6 KiB
C++
#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<typename T>
|
|
static constexpr T words_to_sectors(T size) {
|
|
return (size + static_cast<T>(DataSector::SizeWords - 1))/static_cast<T>(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<uint8_t>(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<InterruptEnable>& port) {
|
|
port.write(port.read().set(InterruptEnable::InterruptTypValue.range_max<uint8_t>()));
|
|
}
|
|
|
|
static void enable_extended(IOPort<InterruptEnable>& port) {
|
|
port.write(InterruptEnable::from(InterruptEnable::InterruptTypValue.range_max<uint8_t>(), InterruptEnable::UnknownIRQ, InterruptEnable::CommandStartIRQ));
|
|
}
|
|
|
|
static Type get_type(const IOPort<InterruptFlag>& port) {
|
|
return static_cast<Type>(port.read().get(InterruptFlag::InterruptTypValue));
|
|
}
|
|
|
|
static void ack(IOPort<InterruptFlag>& port) {
|
|
port.write(port.read().set(InterruptFlag::InterruptTypValue.range_max<uint8_t>()));
|
|
}
|
|
|
|
static void ack_extended(IOPort<InterruptFlag>& port) {
|
|
port.write(InterruptFlag::from(InterruptFlag::InterruptTypValue.range_max<uint8_t>(), 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 Demute{0x0C, Interrupt::Type::Acknowledge};
|
|
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
|
|
}
|
|
} |