/*
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see .
*/
#include "sh4_if.h"
#include "sh4_mem.h"
#include "modules/mmu.h"
#include "hw/pvr/pvr_mem.h"
static u32 CCN_QACR_TR[2];
template
void DYNACALL do_sqw(u32 Dest, const SQBuffer *sqb)
{
u32 Address;
//Translate the SQ addresses as needed
if (mmu_on)
{
mmu_TranslateSQW(Dest, &Address);
}
else
{
//sanity/optimisation check
//verify(CCN_QACR_TR[0]==CCN_QACR_TR[1]);
u32 QACR = CCN_QACR_TR[0];
//QACR has already 0xE000_0000
Address = QACR + (Dest & ~0x1f);
}
if (((Address >> 26) & 7) != 4)//Area 4
{
const SQBuffer *sq = &sqb[(Dest >> 5) & 1];
WriteMemBlock_nommu_sq(Address, sq);
}
else
{
TAWriteSQ(Address, sqb);
}
}
void DYNACALL do_sqw_mmu(u32 dst) {
do_sqw(dst, sq_both);
}
static void DYNACALL do_sqw_simplemmu(u32 dst, const SQBuffer *sqb) {
do_sqw(dst, sqb);
}
//yes, this micro optimization makes a difference
static void DYNACALL do_sqw_nommu_area_3(u32 dst, const SQBuffer *sqb)
{
SQBuffer *pmem = (SQBuffer *)((u8 *)sqb + sizeof(Sh4RCB::sq_buffer) + sizeof(Sh4RCB::cntx) + 0x0C000000);
pmem += (dst & (RAM_SIZE_MAX - 1)) >> 5;
*pmem = sqb[(dst >> 5) & 1];
}
static void DYNACALL do_sqw_nommu_area_3_nonvmem(u32 dst, const SQBuffer *sqb)
{
u8* pmem = &mem_b[0];
memcpy((SQBuffer *)&pmem[dst & (RAM_MASK - 0x1F)], &sqb[(dst >> 5) & 1], sizeof(SQBuffer));
}
static void DYNACALL do_sqw_nommu_full(u32 dst, const SQBuffer *sqb) {
do_sqw(dst, sqb);
}
void setSqwHandler()
{
if (CCN_MMUCR.AT == 1)
{
do_sqw_nommu = &do_sqw_simplemmu;
}
else
{
u32 area = CCN_QACR0.Area;
CCN_QACR_TR[0] = (area << 26) - 0xE0000000; //-0xE0000000 because 0xE0000000 is added on the translation again ...
switch (area)
{
case 3:
if (addrspace::virtmemEnabled())
do_sqw_nommu = &do_sqw_nommu_area_3;
else
do_sqw_nommu = &do_sqw_nommu_area_3_nonvmem;
break;
case 4:
do_sqw_nommu = &TAWriteSQ;
break;
default:
do_sqw_nommu = &do_sqw_nommu_full;
break;
}
}
}