sgi/mc: memory controller ram configuration improvements

This commit is contained in:
Patrick Mackinlay 2023-07-17 11:47:09 +07:00
parent b04c99188f
commit adc3349c1c
4 changed files with 176 additions and 65 deletions

View File

@ -90,7 +90,6 @@ public:
: indigo_state(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_mem_ctrl(*this, "memctrl")
, m_share1(*this, "share1")
{
}
@ -101,11 +100,8 @@ protected:
void mem_map(address_map &map);
void write_ram(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
required_device<r4000_device> m_maincpu;
required_device<sgi_mc_device> m_mem_ctrl;
required_shared_ptr<uint64_t> m_share1;
};
void indigo_state::machine_start()
@ -121,9 +117,6 @@ void indigo_state::machine_reset()
void indigo4k_state::machine_reset()
{
indigo_state::machine_reset();
// set up low RAM mirror
membank("bank1")->set_base(m_share1);
}
uint32_t indigo_state::int_r(offs_t offset, uint32_t mem_mask)
@ -164,32 +157,11 @@ void indigo3k_state::mem_map(address_map &map)
map(0x1fc00000, 0x1fc3ffff).rom().region("user1", 0);
}
void indigo4k_state::write_ram(offs_t offset, uint64_t data, uint64_t mem_mask)
{
// if banks 2 or 3 are enabled, do nothing, we don't support that much memory
if (m_mem_ctrl->get_mem_config(1) & 0x10001000)
{
// a random perturbation so the memory test fails
data ^= 0xffffffffffffffffULL;
}
// if banks 0 or 1 have 2 membanks, also kill it, we only want 128 MB
if (m_mem_ctrl->get_mem_config(0) & 0x40004000)
{
// a random perturbation so the memory test fails
data ^= 0xffffffffffffffffULL;
}
COMBINE_DATA(&m_share1[offset]);
}
void indigo4k_state::mem_map(address_map &map)
{
indigo_map(map);
map(0x00000000, 0x0007ffff).bankrw("bank1");
map(0x08000000, 0x17ffffff).ram().share("share1").w(FUNC(indigo4k_state::write_ram)); /* 256 MB of main RAM */
map(0x1fa00000, 0x1fa1ffff).rw(m_mem_ctrl, FUNC(sgi_mc_device::read), FUNC(sgi_mc_device::write));
map(0x1fc00000, 0x1fc7ffff).rom().region("user1", 0);
map(0x20000000, 0x2fffffff).ram().share("share1").w(FUNC(indigo4k_state::write_ram)); /* 256 MB of main RAM */
}
static INPUT_PORTS_START(indigo)
@ -213,6 +185,10 @@ void indigo3k_state::indigo3k(machine_config &config)
SGI_HPC1(config, m_hpc, m_maincpu, m_eeprom);
}
static DEVICE_INPUT_DEFAULTS_START(ip20_mc)
DEVICE_INPUT_DEFAULTS("VALID", 0x0f, 0x07)
DEVICE_INPUT_DEFAULTS_END
void indigo4k_state::indigo4k(machine_config &config)
{
indigo_base(config);
@ -224,6 +200,8 @@ void indigo4k_state::indigo4k(machine_config &config)
SGI_MC(config, m_mem_ctrl, m_maincpu, m_eeprom, 50000000);
m_mem_ctrl->eisa_present().set_constant(0);
m_mem_ctrl->set_input_default(DEVICE_INPUT_DEFAULTS_NAME(ip20_mc));
SGI_HPC1(config, m_hpc, m_maincpu, m_eeprom);
}

View File

@ -89,7 +89,6 @@ public:
ip24_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_mainram(*this, "mainram")
, m_mem_ctrl(*this, "memctrl")
, m_scsi_ctrl(*this, "scsibus:0:wd33c93")
, m_edlc(*this, "edlc")
@ -117,7 +116,6 @@ protected:
virtual void machine_start() override;
virtual void machine_reset() override;
void write_ram(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
template <uint32_t addr_base> uint64_t bus_error_r(offs_t offset, uint64_t mem_mask = ~0);
template <uint32_t addr_base> void bus_error_w(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
@ -138,7 +136,6 @@ protected:
static void scsi_devices(device_slot_interface &device);
required_device<mips3_device> m_maincpu;
required_shared_ptr<uint64_t> m_mainram;
required_device<sgi_mc_device> m_mem_ctrl;
required_device<wd33c93b_device> m_scsi_ctrl;
required_device<seeq80c03_device> m_edlc;
@ -203,25 +200,6 @@ uint32_t ip22_state::eisa_io_r()
return 0xffffffff;
}
// a bit hackish, but makes the memory detection work properly and allows a big cleanup of the mapping
void ip24_state::write_ram(offs_t offset, uint64_t data, uint64_t mem_mask)
{
// if banks 2 or 3 are enabled, do nothing, we don't support that much memory
if (m_mem_ctrl->get_mem_config(1) & 0x10001000)
{
// a random perturbation so the memory test fails
data ^= 0xffffffffffffffffULL;
}
// if banks 0 or 1 have 2 membanks, also kill it, we only want 128 MB
if (m_mem_ctrl->get_mem_config(0) & 0x40004000)
{
// a random perturbation so the memory test fails
data ^= 0xffffffffffffffffULL;
}
COMBINE_DATA(&m_mainram[offset]);
}
uint8_t ip24_state::volume_r(offs_t offset)
{
if (offset == 0)
@ -246,14 +224,11 @@ void ip24_state::volume_w(offs_t offset, uint8_t data)
void ip24_state::ip24_base_map(address_map &map)
{
map(0x00000000, 0x0007ffff).bankrw("bank1"); /* mirror of first 512k of main RAM */
map(0x08000000, 0x0fffffff).share("mainram").ram().w(FUNC(ip24_state::write_ram)); /* 128 MB of main RAM */
map(0x1f000000, 0x1f9fffff).rw(m_gio64, FUNC(gio64_device::read), FUNC(gio64_device::write));
map(0x1fa00000, 0x1fa1ffff).rw(m_mem_ctrl, FUNC(sgi_mc_device::read), FUNC(sgi_mc_device::write));
map(0x1fb00000, 0x1fb7ffff).rw(FUNC(ip24_state::bus_error_r<0x1fb00000>), FUNC(ip24_state::bus_error_w<0x1fb00000>));
map(0x1fb80000, 0x1fbfffff).m(m_hpc3, FUNC(hpc3_device::map));
map(0x1fc00000, 0x1fc7ffff).rom().region("user1", 0);
map(0x20000000, 0x27ffffff).share("mainram").ram().w(FUNC(ip24_state::write_ram));
}
void ip24_state::ip24_map(address_map &map)
@ -306,9 +281,6 @@ void ip24_state::machine_start()
void ip24_state::machine_reset()
{
// set up low RAM mirror
membank("bank1")->set_base(m_mainram);
//m_maincpu->mips3drc_set_options(MIPS3DRC_COMPATIBLE_OPTIONS | MIPS3DRC_CHECK_OVERFLOWS);
}
@ -329,6 +301,14 @@ void ip24_state::scsi_devices(device_slot_interface &device)
//device.set_option_machine_config("cdrom", cdrom_config);
}
static DEVICE_INPUT_DEFAULTS_START(ip22_mc)
DEVICE_INPUT_DEFAULTS("VALID", 0x0f, 0x07)
DEVICE_INPUT_DEFAULTS_END
static DEVICE_INPUT_DEFAULTS_START(ip24_mc)
DEVICE_INPUT_DEFAULTS("VALID", 0x0f, 0x03)
DEVICE_INPUT_DEFAULTS_END
void ip24_state::ip24_base(machine_config &config, uint32_t system_clock)
{
SGI_MC(config, m_mem_ctrl, m_maincpu, m_eeprom, system_clock);
@ -390,6 +370,7 @@ void ip24_state::ip24_base(machine_config &config, uint32_t system_clock)
void ip24_state::ip24(machine_config &config, uint32_t system_clock)
{
ip24_base(config, system_clock);
m_mem_ctrl->set_input_default(DEVICE_INPUT_DEFAULTS_NAME(ip24_mc));
m_hpc3->set_addrmap(hpc3_device::AS_PIO6, &ip24_state::pio6_map);
@ -456,6 +437,7 @@ void ip22_state::indigo2_4415(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &ip22_state::ip22_map);
ip24_base(config, system_clock);
m_mem_ctrl->set_input_default(DEVICE_INPUT_DEFAULTS_NAME(ip22_mc));
NSCSI_BUS(config, "scsibus2", 0);
NSCSI_CONNECTOR(config, "scsibus2:0").option_set("wd33c93", WD33C93B)

View File

@ -31,6 +31,7 @@ sgi_mc_device::sgi_mc_device(const machine_config &mconfig, const char *tag, dev
: device_t(mconfig, SGI_MC, tag, owner, clock)
, m_maincpu(*this, finder_base::DUMMY_TAG)
, m_eeprom(*this, finder_base::DUMMY_TAG)
, m_simms(*this, "SIMMS")
, m_int_dma_done_cb(*this)
, m_eisa_present(*this, true)
, m_dma_timer(nullptr)
@ -43,6 +44,7 @@ sgi_mc_device::sgi_mc_device(const machine_config &mconfig, const char *tag, dev
, m_gio64_arb_param(0)
, m_arb_cpu_time(0)
, m_arb_burst_time(0)
, m_memcfg{}
, m_cpu_mem_access_config(0)
, m_gio_mem_access_config(0)
, m_cpu_error_addr(0)
@ -90,7 +92,7 @@ void sgi_mc_device::device_start()
save_item(NAME(m_gio64_arb_param));
save_item(NAME(m_arb_cpu_time));
save_item(NAME(m_arb_burst_time));
save_item(NAME(m_mem_config));
save_item(NAME(m_memcfg));
save_item(NAME(m_cpu_mem_access_config));
save_item(NAME(m_gio_mem_access_config));
save_item(NAME(m_cpu_error_addr));
@ -129,8 +131,6 @@ void sgi_mc_device::device_reset()
m_gio64_arb_param = 0;
m_arb_cpu_time = 0;
m_arb_burst_time = 0;
m_mem_config[0] = 0;
m_mem_config[1] = 0;
m_cpu_mem_access_config = 0;
m_gio_mem_access_config = 0;
m_cpu_error_addr = 0;
@ -161,6 +161,31 @@ void sgi_mc_device::device_reset()
memset(m_semaphore, 0, sizeof(uint32_t) * 16);
m_space = &m_maincpu->space(AS_PROGRAM);
u16 const simms = m_simms->read();
// allocate installed memory
for (unsigned bank = 0; bank < 4; bank++)
{
u32 const size = BIT(simms, bank * 4, 3);
switch (size)
{
case 0:
LOG("ram bank %c empty\n", bank + 'A');
m_ram[bank].reset();
break;
default:
LOG("ram bank %c size %dM (%s rank)\n",
bank + 'A', 1U << (size + 1), BIT(simms, bank * 4 + 3) ? "dual" : "single");
m_ram[bank] = std::make_unique<u8[]>(1U << (size + 21));
break;
}
}
// assume memory configuration is invalidated by reset
memcfg_w(0, 0);
memcfg_w(1, 0);
}
void sgi_mc_device::set_cpu_buserr(uint32_t address, uint64_t mem_mask)
@ -351,8 +376,8 @@ uint32_t sgi_mc_device::read(offs_t offset, uint32_t mem_mask)
case 0x00c8/4:
{
const uint32_t index = (offset >> 1) & 1;
LOGMASKED(LOG_MEMCFG, "%s: Memory Configuration Register %d Read: %08x & %08x\n", machine().describe_context(), index, m_mem_config[index], mem_mask);
return m_mem_config[index];
LOGMASKED(LOG_MEMCFG, "%s: Memory Configuration Register %d Read: %08x & %08x\n", machine().describe_context(), index, m_memcfg[index], mem_mask);
return m_memcfg[index];
}
case 0x00d0/4:
LOGMASKED(LOG_READS, "%s: CPU Memory Access Config Params Read: %08x & %08x\n", machine().describe_context(), m_cpu_mem_access_config, mem_mask);
@ -545,7 +570,7 @@ void sgi_mc_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
LOGMASKED(LOG_MEMCFG_EXT, "%s: Bank %d, SIMM Size: %02x (%s)\n", machine().describe_context(), index+1, (data >> 8) & 0x1f, s_mem_size[(data >> 8) & 0x1f]);
LOGMASKED(LOG_MEMCFG_EXT, "%s: Bank %d, Valid: %d\n", machine().describe_context(), index+1, BIT(data, 13));
LOGMASKED(LOG_MEMCFG_EXT, "%s: Bank %d, # Subbanks: %d\n", machine().describe_context(), index+1, BIT(data, 14) + 1);
m_mem_config[index] = data;
memcfg_w(index, data);
break;
}
case 0x00d0/4:
@ -713,3 +738,124 @@ void sgi_mc_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
break;
}
}
/*
* When the configured memory size for a bank exceeds the physical memory
* installed in the bank, the physical memory is mirrored in the configured
* range. When dual ranks are configured, the configured space is divided in
* two and each rank of the installed memory mirrored in the corresponding
* half. When the configured and installed number of ranks do not match, either
* half of the installed memory will be inaccessible, or half of the configured
* range will not be mapped to anything.
*
* The lowest 512KiB of whatever is mapped into physical memory segment 0
* (address 0x0800'0000) is also mapped at address 0.
*/
void sgi_mc_device::memcfg_w(offs_t offset, u32 data)
{
LOGMASKED(LOG_MEMCFG, "memcfg%d 0x%08x\n", offset, data);
// remove existing mapping
for (unsigned bank = 0; bank < 2; bank++)
{
// if previous memory configuration was valid, unmap the whole configured range
if (BIT(m_memcfg[offset], 29 - bank * 16))
{
u32 const conf_base = BIT(m_memcfg[offset], 16 - bank * 16, 8) << 22;
u32 const conf_size = (BIT(m_memcfg[offset], 24 - bank * 16, 5) + 1) << 22;
LOGMASKED(LOG_MEMCFG, "unmap bank %c 0x%08x-0x%08x\n",
offset * 2 + bank + 'A', conf_base, conf_base + conf_size - 1);
m_space->unmap_readwrite(conf_base, conf_base + conf_size - 1);
if (conf_base == 0x0800'0000U)
m_space->unmap_readwrite(0x0000'0000, 0x0007'ffff);
}
}
m_memcfg[offset] = data;
u16 const simms = m_simms->read();
// install ram into memory map
for (unsigned bank = 0; bank < 2; bank++)
{
// bank configuration valid?
if (!BIT(m_memcfg[offset], 29 - bank * 16))
continue;
// simms installed in bank?
if (!BIT(simms, (offset * 2 + bank) * 4, 3))
continue;
// configured base, rank and size/rank
u32 const conf_base = BIT(m_memcfg[offset], 16 - bank * 16, 8) << 22;
unsigned const conf_rank = BIT(m_memcfg[offset], 30 - bank * 16);
u32 const conf_size = (BIT(m_memcfg[offset], 24 - bank * 16, 5) + 1) << (22 - conf_rank);
// installed rank and size/rank
unsigned const inst_rank = BIT(simms, (offset * 2 + bank) * 4 + 3);
u32 const inst_size = 1U << (BIT(simms, (offset * 2 + bank) * 4, 3) + 21 - inst_rank);
// resulting number of ranks and size/rank
unsigned const ranks = std::min(conf_rank, inst_rank) + 1;
u32 const size = std::min(conf_size, inst_size);
for (unsigned rank = 0; rank < ranks; rank++)
{
LOGMASKED(LOG_MEMCFG, "remap bank %c rank %d from 0x%08x-0x%08x mirror 0x%08x size 0x%08x offset 0x%08x\n",
offset * 2 + bank + 'A', rank, conf_base + conf_size * rank, conf_base + conf_size * rank + size - 1, (conf_size - 1) ^ (size - 1), size, size * rank);
m_space->install_ram(conf_base + conf_size * rank, conf_base + conf_size * rank + size - 1, (conf_size - 1) ^ (size - 1), &m_ram[offset * 2 + bank][size * rank]);
}
if (conf_base == 0x0800'0000U)
m_space->install_ram(0x0000'0000, 0x0007'ffff, &m_ram[offset * 2 + bank][0]);
}
}
static INPUT_PORTS_START(mc)
PORT_START("VALID")
PORT_CONFNAME(0x0f, 0x00, "Valid Banks")
PORT_START("SIMMS")
PORT_CONFNAME(0x000f, 0x0003, "RAM bank A") PORT_CONDITION("VALID", 0x01, EQUALS, 0x01)
PORT_CONFSETTING(0x0000, "Empty")
PORT_CONFSETTING(0x0001, "4x1M")
PORT_CONFSETTING(0x000a, "4x2M")
PORT_CONFSETTING(0x0003, "4x4M")
PORT_CONFSETTING(0x000c, "4x8M")
PORT_CONFSETTING(0x0005, "4x16M")
PORT_CONFSETTING(0x000e, "4x32M")
PORT_CONFNAME(0x00f0, 0x0000, "RAM bank B") PORT_CONDITION("VALID", 0x02, EQUALS, 0x02)
PORT_CONFSETTING(0x0000, "Empty")
PORT_CONFSETTING(0x0010, "4x1M")
PORT_CONFSETTING(0x00a0, "4x2M")
PORT_CONFSETTING(0x0030, "4x4M")
PORT_CONFSETTING(0x00c0, "4x8M")
PORT_CONFSETTING(0x0050, "4x16M")
PORT_CONFSETTING(0x00e0, "4x32M")
PORT_CONFNAME(0x0f00, 0x0000, "RAM bank C") PORT_CONDITION("VALID", 0x04, EQUALS, 0x04)
PORT_CONFSETTING(0x0000, "Empty")
PORT_CONFSETTING(0x0100, "4x1M")
PORT_CONFSETTING(0x0a00, "4x2M")
PORT_CONFSETTING(0x0300, "4x4M")
PORT_CONFSETTING(0x0c00, "4x8M")
PORT_CONFSETTING(0x0500, "4x16M")
PORT_CONFSETTING(0x0e00, "4x32M")
PORT_CONFNAME(0xf000, 0x0000, "RAM bank D") PORT_CONDITION("VALID", 0x08, EQUALS, 0x08)
PORT_CONFSETTING(0x0000, "Empty")
PORT_CONFSETTING(0x1000, "4x1M")
PORT_CONFSETTING(0xa000, "4x2M")
PORT_CONFSETTING(0x3000, "4x4M")
PORT_CONFSETTING(0xc000, "4x8M")
PORT_CONFSETTING(0x5000, "4x16M")
PORT_CONFSETTING(0xe000, "4x32M")
INPUT_PORTS_END
ioport_constructor sgi_mc_device::device_input_ports() const
{
return INPUT_PORTS_NAME(mc);
}

View File

@ -34,12 +34,12 @@ public:
void write(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
void set_cpu_buserr(uint32_t address, uint64_t mem_mask);
uint32_t get_mem_config(int channel) const { return m_mem_config[channel]; }
protected:
// device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
virtual ioport_constructor device_input_ports() const override;
private:
enum
@ -63,9 +63,13 @@ private:
void update_count();
void memcfg_w(offs_t offset, u32 data);
required_device<cpu_device> m_maincpu;
required_device<eeprom_serial_93cxx_device> m_eeprom;
required_ioport m_simms;
devcb_write_line m_int_dma_done_cb;
devcb_read_line m_eisa_present;
@ -84,7 +88,7 @@ private:
uint32_t m_gio64_arb_param;
uint32_t m_arb_cpu_time;
uint32_t m_arb_burst_time;
uint32_t m_mem_config[2];
uint32_t m_memcfg[2];
uint32_t m_cpu_mem_access_config;
uint32_t m_gio_mem_access_config;
uint32_t m_cpu_error_addr;
@ -110,9 +114,10 @@ private:
uint32_t m_dma_run;
uint32_t m_eeprom_ctrl;
uint32_t m_semaphore[16];
std::unique_ptr<u8[]> m_ram[4];
};
DECLARE_DEVICE_TYPE(SGI_MC, sgi_mc_device)
#endif // MAME_SGI_MC_H