Do not use threads for CD IRQs anymore
This commit is contained in:
parent
419e7b7bc3
commit
ca1fd5f911
|
@ -8,6 +8,21 @@
|
|||
namespace JabyEngine {
|
||||
namespace CD {
|
||||
namespace internal {
|
||||
struct File {
|
||||
uint32_t cur_lba;
|
||||
uint32_t dst_lba;
|
||||
|
||||
void set_from(const AutoLBAEntry& file_info) {
|
||||
this->cur_lba = file_info.get_lba();
|
||||
this->dst_lba = this->cur_lba + file_info.get_size_in_sectors();
|
||||
}
|
||||
|
||||
bool done_processing() {
|
||||
this->cur_lba++;
|
||||
return this->cur_lba == this->dst_lba;
|
||||
}
|
||||
};
|
||||
|
||||
enum struct State {
|
||||
Ready = 0,
|
||||
Done = 0,
|
||||
|
@ -50,12 +65,6 @@ namespace JabyEngine {
|
|||
}
|
||||
};
|
||||
|
||||
namespace IRQ {
|
||||
void process(uint32_t 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<volatile State&>(current_state);
|
||||
}
|
||||
|
@ -64,6 +73,15 @@ namespace JabyEngine {
|
|||
void end_read_file();
|
||||
void continue_reading();
|
||||
|
||||
void copy_from_sector(uint32_t* dst, size_t bytes);
|
||||
template<typename T>
|
||||
T copy_from_sector() {
|
||||
T data;
|
||||
|
||||
copy_from_sector(reinterpret_cast<uint32_t*>(&data), sizeof(T));
|
||||
return data;
|
||||
}
|
||||
|
||||
BCDTimeStamp get_loc();
|
||||
BCDTimeStamp get_locL();
|
||||
|
||||
|
@ -71,6 +89,10 @@ namespace JabyEngine {
|
|||
void enable_CDDA();
|
||||
void enable_CDXA(bool double_speed);
|
||||
|
||||
static void set_loc(const BCDTimeStamp& cd_time) {
|
||||
Command::send_no_wait(CD_IO::Command::SetLoc, cd_time.min, cd_time.sec, cd_time.sector);
|
||||
}
|
||||
|
||||
static void pause() {
|
||||
Command::send(CD_IO::Command::Pause);
|
||||
}
|
||||
|
|
|
@ -17,13 +17,10 @@ namespace JabyEngine {
|
|||
switch(irq) {
|
||||
case CD_IO::Interrupt::DataReady: {
|
||||
// The IRQ stack is 0x1000 bytes large so this should fit
|
||||
CD::RawXADataSector xa_file;
|
||||
|
||||
CD_IO::PortIndex0::change_to();
|
||||
CD::IRQ::read_sector_to0(reinterpret_cast<uint32_t*>(&xa_file), sizeof(CD::RawXADataSector));
|
||||
const auto xa_file = CD::copy_from_sector<CD::RawXADataSector>();
|
||||
if(setting.channel == xa_file.sub_header.channel_number) {
|
||||
CD::IRQ::resume_at0(setting.start_loc);
|
||||
CD::Command::send(CD_IO::Command::ReadS);
|
||||
CD::set_loc(setting.start_loc);
|
||||
CD::Command::send_no_wait(CD_IO::Command::ReadS);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
|
@ -7,17 +7,18 @@ namespace JabyEngine {
|
|||
namespace InternalCallback = JabyEngine::Callback::internal;
|
||||
|
||||
void setup() {
|
||||
SysCall::EnterCriticalSection();
|
||||
// We do not use threads anymore but keep the code for it
|
||||
/*SysCall::EnterCriticalSection();
|
||||
/*InternalCallback::VSync::thread_handle = SysCall::OpenThread(
|
||||
InternalCallback::VSync::routine,
|
||||
&InternalCallback::VSync::stack[InternalCallback::VSync::StackSize - 1],
|
||||
SysCall::get_gp()
|
||||
);
|
||||
Thread::set_user_mode_for(InternalCallback::VSync::thread_handle);*/
|
||||
Thread::set_user_mode_for(InternalCallback::VSync::thread_handle);
|
||||
|
||||
InternalCallback::CD::thread_handle = Thread::create(InternalCallback::CD::routine, InternalCallback::CD::stack);
|
||||
Thread::set_user_mode_for(InternalCallback::CD::thread_handle);
|
||||
SysCall::ExitCriticalSection();
|
||||
SysCall::ExitCriticalSection();*/
|
||||
}
|
||||
}
|
||||
}
|
|
@ -76,7 +76,8 @@ namespace JabyEngine {
|
|||
|
||||
BIOS::identify();
|
||||
enable_vanilla_bios();
|
||||
Callbacks::setup();
|
||||
// Not used anymore
|
||||
//Callbacks::setup();
|
||||
|
||||
__debug_boot_color_at(::JabyEngine::GPU::Color24::Grey(), DebugX, DebugY, DebugScale);
|
||||
DMA::setup();
|
||||
|
|
|
@ -9,51 +9,45 @@
|
|||
// TODO: Do not spawn a new thread for handling the CD interrupt but use that thread for loading files or something?
|
||||
// TODO: Can you use the GPU IO Port while also using DMA?
|
||||
namespace JabyEngine {
|
||||
namespace CDDA {
|
||||
extern CD::internal::BCDTimeStamp playing_track;
|
||||
}
|
||||
|
||||
namespace CDXA {
|
||||
CD::internal::State interrupt_handler(uint8_t irq);
|
||||
}
|
||||
|
||||
namespace CD {
|
||||
extern volatile uint32_t zero;
|
||||
|
||||
namespace internal {
|
||||
struct File {
|
||||
uint32_t cur_lba;
|
||||
uint32_t dst_lba;
|
||||
|
||||
void set_from(const AutoLBAEntry& file_info) {
|
||||
this->cur_lba = file_info.get_lba();
|
||||
this->dst_lba = this->cur_lba + file_info.get_size_in_sectors();
|
||||
}
|
||||
|
||||
bool done_processing() {
|
||||
this->cur_lba++;
|
||||
return this->cur_lba == this->dst_lba;
|
||||
}
|
||||
};
|
||||
extern SectorBufferAllocator sector_allocator;
|
||||
extern File cur_file;
|
||||
|
||||
static constexpr auto AudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::AutoPauseTrack, CD_IO_Values::Mode::CDDA);
|
||||
static constexpr auto DataSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::DoubleSpeed, CD_IO_Values::Mode::DataSector);
|
||||
static constexpr auto XAAudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::XADPCM, CD_IO_Values::Mode::WholeSector, CD_IO_Values::Mode::UseXAFilter);
|
||||
|
||||
namespace IRQ {
|
||||
static SysCall::InterruptVerifierResult verifier();
|
||||
static void handler(uint32_t);
|
||||
SysCall::InterruptVerifierResult verifier();
|
||||
void handler(uint32_t);
|
||||
}
|
||||
|
||||
static SectorBufferAllocator sector_allocator;
|
||||
static File cur_file;
|
||||
|
||||
auto irq_callback = SysCall::InterruptCallback::from(IRQ::verifier, IRQ::handler);
|
||||
State current_state = State::Ready;
|
||||
uint8_t irq_bit_pending = CD_IO::Interrupt::None;
|
||||
|
||||
auto irq_callback = SysCall::InterruptCallback::from(IRQ::verifier, IRQ::handler);
|
||||
static void read_sector_dma(uint32_t* dst, size_t bytes) {
|
||||
static const auto WaitSectorReady = []() {
|
||||
while(!CD_IO::IndexStatus.read().is_set(CD_IO_Values::IndexStatus::HasDataFifoData));
|
||||
};
|
||||
|
||||
static BCDTimeStamp send_read_cmd0(uint32_t lba, CD_IO::Command::Desc cmd) {
|
||||
static const auto ReadSector = [](uint32_t* dst, size_t bytes) {
|
||||
DMA_IO::CDROM.set_adr(reinterpret_cast<uintptr_t>(dst));
|
||||
DMA_IO::CDROM.block_ctrl.write(DMA_IO_Values::BCR::SyncMode0::for_cd(bytes >> 2));
|
||||
DMA_IO::CDROM.channel_ctrl.write(DMA_IO_Values::CHCHR::StartCDROM());
|
||||
|
||||
DMA_IO::CDROM.wait();
|
||||
CD_IO::PortIndex0::change_to();
|
||||
|
||||
CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::reset());
|
||||
};
|
||||
|
||||
WaitSectorReady();
|
||||
ReadSector(dst, bytes);
|
||||
}
|
||||
|
||||
static BCDTimeStamp send_read_cmd(uint32_t lba, CD_IO::Command::Desc cmd) {
|
||||
const auto loc = BCDTimeStamp::from(lba);
|
||||
|
||||
Command::send(CD_IO::Command::SetLoc, loc.min, loc.sec, loc.sector);
|
||||
|
@ -61,122 +55,17 @@ namespace JabyEngine {
|
|||
return loc;
|
||||
}
|
||||
|
||||
static void send_read_n0(uint32_t lba) {
|
||||
send_read_cmd0(lba, CD_IO::Command::ReadN);
|
||||
static void send_read_n(uint32_t lba) {
|
||||
send_read_cmd(lba, CD_IO::Command::ReadN);
|
||||
current_state = State::Reading;
|
||||
}
|
||||
|
||||
namespace IRQ {
|
||||
static void read_sector_dma0(uint32_t* dst, size_t bytes) {
|
||||
static const auto WaitSectorReady = []() {
|
||||
while(!CD_IO::IndexStatus.read().is_set(CD_IO_Values::IndexStatus::HasDataFifoData));
|
||||
};
|
||||
|
||||
static const auto ReadSector = [](uint32_t* dst, size_t bytes) {
|
||||
DMA_IO::CDROM.set_adr(reinterpret_cast<uintptr_t>(dst));
|
||||
DMA_IO::CDROM.block_ctrl.write(DMA_IO_Values::BCR::SyncMode0::for_cd(bytes >> 2));
|
||||
DMA_IO::CDROM.channel_ctrl.write(DMA_IO_Values::CHCHR::StartCDROM());
|
||||
|
||||
DMA_IO::CDROM.wait();
|
||||
CD_IO::PortIndex0::change_to();
|
||||
|
||||
CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::reset());
|
||||
};
|
||||
|
||||
WaitSectorReady();
|
||||
ReadSector(dst, bytes);
|
||||
}
|
||||
|
||||
void read_sector_to0(uint32_t* dst, size_t bytes) {
|
||||
// We only support DMA rn
|
||||
read_sector_dma0(dst, bytes);
|
||||
|
||||
// Do we ever want to support reading via IO Port?
|
||||
// Doesn't seem to important when we can use DMA
|
||||
}
|
||||
|
||||
void resume_at0(const BCDTimeStamp& cd_time) {
|
||||
Command::send(CD_IO::Command::SetLoc, cd_time.min, cd_time.sec, cd_time.sector);
|
||||
}
|
||||
|
||||
//######################################################################################################################
|
||||
|
||||
static SysCall::InterruptVerifierResult verifier() {
|
||||
if(Interrupt::is_irq(Interrupt::CDROM)) {
|
||||
Interrupt::ack_irq(Interrupt::CDROM);
|
||||
return SysCall::InterruptVerifierResult::ExecuteHandler;
|
||||
}
|
||||
|
||||
else {
|
||||
return SysCall::InterruptVerifierResult::SkipHandler;
|
||||
}
|
||||
}
|
||||
|
||||
static void handler(uint32_t x) {
|
||||
const auto old_status = CD_IO::IndexStatus.read();
|
||||
|
||||
CD_IO::PortIndex1::change_to();
|
||||
const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag);
|
||||
CD_IO::PortIndex1::change_to();
|
||||
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag);
|
||||
|
||||
irq_bit_pending = bit::clear(irq_bit_pending, cur_irq);
|
||||
|
||||
CD_IO::PortIndex0::change_to();
|
||||
if(cur_irq == CD_IO::Interrupt::DataReady) {
|
||||
CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::want_data());
|
||||
}
|
||||
|
||||
// No masking required because we can only write bit 0 - 2
|
||||
CD_IO::IndexStatus.write(old_status);
|
||||
Callback::internal::CD::execute(cur_irq);
|
||||
}
|
||||
|
||||
void process(uint32_t irq) {
|
||||
if(current_state != State::XAMode) {
|
||||
switch(irq) {
|
||||
case CD_IO::Interrupt::DataReady: {
|
||||
// Obtain sector content here
|
||||
auto* sector = sector_allocator.allocate_sector();
|
||||
if(sector) {
|
||||
//Now obtain sector
|
||||
read_sector_to0(sector->data, CD_IO::DataSector::SizeBytes);
|
||||
|
||||
if(cur_file.done_processing()) {
|
||||
current_state = State::Done;
|
||||
Command::send(CD_IO::Command::Pause);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
current_state = State::BufferFull;
|
||||
Command::send(CD_IO::Command::Pause);
|
||||
}
|
||||
} break;
|
||||
|
||||
case CD_IO::Interrupt::DataEnd: {
|
||||
resume_at0(CDDA::playing_track);
|
||||
Command::send(CD_IO::Command::Play);
|
||||
} break;
|
||||
|
||||
case CD_IO::Interrupt::DiskError: {
|
||||
current_state = State::Error;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
current_state = CDXA::interrupt_handler(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) {
|
||||
cur_file.set_from(file_info);
|
||||
sector_allocator = buffer_allocator;
|
||||
|
||||
enable_CD();
|
||||
send_read_n0(cur_file.cur_lba);
|
||||
send_read_n(cur_file.cur_lba);
|
||||
}
|
||||
|
||||
void end_read_file() {
|
||||
|
@ -186,10 +75,14 @@ namespace JabyEngine {
|
|||
void continue_reading() {
|
||||
if(current_state == State::BufferFull) {
|
||||
CD_IO::PortIndex0::change_to();
|
||||
send_read_n0(cur_file.cur_lba);
|
||||
send_read_n(cur_file.cur_lba);
|
||||
}
|
||||
}
|
||||
|
||||
void copy_from_sector(uint32_t* dst, size_t bytes) {
|
||||
read_sector_dma(dst, bytes);
|
||||
}
|
||||
|
||||
BCDTimeStamp get_loc() {
|
||||
Command::send_wait_response(CD_IO::Command::GetLocP);
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#include "../../internal-include/CD/cd_internal.hpp"
|
||||
#include <PSX/System/IOPorts/dma_io.hpp>
|
||||
|
||||
namespace JabyEngine {
|
||||
namespace CDDA {
|
||||
extern CD::internal::BCDTimeStamp playing_track;
|
||||
}
|
||||
|
||||
namespace CDXA {
|
||||
CD::internal::State interrupt_handler(uint8_t irq);
|
||||
}
|
||||
|
||||
namespace CD {
|
||||
namespace internal {
|
||||
SectorBufferAllocator sector_allocator;
|
||||
File cur_file;
|
||||
|
||||
namespace IRQ {
|
||||
static void process(uint32_t irq) {
|
||||
if(current_state != State::XAMode) {
|
||||
switch(irq) {
|
||||
case CD_IO::Interrupt::DataReady: {
|
||||
// Obtain sector content here
|
||||
auto* sector = sector_allocator.allocate_sector();
|
||||
if(sector) {
|
||||
//Now obtain sector
|
||||
copy_from_sector(sector->data, CD_IO::DataSector::SizeBytes);
|
||||
|
||||
if(cur_file.done_processing()) {
|
||||
current_state = State::Done;
|
||||
Command::send_no_wait(CD_IO::Command::Pause);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
current_state = State::BufferFull;
|
||||
Command::send_no_wait(CD_IO::Command::Pause);
|
||||
}
|
||||
} break;
|
||||
|
||||
case CD_IO::Interrupt::DataEnd: {
|
||||
set_loc(CDDA::playing_track);
|
||||
Command::send_no_wait(CD_IO::Command::Play);
|
||||
} break;
|
||||
|
||||
case CD_IO::Interrupt::DiskError: {
|
||||
current_state = State::Error;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
current_state = CDXA::interrupt_handler(irq);
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################################################################
|
||||
|
||||
SysCall::InterruptVerifierResult verifier() {
|
||||
if(Interrupt::is_irq(Interrupt::CDROM)) {
|
||||
Interrupt::ack_irq(Interrupt::CDROM);
|
||||
return SysCall::InterruptVerifierResult::ExecuteHandler;
|
||||
}
|
||||
|
||||
else {
|
||||
return SysCall::InterruptVerifierResult::SkipHandler;
|
||||
}
|
||||
}
|
||||
|
||||
void handler(uint32_t x) {
|
||||
const auto old_status = CD_IO::IndexStatus.read();
|
||||
|
||||
CD_IO::PortIndex1::change_to();
|
||||
const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag);
|
||||
CD_IO::PortIndex1::change_to();
|
||||
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag);
|
||||
|
||||
irq_bit_pending = bit::clear(irq_bit_pending, cur_irq);
|
||||
|
||||
CD_IO::PortIndex0::change_to();
|
||||
if(cur_irq == CD_IO::Interrupt::DataReady) {
|
||||
CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::want_data());
|
||||
}
|
||||
|
||||
process(cur_irq);
|
||||
// No masking required because we can only write bit 0 - 2
|
||||
CD_IO::IndexStatus.write(old_status);
|
||||
return SysCall::ReturnFromException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue