begin SH4 MMU improvements (with a view to seeing what mk6 needs)

This commit is contained in:
David Haywood 2016-11-23 03:02:59 +00:00
parent 9b2e44723c
commit 5a942ef207
3 changed files with 227 additions and 40 deletions

View File

@ -75,7 +75,11 @@ static ADDRESS_MAP_START( sh4_internal_map, AS_PROGRAM, 64, sh4_base_device )
AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x01FFF000)
AM_RANGE(0x1E000000, 0x1E000FFF) AM_RAM AM_MIRROR(0x01FFF000)
AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0) // todo: store queues should be write only on DC's SH4, executing PREFM shouldn't cause an actual memory read access!
AM_RANGE(0xF6000000, 0xF7FFFFFF) AM_READWRITE(sh4_tlb_r,sh4_tlb_w)
AM_RANGE(0xF6000000, 0xF6FFFFFF) AM_READWRITE(sh4_utlb_address_array_r,sh4_utlb_address_array_w)
AM_RANGE(0xF7000000, 0xF77FFFFF) AM_READWRITE(sh4_utlb_data_array1_r,sh4_utlb_data_array1_w)
AM_RANGE(0xF7800000, 0xF7FFFFFF) AM_READWRITE(sh4_utlb_data_array2_r,sh4_utlb_data_array2_w)
AM_RANGE(0xFE000000, 0xFFFFFFFF) AM_READWRITE32(sh4_internal_r, sh4_internal_w, 0xffffffffffffffffU)
ADDRESS_MAP_END
@ -180,6 +184,12 @@ void sh34_base_device::TODO(const uint16_t opcode)
{
}
void sh34_base_device::LDTLB(const uint16_t opcode)
{
logerror("unhandled LDTLB\n");
}
#if 0
int sign_of(int n)
{
@ -3331,7 +3341,7 @@ inline void sh34_base_device::execute_one_0000(const uint16_t opcode)
case 0x08: CLRT(opcode); break;
case 0x18: SETT(opcode); break;
case 0x28: CLRMAC(opcode); break;
case 0x38: TODO(opcode); break;
case 0x38: LDTLB(opcode); break;
case 0x48: CLRS(opcode); break;
case 0x58: SETS(opcode); break;
case 0x68: NOP(opcode); break;
@ -3339,7 +3349,7 @@ inline void sh34_base_device::execute_one_0000(const uint16_t opcode)
case 0x88: CLRT(opcode); break;
case 0x98: SETT(opcode); break;
case 0xa8: CLRMAC(opcode); break;
case 0xb8: TODO(opcode); break;
case 0xb8: LDTLB(opcode); break;
case 0xc8: CLRS(opcode); break;
case 0xd8: SETS(opcode); break;
case 0xe8: NOP(opcode); break;
@ -4028,6 +4038,47 @@ void sh4be_device::execute_run()
} while( m_sh4_icount > 0 );
}
void sh4_base_device::device_start()
{
sh34_base_device::device_start();
int i;
for (i=0;i<64;i++)
{
m_utlb[i].ASID = 0;
m_utlb[i].VPN = 0;
m_utlb[i].V = 0;
m_utlb[i].PPN = 0;
m_utlb[i].PSZ = 0;
m_utlb[i].SH = 0;
m_utlb[i].C = 0;
m_utlb[i].PPR = 0;
m_utlb[i].D = 0;
m_utlb[i].WT = 0;
m_utlb[i].SA = 0;
m_utlb[i].TC = 0;
}
for (i=0;i<64;i++)
{
save_item(NAME(m_utlb[i].ASID), i);
save_item(NAME(m_utlb[i].VPN), i);
save_item(NAME(m_utlb[i].V), i);
save_item(NAME(m_utlb[i].PPN), i);
save_item(NAME(m_utlb[i].PSZ), i);
save_item(NAME(m_utlb[i].SH), i);
save_item(NAME(m_utlb[i].C), i);
save_item(NAME(m_utlb[i].PPR), i);
save_item(NAME(m_utlb[i].D), i);
save_item(NAME(m_utlb[i].WT), i);
save_item(NAME(m_utlb[i].SA), i);
save_item(NAME(m_utlb[i].TC), i);
}
}
void sh34_base_device::device_start()
{
for (int i=0; i<3; i++)
@ -4134,8 +4185,6 @@ void sh34_base_device::device_start()
save_item(NAME( m_ioport16_direction));
save_item(NAME(m_ioport4_pullup));
save_item(NAME(m_ioport4_direction));
save_item(NAME(m_sh4_tlb_address));
save_item(NAME(m_sh4_tlb_data));
save_item(NAME(m_sh4_mmu_enabled));
save_item(NAME(m_sh3internal_upper));
save_item(NAME(m_sh3internal_lower));

View File

@ -136,6 +136,26 @@ struct sh4_ddt_dma
int mode;
};
// ASID [7:0] | VPN [31:10] | V | | PPN [28:10] | SZ[1:0] | SH | C | PR[1:0] | D | WT | SA[2:0] | TC
struct sh4_utlb
{
uint8_t ASID;
uint32_t VPN;
uint8_t V;
uint32_t PPN;
uint8_t PSZ;
uint8_t SH;
uint8_t C;
uint8_t PPR;
uint8_t D;
uint8_t WT;
uint8_t SA;
uint8_t TC;
};
typedef void (*sh4_ftcsr_callback)(uint32_t);
@ -358,8 +378,6 @@ protected:
void (*m_ftcsr_read_callback)(uint32_t data);
/* This MMU simulation is good for the simple remap used on Naomi GD-ROM SQ access *ONLY* */
uint32_t m_sh4_tlb_address[64];
uint32_t m_sh4_tlb_data[64];
uint8_t m_sh4_mmu_enabled;
int m_cpu_type;
@ -451,6 +469,7 @@ protected:
void LDSMMACH(const uint16_t opcode);
void LDSMMACL(const uint16_t opcode);
void LDSMPR(const uint16_t opcode);
void LDTLB(const uint16_t opcode);
void MAC_L(const uint16_t opcode);
void MAC_W(const uint16_t opcode);
void MOV(const uint16_t opcode);
@ -627,7 +646,7 @@ protected:
void increment_rtc_time(int mode);
void sh4_dmac_nmi();
void sh4_handler_ipra_w(uint32_t data, uint32_t mem_mask);
uint32_t sh4_getsqremap(uint32_t address);
virtual uint32_t sh4_getsqremap(uint32_t address);
void sh4_parse_configuration();
void sh4_timer_recompute(int which);
uint32_t sh4_handle_tcnt0_addr_r(uint32_t mem_mask);
@ -736,10 +755,18 @@ public:
DECLARE_WRITE32_MEMBER( sh4_internal_w );
DECLARE_READ32_MEMBER( sh4_internal_r );
DECLARE_READ64_MEMBER( sh4_tlb_r );
DECLARE_WRITE64_MEMBER( sh4_tlb_w );
DECLARE_READ64_MEMBER( sh4_utlb_address_array_r );
DECLARE_WRITE64_MEMBER( sh4_utlb_address_array_w );
DECLARE_READ64_MEMBER( sh4_utlb_data_array1_r );
DECLARE_WRITE64_MEMBER( sh4_utlb_data_array1_w );
DECLARE_READ64_MEMBER( sh4_utlb_data_array2_r );
DECLARE_WRITE64_MEMBER( sh4_utlb_data_array2_w );
virtual uint32_t sh4_getsqremap(uint32_t address) override;
sh4_utlb m_utlb[64];
protected:
virtual void device_start() override;
virtual void device_reset() override;
};

View File

@ -679,6 +679,8 @@ WRITE32_MEMBER( sh4_base_device::sh4_internal_w )
switch( offset )
{
case MMUCR: // MMU Control
logerror("MMUCR %08x\n", data);
if (data & MMUCR_AT)
{
printf("SH4 MMU Enabled\n");
@ -686,16 +688,7 @@ WRITE32_MEMBER( sh4_base_device::sh4_internal_w )
printf("The MMU emulation is a hack specific to that system\n");
m_sh4_mmu_enabled = 1;
// should be a different bit!
{
int i;
for (i=0;i<64;i++)
{
m_sh4_tlb_address[i] = 0;
m_sh4_tlb_data[i] = 0;
}
}
}
else
{
@ -1185,6 +1178,11 @@ void sh34_base_device::sh4_parse_configuration()
}
uint32_t sh34_base_device::sh4_getsqremap(uint32_t address)
{
return address;
}
uint32_t sh4_base_device::sh4_getsqremap(uint32_t address)
{
if (!m_sh4_mmu_enabled)
return address;
@ -1195,9 +1193,9 @@ uint32_t sh34_base_device::sh4_getsqremap(uint32_t address)
for (i=0;i<64;i++)
{
uint32_t topcmp = m_sh4_tlb_address[i]&0xfff00000;
uint32_t topcmp = (m_utlb[i].VPN<<10)&0xfff00000;
if (topcmp==topaddr)
return (address&0x000fffff) | ((m_sh4_tlb_data[i])&0xfff00000);
return (address&0x000fffff) | ((m_utlb[i].PPN<<10)&0xfff00000);
}
}
@ -1205,34 +1203,147 @@ uint32_t sh34_base_device::sh4_getsqremap(uint32_t address)
return address;
}
READ64_MEMBER( sh4_base_device::sh4_tlb_r )
{
int offs = offset*8;
if (offs >= 0x01000000)
WRITE64_MEMBER( sh4_base_device::sh4_utlb_address_array_w )
{
/* uses bits 13:8 of address to select which UTLB entry we're addressing
bit 7 of the address enables 'associative' mode, causing a search
operation rather than a direct write.
NNNN NNNN NNNN NNNN NNNN NNDV AAAA AAAA
N = VPM = Virtual Page Number
D = Dirty Bit
V = Validity Bit
A = ASID = Address Space Identifier
*/
logerror("sh4_utlb_address_array_w %08x %08x\n", offset, data);
int offs = offset << 3;
uint8_t associative = (offs >> 7) & 1;
if (!associative)
{
uint8_t i = (offs>>8)&63;
return m_sh4_tlb_data[i];
// non-associative mode
uint8_t i = (offs >> 8) & 63;
m_utlb[i].VPN = (data & 0xfffffc00) >> 10;
m_utlb[i].D = (data & 0x00000200) >> 9;
m_utlb[i].V = (data & 0x00000100) >> 8;
m_utlb[i].ASID = (data & 0x000000ff) >> 0;
}
else
{
uint8_t i = (offs>>8)&63;
return m_sh4_tlb_address[i];
// associative mode
fatalerror("SH4MMU: associative mode writes unsupported\n");
}
}
WRITE64_MEMBER( sh4_base_device::sh4_tlb_w )
READ64_MEMBER( sh4_base_device::sh4_utlb_address_array_r )
{
// associative bit is ignored for reads
int offs = offset*8;
if (offs >= 0x01000000)
{
uint8_t i = (offs>>8)&63;
m_sh4_tlb_data[i] = data&0xffffffff;
}
else
{
uint8_t i = (offs>>8)&63;
m_sh4_tlb_address[i] = data&0xffffffff;
}
uint32_t ret = 0;
uint8_t i = (offs >> 8) & 63;
ret |= m_utlb[i].VPN << 10;
ret |= m_utlb[i].D << 9;
ret |= m_utlb[i].V << 8;
ret |= m_utlb[i].ASID << 0;
return ret;
}
WRITE64_MEMBER( sh4_base_device::sh4_utlb_data_array1_w )
{
/* uses bits 13:8 of address to select which UTLB entry we're addressing
---P PPPP PPPP PPPP PPPP PP-V zRRz CDHW
P = PPN = Physical page number
V = Validity bit
z = SZ = Page Size (2 bits, split)
D = Dirty Bit
R = PR = Protection Key Data
C = Cacheable bit
H = Share status
W = Write through
- = unused (should be 0)
*/
logerror("sh4_utlb_data_array1_w %08x %08x\n", offset, data);
int offs = offset*8;
uint8_t i = (offs>>8)&63;
m_utlb[i].PPN = (data & 0x1ffffc00) >> 10;
m_utlb[i].V = (data & 0x00000100) >> 8;
m_utlb[i].PSZ = (data & 0x00000080) >> 6;
m_utlb[i].PSZ |=(data & 0x00000010) >> 4;
m_utlb[i].PPR= (data & 0x00000060) >> 5;
m_utlb[i].C = (data & 0x00000008) >> 3;
m_utlb[i].D = (data & 0x00000004) >> 2;
m_utlb[i].SH = (data & 0x00000002) >> 1;
m_utlb[i].WT = (data & 0x00000001) >> 0;
}
READ64_MEMBER(sh4_base_device::sh4_utlb_data_array1_r)
{
uint32_t ret = 0;
int offs = offset*8;
uint8_t i = (offs>>8)&63;
ret |= m_utlb[i].PPN << 10;
ret |= m_utlb[i].V << 8;
ret |= (m_utlb[i].PSZ & 2) << 6;
ret |= (m_utlb[i].PSZ & 1) << 4;
ret |= m_utlb[i].PPR << 5;
ret |= m_utlb[i].C << 3;
ret |= m_utlb[i].D << 2;
ret |= m_utlb[i].SH << 1;
ret |= m_utlb[i].WT << 0;
return ret;
}
WRITE64_MEMBER( sh4_base_device::sh4_utlb_data_array2_w )
{
/* uses bits 13:8 of address to select which UTLB entry we're addressing
---- ---- ---- ---- ---- ---- ---- TSSS
T = TC = Timing Control
S = SA = Space attributes
- = unused (should be 0)
*/
logerror("sh4_utlb_data_array2_w %08x %08x\n", offset, data);
int offs = offset*8;
uint8_t i = (offs>>8)&63;
m_utlb[i].TC = (data & 0x00000008) >> 3;
m_utlb[i].SA = (data & 0x00000007) >> 0;
}
READ64_MEMBER(sh4_base_device::sh4_utlb_data_array2_r)
{
uint32_t ret = 0;
int offs = offset*8;
uint8_t i = (offs>>8)&63;
ret |= m_utlb[i].TC << 3;
ret |= m_utlb[i].SA << 0;
return ret;
}