Cog/Frameworks/lazyusf/lazyusf/dma.c

180 lines
4.6 KiB
C

/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include <string.h>
#include "main.h"
#include "cpu.h"
#include "usf.h"
#include "usf_internal.h"
void PI_DMA_READ (usf_state_t * state) {
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts(state);
return;
}
void PI_DMA_WRITE (usf_state_t * state) {
uint32_t i;
PI_STATUS_REG |= PI_STATUS_DMA_BUSY;
if ( PI_DRAM_ADDR_REG + PI_WR_LEN_REG + 1 > state->RdramSize) {
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts(state);
return;
}
if ( PI_CART_ADDR_REG >= 0x08000000 && PI_CART_ADDR_REG <= 0x08010000) {
return;
}
if ( PI_CART_ADDR_REG >= 0x10000000 && PI_CART_ADDR_REG <= 0x1FBFFFFF) {
PI_CART_ADDR_REG -= 0x10000000;
for (i = 0; i < PI_WR_LEN_REG + 1; i ++) {
*(state->N64MEM+((PI_DRAM_ADDR_REG + i) ^ 3)) = *PageROM(state, (PI_CART_ADDR_REG + i) ^ 3);
}
PI_CART_ADDR_REG += 0x10000000;
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts(state);
CheckTimer(state);
return;
}
PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
MI_INTR_REG |= MI_INTR_PI;
CheckInterrupts(state);
}
void SI_DMA_READ (usf_state_t * state) {
if ((int32_t)SI_DRAM_ADDR_REG > (int32_t)state->RdramSize) {
return;
}
PifRamRead(state);
SI_DRAM_ADDR_REG &= 0xFFFFFFF8;
if ((int32_t)SI_DRAM_ADDR_REG < 0) {
int32_t count, RdramPos;
RdramPos = (int32_t)SI_DRAM_ADDR_REG;
for (count = 0; count < 0x40; count++, RdramPos++) {
if (RdramPos < 0) { continue; }
state->N64MEM[RdramPos ^3] = state->PIF_Ram[count];
}
} else {
int32_t count, RdramPos;
RdramPos = (uint32_t)SI_DRAM_ADDR_REG;
for (count = 0; count < 0x40; count++, RdramPos++) {
if (RdramPos < 0) { continue; }
state->N64MEM[RdramPos ^3] = state->PIF_Ram[count];
}
}
MI_INTR_REG |= MI_INTR_SI;
SI_STATUS_REG |= SI_STATUS_INTERRUPT;
CheckInterrupts(state);
}
void SI_DMA_WRITE (usf_state_t * state) {
if ((int32_t)SI_DRAM_ADDR_REG > (int32_t)state->RdramSize) {
return;
}
SI_DRAM_ADDR_REG &= 0xFFFFFFF8;
if ((int32_t)SI_DRAM_ADDR_REG < 0) {
int32_t count, RdramPos;
RdramPos = (int32_t)SI_DRAM_ADDR_REG;
for (count = 0; count < 0x40; count++, RdramPos++) {
if (RdramPos < 0) { state->PIF_Ram[count] = 0; continue; }
state->PIF_Ram[count] = state->N64MEM[RdramPos ^3];
}
} else {
int32_t count, RdramPos;
RdramPos = (int32_t)SI_DRAM_ADDR_REG;
for (count = 0; count < 0x40; count++, RdramPos++) {
if (RdramPos < 0) { state->PIF_Ram[count] = 0; continue; }
state->PIF_Ram[count] = state->N64MEM[RdramPos ^3];
}
}
PifRamWrite(state);
MI_INTR_REG |= MI_INTR_SI;
SI_STATUS_REG |= SI_STATUS_INTERRUPT;
CheckInterrupts(state);
}
void SP_DMA_READ (usf_state_t * state) {
SP_DRAM_ADDR_REG &= 0x1FFFFFFF;
if (SP_DRAM_ADDR_REG > state->RdramSize) {
SP_DMA_BUSY_REG = 0;
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
return;
}
if (SP_RD_LEN_REG + 1 + (SP_MEM_ADDR_REG & 0xFFF) > 0x1000) {
return;
}
memcpy( state->DMEM + (SP_MEM_ADDR_REG & 0x1FFF), state->N64MEM + SP_DRAM_ADDR_REG,
SP_RD_LEN_REG + 1 );
SP_DMA_BUSY_REG = 0;
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
MI_INTR_REG &= ~MI_INTR_SP;
CheckInterrupts(state);
CheckTimer(state);
}
void SP_DMA_WRITE (usf_state_t * state) {
if (SP_DRAM_ADDR_REG > state->RdramSize) {
return;
}
if (SP_WR_LEN_REG + 1 + (SP_MEM_ADDR_REG & 0xFFF) > 0x1000) {
return;
}
memcpy( state->N64MEM + SP_DRAM_ADDR_REG, state->DMEM + (SP_MEM_ADDR_REG & 0x1FFF),
SP_WR_LEN_REG + 1);
SP_DMA_BUSY_REG = 0;
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
}