Skip to content
Snippets Groups Projects
dma.cc 2.37 KiB
Newer Older
#include <cpu/iop/dma.h>
#include <common/memory.h>
#include <fmt/color.h>

namespace iop
{
	/* DMA Controller class implementation. */
	DMAController::DMAController(ComponentManager* manager) :
		manager(manager)
	{
	}

	void DMAController::tick()
	{
	}

	void DMAController::transfer_finished(DMAChannels dma_channel)
	{
	}

	void DMAController::start(DMAChannels dma_channel)
	{
		DMAChannel& channel = channels[dma_channel];

		/* Start linked list copy routine. */
		switch (channel.channel_ctrl.transfer_mode)
		case TransferMode::Linked_List:	
			list_copy(dma_channel); break;
		default:
			block_copy(dma_channel);
		}

		/* Complete the transfer. */
		transfer_finished(dma_channel);
	}

	void DMAController::block_copy(DMAChannels dma_channel)
	{
	}

	void DMAController::list_copy(DMAChannels dma_channel)
	{
	}

	uint32_t DMAController::read(uint32_t address)
	{
		/* Get channel information from address. */
		bool group = address & 0x100;
		uint16_t channel_num = (address & 0x70) >> 4;
		uint16_t offset = (address & 0xf) >> 2;
		
		uint32_t* ptr = nullptr;
		if (channel_num >= 0 && channel_num <= 6) 
		{
			ptr = (uint32_t*)&channels[channel_num + group * 7] + offset;
		}
		else if (channel_num == 7) 
		{
			ptr = (uint32_t*)&globals + 2 * offset + group;
		}
		else
		{
			fmt::print("[IOP DMA] Invalid channel number {:d}\n", channel_num);
			std::abort();
		fmt::print("[IOP DMA] Reading {:#x} from DMA channel {:d} at address {:#x}\n", *ptr, channel_num, address);
		return *ptr;
	void DMAController::write(uint32_t address, uint32_t data)
	{
		/* Get channel information from address. */
		bool group = address & 0x100;
		uint16_t channel_num = (address & 0x70) >> 4;
		uint16_t offset = (address & 0xf) >> 2;

		fmt::print("[IOP DMA] Writing {:#x} to DMA channel {:d} at address {:#x}\n", data, channel_num, address);

		if (channel_num >= 0 && channel_num <= 6) 
		{
			auto ptr = (uint32_t*)&channels[channel_num + group * 7] + offset;
			*ptr = data;
		}
		else if (channel_num == 7) 
		{
			auto ptr = (uint32_t*)&globals + 2 * offset + group;
			*ptr = data;

			if (offset == 4 && !group)
				/* Handle special case for writing to DICR */
				auto& irq = globals.dicr;
				irq.master_flag = irq.force || (irq.master_enable && ((irq.enable & irq.flags) > 0));
		else
		{
			fmt::print("[IOP DMA] Invalid channel number {:d}\n", channel_num);
			std::abort();
		}