From 5a942ef207c3888e99c44ba8f9282db2eddd531d Mon Sep 17 00:00:00 2001 From: David Haywood Date: Wed, 23 Nov 2016 03:02:59 +0000 Subject: [PATCH] begin SH4 MMU improvements (with a view to seeing what mk6 needs) --- src/devices/cpu/sh4/sh4.cpp | 59 ++++++++++- src/devices/cpu/sh4/sh4.h | 37 ++++++- src/devices/cpu/sh4/sh4comn.cpp | 171 ++++++++++++++++++++++++++------ 3 files changed, 227 insertions(+), 40 deletions(-) diff --git a/src/devices/cpu/sh4/sh4.cpp b/src/devices/cpu/sh4/sh4.cpp index 1d5c69ad483..ce1a3fedf91 100644 --- a/src/devices/cpu/sh4/sh4.cpp +++ b/src/devices/cpu/sh4/sh4.cpp @@ -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)); diff --git a/src/devices/cpu/sh4/sh4.h b/src/devices/cpu/sh4/sh4.h index 7531363c2da..0cb92ae6b5e 100644 --- a/src/devices/cpu/sh4/sh4.h +++ b/src/devices/cpu/sh4/sh4.h @@ -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; }; diff --git a/src/devices/cpu/sh4/sh4comn.cpp b/src/devices/cpu/sh4/sh4comn.cpp index 985413e4a73..069498cde74 100644 --- a/src/devices/cpu/sh4/sh4comn.cpp +++ b/src/devices/cpu/sh4/sh4comn.cpp @@ -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; +} \ No newline at end of file