Skip to content

Commit

Permalink
Adding a few more operations.
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasnoble committed Sep 27, 2024
1 parent c659d40 commit dc8193a
Show file tree
Hide file tree
Showing 5 changed files with 361 additions and 28 deletions.
74 changes: 69 additions & 5 deletions src/mips/psyqo/cdrom-device.hh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ SOFTWARE.

namespace psyqo {

class GPU;

namespace Concepts {

template <typename T, typename = void>
Expand Down Expand Up @@ -124,6 +126,19 @@ class CDRomDevice final : public CDRom {
void readSectors(uint32_t sector, uint32_t count, void *buffer, eastl::function<void(bool)> &&callback) override;
TaskQueue::Task scheduleReadSectors(uint32_t sector, uint32_t count, void *buffer);

/**
* @brief Gets the size of the Table of Contents from the CDRom. Note that
* while the blocking variant is available because it is a fairly short
* operation with the CDRom controller, it can still block the system
* for roughly 2ms, which is a long time in the context of a 33MHz CPU.
*
* @param size The pointer to store the size of the TOC.
* @param callback The callback to call when the size is retrieved.
*/
void getTOCSize(unsigned *size, eastl::function<void(bool)> &&callback);
TaskQueue::Task scheduleGetTOCSize(unsigned *size);
unsigned getTOCSizeBlocking(GPU &);

/**
* @brief Reads the Table of Contents from the CDRom.
*
Expand All @@ -133,14 +148,52 @@ class CDRomDevice final : public CDRom {
* provided buffer starting at index 1 for the first track. Any tracks
* that are not present on the CD will not have their MSF structure
* filled in, so the application should ensure that the buffer is
* initialized to zero before calling this method.
* initialized to zero before calling this method. The blocking variant
* may take a total of 200ms to complete, depending on the number of
* tracks on the CD.
*
* @param toc The buffer to read the TOC into. Ideally, this buffer
* should be able to hold 100 `MSF` structures for safety.
* @param toc The buffer to read the TOC into.
* @param size The size of the buffer. Should be 100 to hold all possible tracks.
* @param callback The callback to call when the read is complete.
*/
void readTOC(MSF *toc, eastl::function<void(bool)> &&callback);
TaskQueue::Task scheduleReadTOC(MSF *toc);
void readTOC(MSF *toc, unsigned size, eastl::function<void(bool)> &&callback);
TaskQueue::Task scheduleReadTOC(MSF *toc, unsigned size);
bool readTOCBlocking(MSF *toc, unsigned size, GPU &);

/**
* @brief Mutes the CD audio for both CDDA and CDXA.
*
* @param callback The callback to call when the mute operation is complete.
*/
void mute(eastl::function<void(bool)> &&callback);
TaskQueue::Task scheduleMute();
void muteBlocking(GPU &);

/**
* @brief Unmutes the CD audio for both CDDA and CDXA.
*
* @param callback The callback to call when the unmute operation is complete.
*/
void unmute(eastl::function<void(bool)> &&callback);
TaskQueue::Task scheduleUnmute();
void unmuteBlocking(GPU &);

/**
* @brief Begins playing CDDA audio from a given starting point.
*
* @details This method will begin playing CDDA audio from a given
* starting point. The starting point is either a track number or
* an MSF value. The callback will be called when playback is complete,
* paused, or if an error occurs, which can be after the end of the
* track if `stopAtEndOfTrack` is set to true, or at the end of the
* disc if the last track is reached.
*
* @param start The starting point for playback.
* @param stopAtEndOfTrack If true, playback will stop at the end of the track.
* @param callback The callback to call when playback is complete.
*/
void playCDDA(MSF start, bool stopAtEndOfTrack, eastl::function<void(bool)> &&callback);
void playCDDA(unsigned track, bool stopAtEndOfTrack, eastl::function<void(bool)> &&callback);

/**
* @brief The action base class for the internal state machine.
Expand All @@ -167,6 +220,7 @@ class CDRomDevice final : public CDRom {
private:
void switchAction(ActionBase *action);
void irq();
void actionComplete();

friend class ActionBase;

Expand All @@ -175,6 +229,16 @@ class CDRomDevice final : public CDRom {
ActionBase *m_action = nullptr;
uint8_t m_state = 0;
bool m_success = false;
bool m_blocking = false;

struct BlockingAction {
BlockingAction(CDRomDevice *, GPU &);
~BlockingAction();

private:
CDRomDevice *m_device;
GPU &m_gpu;
};
};

} // namespace psyqo
3 changes: 2 additions & 1 deletion src/mips/psyqo/examples/task-demo/task-demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,12 @@ void TaskDemo::createScene() {
.then([this](auto task) {
m_text = "Success!";
syscall_puts("Success!\n");
ramsyscall_printf("Track count: %d\n", m_cdrom.getTOCSizeBlocking(gpu()));
m_systemCnfSize = m_request.entry.size;
m_done = true;
task->resolve();
})
.then(m_cdrom.scheduleReadTOC(m_toc))
.then(m_cdrom.scheduleReadTOC(m_toc, 100))
.then([this](auto task) {
for (unsigned i = 1; i < 100; i++) {
if (m_toc[i].m == 0 && m_toc[i].s == 0 && m_toc[i].f == 0) {

Check warning on line 124 in src/mips/psyqo/examples/task-demo/task-demo.cpp

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Complex Conditional

TaskDemo::createScene has 1 complex conditionals with 2 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
Expand Down
2 changes: 1 addition & 1 deletion src/mips/psyqo/hardware/cdrom.hh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ enum class CDL : uint8_t {
PAUSE = 9,
INIT = 10,
MUTE = 11,
DEMUTE = 12,
UNMUTE = 12,
SETFILTER = 13,
SETMODE = 14,
GETMODE = 15,
Expand Down
1 change: 1 addition & 0 deletions src/mips/psyqo/hardware/cpu.hh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct IRQReg : public Register<offset> {
void set(IRQ irq) { *this |= (static_cast<uint32_t>(irq)); }
void clear(IRQ irq) { *this &= ~(static_cast<uint32_t>(irq)); }
void clear() { Register<offset>::access() = 0; }
bool isSet(IRQ irq) const { return (*this & static_cast<uint32_t>(irq)) != 0; }
};

extern IRQReg<0x0070> IReg;
Expand Down
Loading

0 comments on commit dc8193a

Please sign in to comment.