#pragma once
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/SPU/spu.hpp>

namespace JabyEngine {
    namespace SPU {
        namespace internal {
            struct DMA {
                static void wait() {
                    DMA_IO::SPU.wait();
                    while(SPU_IO::StatusRegister.read().is_set(SPU_IO_Values::StatusRegister::TransferBusy));
                }

                static void end() {
                    SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop);
                }

                struct Receive {
                    static void prepare() {
                        end();
                        SPU_IO::DataTransferControl.write(SPU_IO_Values::DataTransferControl::NormalTransferMode());
                        SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop);
                    }

                    static void set_src(uintptr_t adr) {
                        DMA_IO::SPU.set_adr(adr);
                    }

                    static void set_dst(SPU::SRAMAdr adr) {
                        SPU_IO::SRAMTransferAdr.write(adr);
                        SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::DMAWrite);
                    }

                    static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) {
                        using SyncMode1 = DMA_IO_Values::BCR::SyncMode1;

                        DMA_IO::SPU.block_ctrl.write(DMA_IO_Values::BCR::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount)));
                        DMA_IO::SPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartSPUReceive());
                    }
                };
            };
        }
    }
}
