Do not use threads for CD IRQs anymore

This commit is contained in:
Jaby 2024-10-05 11:14:33 +02:00
parent 419e7b7bc3
commit ca1fd5f911
7 changed files with 163 additions and 156 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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();*/
}
}
}

View File

@ -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();

View File

@ -9,65 +9,25 @@
// 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 BCDTimeStamp send_read_cmd0(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);
Command::send(cmd);
return loc;
}
static void send_read_n0(uint32_t lba) {
send_read_cmd0(lba, CD_IO::Command::ReadN);
current_state = State::Reading;
}
namespace IRQ {
static void read_sector_dma0(uint32_t* dst, size_t bytes) {
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));
};
@ -87,88 +47,17 @@ namespace JabyEngine {
ReadSector(dst, bytes);
}
void read_sector_to0(uint32_t* dst, size_t bytes) {
// We only support DMA rn
read_sector_dma0(dst, bytes);
static BCDTimeStamp send_read_cmd(uint32_t lba, CD_IO::Command::Desc cmd) {
const auto loc = BCDTimeStamp::from(lba);
// Do we ever want to support reading via IO Port?
// Doesn't seem to important when we can use DMA
Command::send(CD_IO::Command::SetLoc, loc.min, loc.sec, loc.sector);
Command::send(cmd);
return loc;
}
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);
}
}
static void send_read_n(uint32_t lba) {
send_read_cmd(lba, CD_IO::Command::ReadN);
current_state = State::Reading;
}
void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) {
@ -176,7 +65,7 @@ namespace JabyEngine {
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);

View File

@ -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();
}
}
}
}
}