#pragma once #include "cd_types.hpp" #include #include namespace JabyEngine { namespace CD { namespace internal { enum struct State { Ready = 0, Done = 0, XAMode, Reading, BufferFull, Error, }; extern State current_state; extern volatile uint8_t cmd_interrupt_bit; extern uint8_t rel_last_send_cmd; extern uint8_t last_send_cmd; struct Command { struct Internal { static void wait_completed(CD_IO::Interrupt::Type irq) { while(!bit::is_set(cmd_interrupt_bit, irq)); } static void wait_completed_irq(CD_IO::Interrupt::Type irq) { static const auto get_next_irq = []() -> CD_IO::Interrupt::Type { CD_IO::Interrupt::Type cur_irq; do { cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag); if(cur_irq == CD_IO::Interrupt::Acknowledge) { printf("Rand ACK for 0x%X\n", last_send_cmd); } if(cur_irq == CD_IO::Interrupt::Complete) { printf("Rand Comp for 0x%X\n", last_send_cmd); } } while(cur_irq == CD_IO::Interrupt::None); CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag); cmd_interrupt_bit = bit::set(cmd_interrupt_bit, cur_irq); return cur_irq; }; CD_IO::PortIndex1::change_to(); while(get_next_irq() != irq); CD_IO::PortIndex0::change_to(); } template static void send(IOPort& cmd_fifo, IOPort& parameter_fifo, CD_IO::Command::Desc cmd, ARGS...args) { while(CD_IO::IndexStatus.read().is_set(CD_IO::IndexStatus::IsTransmissionBusy)); SysCall::EnterCriticalSection(); cmd_interrupt_bit = 0; CD_IO::PortIndex0::change_to(); ((parameter_fifo.write(CD_IO::ParameterFifo{args})),...); cmd_fifo.write(CD_IO::CommandFifo{cmd.id}); rel_last_send_cmd = cmd.id; last_send_cmd = cmd.id; SysCall::ExitCriticalSection(); } template static void send_irq(IOPort& cmd_fifo, IOPort& parameter_fifo, CD_IO::Command::Desc cmd, ARGS...args) { while(CD_IO::IndexStatus.read().is_set(CD_IO::IndexStatus::IsTransmissionBusy)); CD_IO::PortIndex0::change_to(); ((parameter_fifo.write(CD_IO::ParameterFifo{args})),...); cmd_fifo.write(CD_IO::CommandFifo{cmd.id}); rel_last_send_cmd = cmd.id; last_send_cmd = cmd.id; } }; // Requires Index 0 template static void send_wait(CD_IO::Command::Desc cmd, ARGS...args) { Internal::send(CD_IO::PortIndex0::CommandFifo, CD_IO::PortIndex0::ParameterFifo, cmd, args...); Internal::wait_completed(cmd.complete_irq); } // Requires Index 0 template static void send_wait_irq(CD_IO::Command::Desc cmd, ARGS...args) { Internal::send_irq(CD_IO::PortIndex0::CommandFifo, CD_IO::PortIndex0::ParameterFifo, cmd, args...); Internal::wait_completed_irq(cmd.complete_irq); } }; namespace IRQ { void read_sector_to0(uint32_t* dst, size_t bytes); void resume_at0(const BCDTimeStamp& cd_time); } static State read_current_state() { return const_cast(current_state); } void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator); void continue_reading(); BCDTimeStamp get_loc(); void enable_CDDA(); void enable_CDXA(bool double_speed); static void pause() { CD_IO::PortIndex0::change_to(); Command::send_wait(CD_IO::Command::Pause); } } } }