flycast/core/hw/sh4/sh4_mmr.cpp

949 lines
18 KiB
C++
Raw Normal View History

2013-12-19 17:10:14 +00:00
/*
Sh4 internal register routing (P4 & 'area 7')
*/
2020-01-25 10:00:34 +00:00
#include <array>
2013-12-19 17:10:14 +00:00
#include "types.h"
#include "sh4_mmr.h"
#include "hw/mem/_vmem.h"
#include "modules/mmu.h"
#include "modules/ccn.h"
#include "modules/modules.h"
#include "sh4_cache.h"
2013-12-19 17:10:14 +00:00
//64bytes of sq // now on context ~
2020-01-25 10:00:34 +00:00
std::array<u8, OnChipRAM_SIZE> OnChipRAM;
2013-12-19 17:10:14 +00:00
//All registers are 4 byte aligned
2020-01-25 10:00:34 +00:00
std::array<RegisterStruct, 18> CCN;
std::array<RegisterStruct, 9> UBC;
std::array<RegisterStruct, 19> BSC;
std::array<RegisterStruct, 17> DMAC;
std::array<RegisterStruct, 5> CPG;
std::array<RegisterStruct, 16> RTC;
std::array<RegisterStruct, 5> INTC;
std::array<RegisterStruct, 12> TMU;
std::array<RegisterStruct, 8> SCI;
std::array<RegisterStruct, 10> SCIF;
static u32 sh4io_read_noacc(u32 addr)
2013-12-19 17:10:14 +00:00
{
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "sh4io: Invalid read access @@ %08X", addr);
2013-12-19 17:10:14 +00:00
return 0;
}
2020-01-25 10:00:34 +00:00
static void sh4io_write_noacc(u32 addr, u32 data)
2013-12-19 17:10:14 +00:00
{
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "sh4io: Invalid write access @@ %08X %08X", addr, data);
2013-12-19 17:10:14 +00:00
//verify(false);
}
2020-01-25 10:00:34 +00:00
static void sh4io_write_const(u32 addr, u32 data)
2013-12-19 17:10:14 +00:00
{
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "sh4io: Const write ignored @@ %08X <- %08X", addr, data);
2013-12-19 17:10:14 +00:00
}
2020-01-25 10:00:34 +00:00
template<class T>
void sh4_rio_reg(T& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf)
2013-12-19 17:10:14 +00:00
{
u32 idx=(addr&255)/4;
2020-01-25 10:00:34 +00:00
verify(idx < arr.size());
2013-12-19 17:10:14 +00:00
2020-01-25 10:00:34 +00:00
arr[idx].flags = flags;
2013-12-19 17:10:14 +00:00
if (flags == RIO_NO_ACCESS)
{
arr[idx].readFunctionAddr=&sh4io_read_noacc;
arr[idx].writeFunctionAddr=&sh4io_write_noacc;
}
else if (flags == RIO_CONST)
{
arr[idx].writeFunctionAddr=&sh4io_write_const;
}
else
{
arr[idx].data32=0;
if (flags & REG_RF)
arr[idx].readFunctionAddr=rf;
if (flags & REG_WF)
arr[idx].writeFunctionAddr=wf==0?&sh4io_write_noacc:wf;
}
}
2020-01-25 10:00:34 +00:00
template void sh4_rio_reg(std::array<RegisterStruct, 5>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template void sh4_rio_reg(std::array<RegisterStruct, 8>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template void sh4_rio_reg(std::array<RegisterStruct, 9>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template void sh4_rio_reg(std::array<RegisterStruct, 10>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template void sh4_rio_reg(std::array<RegisterStruct, 12>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template void sh4_rio_reg(std::array<RegisterStruct, 16>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template void sh4_rio_reg(std::array<RegisterStruct, 17>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template void sh4_rio_reg(std::array<RegisterStruct, 18>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template void sh4_rio_reg(std::array<RegisterStruct, 19>& arr, u32 addr, RegIO flags, u32 sz, RegReadAddrFP* rf, RegWriteAddrFP* wf);
template<u32 sz, class T>
u32 sh4_rio_read(T& regs, u32 addr)
2013-12-19 17:10:14 +00:00
{
u32 offset = addr&255;
#ifdef TRACE
if (offset & 3/*(size-1)*/) //4 is min align size
2013-12-19 17:10:14 +00:00
{
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unaligned System Bus register read");
2013-12-19 17:10:14 +00:00
}
#endif
offset>>=2;
#ifdef TRACE
2020-01-25 10:00:34 +00:00
if (regs[offset].flags & sz)
2013-12-19 17:10:14 +00:00
{
#endif
2020-01-25 10:00:34 +00:00
if (!(regs[offset].flags & REG_RF) )
2013-12-19 17:10:14 +00:00
{
if (sz==4)
2020-01-25 10:00:34 +00:00
return regs[offset].data32;
2013-12-19 17:10:14 +00:00
else if (sz==2)
2020-01-25 10:00:34 +00:00
return regs[offset].data16;
2013-12-19 17:10:14 +00:00
else
2020-01-25 10:00:34 +00:00
return regs[offset].data8;
2013-12-19 17:10:14 +00:00
}
else
{
2020-01-25 10:00:34 +00:00
return regs[offset].readFunctionAddr(addr);
2013-12-19 17:10:14 +00:00
}
#ifdef TRACE
}
else
{
2019-08-08 06:20:15 +00:00
INFO_LOG(SH4, "ERROR [wrong size read on register]");
2013-12-19 17:10:14 +00:00
}
#endif
return 0;
}
2020-01-25 10:00:34 +00:00
template<u32 sz, class T>
void sh4_rio_write(T& regs, u32 addr, u32 data)
2013-12-19 17:10:14 +00:00
{
u32 offset = addr&255;
#ifdef TRACE
if (offset & 3/*(size-1)*/) //4 is min align size
2013-12-19 17:10:14 +00:00
{
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unaligned System bus register write");
2013-12-19 17:10:14 +00:00
}
#endif
offset>>=2;
#ifdef TRACE
2020-01-25 10:00:34 +00:00
if (regs[offset].flags & sz)
2013-12-19 17:10:14 +00:00
{
#endif
2020-01-25 10:00:34 +00:00
if (!(regs[offset].flags & REG_WF) )
2013-12-19 17:10:14 +00:00
{
if (sz==4)
2020-01-25 10:00:34 +00:00
regs[offset].data32=data;
2013-12-19 17:10:14 +00:00
else if (sz==2)
2020-01-25 10:00:34 +00:00
regs[offset].data16=(u16)data;
2013-12-19 17:10:14 +00:00
else
2020-01-25 10:00:34 +00:00
regs[offset].data8=(u8)data;
2013-12-19 17:10:14 +00:00
return;
}
else
{
//printf("RSW: %08X\n",addr);
2020-01-25 10:00:34 +00:00
regs[offset].writeFunctionAddr(addr,data);
2013-12-19 17:10:14 +00:00
return;
}
#ifdef TRACE
}
else
{
2019-08-08 06:20:15 +00:00
INFO_LOG(SH4, "ERROR: Wrong size write on register - offset=%x, data=%x, size=%d",offset,data,sz);
2013-12-19 17:10:14 +00:00
}
#endif
}
//Region P4
//Read P4
template <class T>
2013-12-19 17:10:14 +00:00
T DYNACALL ReadMem_P4(u32 addr)
{
constexpr size_t sz = sizeof(T);
2013-12-19 17:10:14 +00:00
switch((addr>>24)&0xFF)
{
case 0xE0:
case 0xE1:
case 0xE2:
case 0xE3:
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unhandled p4 read [Store queue] 0x%x", addr);
2013-12-19 17:10:14 +00:00
return 0;
case 0xF0:
DEBUG_LOG(SH4, "IC Address read %08x", addr);
if (sz == 4)
return icache.ReadAddressArray(addr);
else
return 0;
2013-12-19 17:10:14 +00:00
case 0xF1:
DEBUG_LOG(SH4, "IC Data read %08x", addr);
if (sz == 4)
return icache.ReadDataArray(addr);
else
return 0;
2013-12-19 17:10:14 +00:00
case 0xF2:
{
u32 entry=(addr>>8)&3;
return ITLB[entry].Address.reg_data | (ITLB[entry].Data.V<<8);
}
case 0xF3:
{
u32 entry=(addr>>8)&3;
return ITLB[entry].Data.reg_data;
}
case 0xF4:
DEBUG_LOG(SH4, "OC Address read %08x", addr);
if (sz == 4)
return ocache.ReadAddressArray(addr);
else
2013-12-19 17:10:14 +00:00
return 0;
case 0xF5:
DEBUG_LOG(SH4, "OC Data read %08x", addr);
if (sz == 4)
return ocache.ReadDataArray(addr);
else
return 0;
2013-12-19 17:10:14 +00:00
case 0xF6:
{
u32 entry=(addr>>8)&63;
u32 rv=UTLB[entry].Address.reg_data;
rv|=UTLB[entry].Data.D<<9;
rv|=UTLB[entry].Data.V<<8;
return rv;
}
case 0xF7:
{
u32 entry=(addr>>8)&63;
return UTLB[entry].Data.reg_data;
}
case 0xFF:
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unhandled p4 read [area7] 0x%x", addr);
2013-12-19 17:10:14 +00:00
break;
default:
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unhandled p4 read [Reserved] 0x%x", addr);
2013-12-19 17:10:14 +00:00
break;
}
return 0;
}
//Write P4
template <class T>
2013-12-19 17:10:14 +00:00
void DYNACALL WriteMem_P4(u32 addr,T data)
{
constexpr size_t sz = sizeof(T);
2013-12-19 17:10:14 +00:00
switch((addr>>24)&0xFF)
{
case 0xE0:
case 0xE1:
case 0xE2:
case 0xE3:
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unhandled p4 Write [Store queue] 0x%x", addr);
2013-12-19 17:10:14 +00:00
break;
case 0xF0:
DEBUG_LOG(SH4, "IC Address write %08x = %x", addr, data);
if (sz == 4)
icache.WriteAddressArray(addr, data);
2013-12-19 17:10:14 +00:00
return;
case 0xF1:
DEBUG_LOG(SH4, "IC Data write %08x = %x", addr, data);
if (sz == 4)
icache.WriteDataArray(addr, data);
2013-12-19 17:10:14 +00:00
return;
case 0xF2:
{
u32 entry=(addr>>8)&3;
ITLB[entry].Address.reg_data=data & 0xFFFFFCFF;
ITLB[entry].Data.V=(data>>8) & 1;
ITLB_Sync(entry);
return;
}
case 0xF3:
{
u32 entry=(addr>>8)&3;
if (addr&0x800000)
{
ITLB[entry].Assistance.reg_data = data & 0xf;
}
else
{
ITLB[entry].Data.reg_data=data;
}
2013-12-19 17:10:14 +00:00
ITLB_Sync(entry);
2013-12-19 17:10:14 +00:00
return;
}
case 0xF4:
DEBUG_LOG(SH4, "OC Address write %08x = %x", addr, data);
if (sz == 4)
ocache.WriteAddressArray(addr, data);
return;
2013-12-19 17:10:14 +00:00
case 0xF5:
DEBUG_LOG(SH4, "OC Data write %08x = %x", addr, data);
if (sz == 4)
ocache.WriteDataArray(addr, data);
2013-12-19 17:10:14 +00:00
return;
case 0xF6:
{
if (addr&0x80)
{
2019-08-30 21:35:10 +00:00
#ifdef NO_MMU
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unhandled p4 Write [Unified TLB address array, Associative Write] 0x%x = %x", addr, data);
2019-08-30 21:35:10 +00:00
#endif
2015-09-17 19:31:25 +00:00
2013-12-19 17:10:14 +00:00
CCN_PTEH_type t;
t.reg_data=data;
u32 va=t.VPN<<10;
2019-08-30 21:35:10 +00:00
#ifndef NO_MMU
2013-12-19 17:10:14 +00:00
for (int i=0;i<64;i++)
{
if (mmu_match(va,UTLB[i].Address,UTLB[i].Data))
2013-12-19 17:10:14 +00:00
{
UTLB[i].Data.V=((u32)data>>8)&1;
UTLB[i].Data.D=((u32)data>>9)&1;
UTLB_Sync(i);
}
}
for (int i=0;i<4;i++)
{
if (mmu_match(va,ITLB[i].Address,ITLB[i].Data))
{
ITLB[i].Data.V=((u32)data>>8)&1;
ITLB[i].Data.D=((u32)data>>9)&1;
ITLB_Sync(i);
}
}
2019-08-30 21:35:10 +00:00
#endif
2013-12-19 17:10:14 +00:00
}
else
{
u32 entry=(addr>>8)&63;
UTLB[entry].Address.reg_data=data & 0xFFFFFCFF;
UTLB[entry].Data.D=(data>>9)&1;
UTLB[entry].Data.V=(data>>8)&1;
UTLB_Sync(entry);
}
return;
}
break;
case 0xF7:
{
u32 entry=(addr>>8)&63;
if (addr&0x800000)
{
UTLB[entry].Assistance.reg_data = data & 0xf;
}
else
{
UTLB[entry].Data.reg_data=data;
}
2013-12-19 17:10:14 +00:00
UTLB_Sync(entry);
2013-12-19 17:10:14 +00:00
return;
}
case 0xFF:
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unhandled p4 Write [area7] 0x%x = %x", addr, data);
2013-12-19 17:10:14 +00:00
break;
default:
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Unhandled p4 Write [Reserved] 0x%x", addr);
2013-12-19 17:10:14 +00:00
break;
}
}
//***********
//Store Queue
//***********
//TODO : replace w/ mem mapped array
//Read SQ
template <class T>
2013-12-19 17:10:14 +00:00
T DYNACALL ReadMem_sq(u32 addr)
{
if (sizeof(T) != 4)
2013-12-19 17:10:14 +00:00
{
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Store Queue Error - only 4 byte read are possible[x%X]", addr);
2013-12-19 17:10:14 +00:00
return 0xDE;
}
u32 united_offset=addr & 0x3C;
return (T)*(u32*)&sq_both[united_offset];
}
//Write SQ
template <class T>
2013-12-19 17:10:14 +00:00
void DYNACALL WriteMem_sq(u32 addr,T data)
{
if (sizeof(T) != 4)
2019-07-01 13:22:04 +00:00
INFO_LOG(SH4, "Store Queue Error - only 4 byte writes are possible[x%X=0x%X]", addr, data);
2013-12-19 17:10:14 +00:00
u32 united_offset=addr & 0x3C;
*(u32*)&sq_both[united_offset]=data;
}
//***********
//**Area 7**
//***********
2019-07-07 22:03:44 +00:00
#define OUT_OF_RANGE(reg) INFO_LOG(SH4, "Out of range on register %s index %x", reg, addr)
2013-12-19 17:10:14 +00:00
//Read Area7
template <class T>
2013-12-19 17:10:14 +00:00
T DYNACALL ReadMem_area7(u32 addr)
{
constexpr size_t sz = sizeof(T);
2013-12-19 17:10:14 +00:00
/*
if (likely(addr==0xffd80024))
{
return TMU_TCNT(2);
}
else if (likely(addr==0xFFD8000C))
{
return TMU_TCNT(0);
}
else */if (likely(addr==0xFF000028))
{
return CCN_INTEVT;
}
else if (likely(addr==0xFFA0002C))
{
return DMAC_CHCR(2).full;
}
addr&=0x1FFFFFFF;
u32 map_base=addr>>16;
switch (map_base & 0x1FFF)
{
case A7_REG_HASH(CCN_BASE_addr):
if (addr<=0x1F000044)
2013-12-19 17:10:14 +00:00
{
return (T)sh4_rio_read<sz>(CCN,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("CCN");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
case A7_REG_HASH(UBC_BASE_addr):
if (addr<=0x1F200020)
{
return (T)sh4_rio_read<sz>(UBC,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("UBC");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
case A7_REG_HASH(BSC_BASE_addr):
if (addr<=0x1F800048)
{
return (T)sh4_rio_read<sz>(BSC,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("BSC");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
2019-07-07 22:03:44 +00:00
case A7_REG_HASH(BSC_SDMR2_addr):
//dram settings 2 / write only
INFO_LOG(SH4, "Read from write-only registers [dram settings 2]");
return 0;
case A7_REG_HASH(BSC_SDMR3_addr):
//dram settings 3 / write only
INFO_LOG(SH4, "Read from write-only registers [dram settings 3]");
return 0;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(DMAC_BASE_addr):
if (addr<=0x1FA00040)
{
return (T)sh4_rio_read<sz>(DMAC,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("DMAC");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
case A7_REG_HASH(CPG_BASE_addr):
if (addr<=0x1FC00010)
{
return (T)sh4_rio_read<sz>(CPG,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("CPG");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
case A7_REG_HASH(RTC_BASE_addr):
if (addr<=0x1FC8003C)
{
return (T)sh4_rio_read<sz>(RTC,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("RTC");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
case A7_REG_HASH(INTC_BASE_addr):
if (addr<=0x1FD00010)
2013-12-19 17:10:14 +00:00
{
return (T)sh4_rio_read<sz>(INTC,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("INTC");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
case A7_REG_HASH(TMU_BASE_addr):
if (addr<=0x1FD8002C)
{
return (T)sh4_rio_read<sz>(TMU,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("TMU");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
case A7_REG_HASH(SCI_BASE_addr):
if (addr<=0x1FE0001C)
{
return (T)sh4_rio_read<sz>(SCI,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("SCI");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
case A7_REG_HASH(SCIF_BASE_addr):
if (addr<=0x1FE80024)
{
return (T)sh4_rio_read<sz>(SCIF,addr & 0xFF);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("SCIF");
return 0;
2013-12-19 17:10:14 +00:00
}
break;
// Who really cares about ht-UDI? it's not existent on the Dreamcast IIRC
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(UDI_BASE_addr):
switch(addr)
{
//UDI SDIR 0x1FF00000 0x1FF00000 16 0xFFFF Held Held Held Pclk
case UDI_SDIR_addr :
break;
//UDI SDDR 0x1FF00008 0x1FF00008 32 Held Held Held Held Pclk
case UDI_SDDR_addr :
break;
}
break;
}
2019-07-07 22:03:44 +00:00
INFO_LOG(SH4, "Unknown Read from Area7 - addr=%x", addr);
2013-12-19 17:10:14 +00:00
return 0;
}
//Write Area7
template <class T>
2013-12-19 17:10:14 +00:00
void DYNACALL WriteMem_area7(u32 addr,T data)
{
constexpr size_t sz = sizeof(T);
2013-12-19 17:10:14 +00:00
if (likely(addr==0xFF000038))
{
CCN_QACR_write<0>(addr,data);
return;
}
else if (likely(addr==0xFF00003C))
{
CCN_QACR_write<1>(addr,data);
return;
}
addr&=0x1FFFFFFF;
u32 map_base=addr>>16;
switch (map_base & 0x1FFF)
{
case A7_REG_HASH(CCN_BASE_addr):
if (addr<=0x1F00003C)
{
sh4_rio_write<sz>(CCN,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("CCN");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(UBC_BASE_addr):
if (addr<=0x1F200020)
{
sh4_rio_write<sz>(UBC,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("UBC");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(BSC_BASE_addr):
if (addr<=0x1F800048)
{
sh4_rio_write<sz>(BSC,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("BSC");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
case A7_REG_HASH(BSC_SDMR2_addr):
//dram settings 2 / write only
return;
2013-12-19 17:10:14 +00:00
2019-07-07 22:03:44 +00:00
case A7_REG_HASH(BSC_SDMR3_addr):
//dram settings 3 / write only
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(DMAC_BASE_addr):
if (addr<=0x1FA00040)
{
sh4_rio_write<sz>(DMAC,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("DMAC");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(CPG_BASE_addr):
if (addr<=0x1FC00010)
{
sh4_rio_write<sz>(CPG,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("CPG");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(RTC_BASE_addr):
if (addr<=0x1FC8003C)
{
sh4_rio_write<sz>(RTC,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("RTC");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(INTC_BASE_addr):
if (addr<=0x1FD0000C)
{
sh4_rio_write<sz>(INTC,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("INTC");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(TMU_BASE_addr):
if (addr<=0x1FD8002C)
{
sh4_rio_write<sz>(TMU,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("TMU");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(SCI_BASE_addr):
if (addr<=0x1FE0001C)
{
sh4_rio_write<sz>(SCI,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("SCI");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(SCIF_BASE_addr):
if (addr<=0x1FE80024)
{
sh4_rio_write<sz>(SCIF,addr & 0xFF,data);
}
else
{
2019-07-07 22:03:44 +00:00
OUT_OF_RANGE("SCIF");
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
return;
2013-12-19 17:10:14 +00:00
//who really cares about ht-udi ? it's not existent on dc iirc ..
2013-12-19 17:10:14 +00:00
case A7_REG_HASH(UDI_BASE_addr):
switch(addr)
{
//UDI SDIR 0xFFF00000 0x1FF00000 16 0xFFFF Held Held Held Pclk
case UDI_SDIR_addr :
break;
//UDI SDDR 0xFFF00008 0x1FF00008 32 Held Held Held Held Pclk
case UDI_SDDR_addr :
break;
}
break;
}
2019-07-07 22:03:44 +00:00
INFO_LOG(SH4, "Write to Area7 not implemented, addr=%x, data=%x", addr, data);
2013-12-19 17:10:14 +00:00
}
//***********
//On Chip Ram
//***********
//Read OCR
template <class T>
2013-12-19 17:10:14 +00:00
T DYNACALL ReadMem_area7_OCR_T(u32 addr)
{
if (CCN_CCR.ORA)
{
if (sizeof(T) == 1)
2013-12-19 17:10:14 +00:00
return (T)OnChipRAM[addr&OnChipRAM_MASK];
else if (sizeof(T) == 2)
2013-12-19 17:10:14 +00:00
return (T)*(u16*)&OnChipRAM[addr&OnChipRAM_MASK];
else if (sizeof(T) == 4)
2013-12-19 17:10:14 +00:00
return (T)*(u32*)&OnChipRAM[addr&OnChipRAM_MASK];
else
{
ERROR_LOG(SH4, "ReadMem_area7_OCR_T: template SZ is wrong = %zd", sizeof(T));
2013-12-19 17:10:14 +00:00
return 0xDE;
}
}
else
{
INFO_LOG(SH4, "On Chip Ram Read, but OCR is disabled. addr %x", addr);
2013-12-19 17:10:14 +00:00
return 0xDE;
}
}
//Write OCR
template <class T>
2013-12-19 17:10:14 +00:00
void DYNACALL WriteMem_area7_OCR_T(u32 addr,T data)
{
if (CCN_CCR.ORA)
{
if (sizeof(T) == 1)
2013-12-19 17:10:14 +00:00
OnChipRAM[addr&OnChipRAM_MASK]=(u8)data;
else if (sizeof(T) == 2)
2013-12-19 17:10:14 +00:00
*(u16*)&OnChipRAM[addr&OnChipRAM_MASK]=(u16)data;
else if (sizeof(T) == 4)
2013-12-19 17:10:14 +00:00
*(u32*)&OnChipRAM[addr&OnChipRAM_MASK]=data;
else
{
ERROR_LOG(SH4, "WriteMem_area7_OCR_T: template SZ is wrong = %zd", sizeof(T));
2013-12-19 17:10:14 +00:00
}
}
else
{
INFO_LOG(SH4, "On Chip Ram Write, but OCR is disabled. addr %x", addr);
2013-12-19 17:10:14 +00:00
}
}
2020-01-25 10:00:34 +00:00
template <class T>
static void init_regs(T& regs)
{
for (auto& reg : regs)
{
reg.flags = RIO_NO_ACCESS;
reg.readFunctionAddr = &sh4io_read_noacc;
reg.writeFunctionAddr = &sh4io_write_noacc;
}
}
2013-12-19 17:10:14 +00:00
//Init/Res/Term
void sh4_mmr_init()
{
2020-01-25 10:00:34 +00:00
init_regs(CCN);
init_regs(UBC);
init_regs(BSC);
init_regs(DMAC);
init_regs(CPG);
init_regs(RTC);
init_regs(INTC);
init_regs(TMU);
init_regs(SCI);
init_regs(SCIF);
2013-12-19 17:10:14 +00:00
//initialise Register structs
bsc_init();
ccn_init();
cpg_init();
dmac_init();
intc_init();
rtc_init();
serial_init();
tmu_init();
ubc_init();
}
void sh4_mmr_reset(bool hard)
2013-12-19 17:10:14 +00:00
{
if (hard)
{
2020-01-25 10:00:34 +00:00
for (auto& reg : CCN)
reg.reset();
for (auto& reg : UBC)
reg.reset();
for (auto& reg : BSC)
reg.reset();
for (auto& reg : DMAC)
reg.reset();
for (auto& reg : CPG)
reg.reset();
for (auto& reg : RTC)
reg.reset();
for (auto& reg : INTC)
reg.reset();
for (auto& reg : TMU)
reg.reset();
for (auto& reg : SCI)
reg.reset();
for (auto& reg : SCIF)
reg.reset();
}
2020-01-25 10:00:34 +00:00
OnChipRAM = {};
2013-12-19 17:10:14 +00:00
//Reset register values
2019-09-11 13:00:08 +00:00
bsc_reset(hard);
ccn_reset(hard);
2013-12-19 17:10:14 +00:00
cpg_reset();
dmac_reset();
intc_reset();
rtc_reset();
serial_reset();
2019-09-11 13:00:08 +00:00
tmu_reset(hard);
2013-12-19 17:10:14 +00:00
ubc_reset();
}
void sh4_mmr_term()
{
//free any alloc'd resources [if any]
ubc_term();
tmu_term();
serial_term();
rtc_term();
intc_term();
dmac_term();
cpg_term();
ccn_term();
bsc_term();
}
//Mem map :)
//AREA 7--Sh4 Regs
2013-12-19 17:10:14 +00:00
_vmem_handler area7_handler;
_vmem_handler area7_orc_handler;
void map_area7_init()
{
//=_vmem_register_handler(ReadMem8_area7,ReadMem16_area7,ReadMem32_area7,
// WriteMem8_area7,WriteMem16_area7,WriteMem32_area7);
//default area7 handler
area7_handler= _vmem_register_handler_Template(ReadMem_area7,WriteMem_area7);
area7_orc_handler= _vmem_register_handler_Template(ReadMem_area7_OCR_T,WriteMem_area7_OCR_T);
}
void map_area7(u32 base)
{
//OCR @
//((addr>=0x7C000000) && (addr<=0x7FFFFFFF))
if (base==0x60)
_vmem_map_handler(area7_orc_handler,0x1C | base , 0x1F| base);
else
{
_vmem_map_handler(area7_handler,0x1C | base , 0x1F| base);
}
}
//P4
void map_p4()
{
//P4 Region :
_vmem_handler p4_handler = _vmem_register_handler_Template(ReadMem_P4,WriteMem_P4);
2013-12-19 17:10:14 +00:00
//register this before area7 and SQ , so they overwrite it and handle em :)
//default P4 handler
//0xE0000000-0xFFFFFFFF
_vmem_map_handler(p4_handler,0xE0,0xFF);
//Store Queues -- Write only 32bit
2013-12-19 17:10:14 +00:00
_vmem_map_block(sq_both,0xE0,0xE0,63);
_vmem_map_block(sq_both,0xE1,0xE1,63);
_vmem_map_block(sq_both,0xE2,0xE2,63);
_vmem_map_block(sq_both,0xE3,0xE3,63);
map_area7(0xE0);
2018-10-20 17:38:21 +00:00
}