diff options
Diffstat (limited to 'src/devices/bus/vme/cp31.cpp')
-rw-r--r-- | src/devices/bus/vme/cp31.cpp | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/src/devices/bus/vme/cp31.cpp b/src/devices/bus/vme/cp31.cpp new file mode 100644 index 00000000000..14b739713fe --- /dev/null +++ b/src/devices/bus/vme/cp31.cpp @@ -0,0 +1,315 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev + +/* + * Besta CP31 board, possibly a customized version of Force CPU30. + * + * Supported by SysV R3 "Bestix" port and also by Linux port, + * see https://github.com/shattered/linux-m68k + * + * Chips: + * + * 68030 @ 25 MHz - CPU + * 68882 @ 25 MHz - FPU + * 68561 - MPCC (serial port) + * 68230 - PI/T (parallel interface and timer) + * 68153 - BIM (interrupt router) + * 62421 - RTC + * + * To do: + * + * - pass functional test + * - boot to multiuser (SysV and Linux) (requires ISCSI-1) + * + */ + +#include "emu.h" + +#include "cp31.h" + + +#define LOG_INT (1U << 1) + +#define VERBOSE (0) // (LOG_GENERAL | LOG_INT) +//#define LOG_OUTPUT_FUNC printf +#include "logmacro.h" + +#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__) + + +#ifdef _MSC_VER +#define FUNCNAME __func__ +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#endif + + +#define CLOCK50 XTAL(50'000'000) /* HCJ */ +#define CLOCK40 XTAL(40'000'000) /* HCJ */ +#define CLOCK32 XTAL(32'000'000) /* HCJ */ + +#define RS232P1_TAG "rs232p1" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +DEFINE_DEVICE_TYPE(VME_CP31, vme_cp31_card_device, "cp31", "Besta CP31 CPU board") + +void vme_cp31_card_device::cp31_mem(address_map &map) +{ + map.unmap_value_high(); + map(0x00000000, 0x001fffff).ram().share("dram"); // local bus DRAM, 4 MB +// map(0x08010000, 0x08011fff).ram(); // unknown -- accessed by cp31dssp +// map(0xfca03500, 0xfca0350f).unmaprw(); // ISCSI-1 board on VME bus + map(0xff000000, 0xff03ffff).rom().region("user1", 0); + map(0xff040000, 0xff07ffff).ram(); // onboard SRAM + map(0xff800000, 0xff80001f).rw(m_mpcc, FUNC(mpcc68561_device::read), FUNC(mpcc68561_device::write)); + map(0xff800200, 0xff8003ff).rw(m_pit2, FUNC(pit68230_device::read), FUNC(pit68230_device::write)); + map(0xff800800, 0xff80080f).rw(m_bim, FUNC(bim68153_device::read), FUNC(bim68153_device::write)).umask32(0xff00ff00); + map(0xff800a00, 0xff800a1f).rw(m_rtc, FUNC(rtc62421_device::read), FUNC(rtc62421_device::write)); + map(0xff800c00, 0xff800dff).rw(m_pit1, FUNC(pit68230_device::read), FUNC(pit68230_device::write)); +// map(0xff800400, 0xff800xxx) // TIC? -- shows up in cp31dssp log +// map(0xff800e00, 0xff800xxx) // PIT3? +} + +static DEVICE_INPUT_DEFAULTS_START( terminal ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) +DEVICE_INPUT_DEFAULTS_END + +// FIXME unverified +static INPUT_PORTS_START(cp31) + PORT_START("SA1") + PORT_DIPNAME(0x01, 0x00, "Clear macros on reset") + PORT_DIPSETTING(0x00, "On") + PORT_DIPSETTING(0x01, "Off") + PORT_DIPNAME(0x02, 0x00, "VME bus width") + PORT_DIPSETTING(0x00, "16 bits") + PORT_DIPSETTING(0x02, "32 bits") + PORT_DIPNAME(0x0c, 0x0c, "Boot into...") + PORT_DIPSETTING(0x00, "UNIX") + PORT_DIPSETTING(0x0c, "Monitor") + PORT_DIPNAME(0x10, 0x10, "Console port setup") + PORT_DIPSETTING(0x00, "Custom") + PORT_DIPSETTING(0x10, "Standard") + PORT_DIPNAME(0x20, 0x20, "Console port bits") + PORT_DIPSETTING(0x00, "7N1") + PORT_DIPSETTING(0x20, "8N2") + PORT_DIPNAME(0xc0, 0xc0, "Console port speed") + PORT_DIPSETTING(0xc0, "9600") + PORT_DIPSETTING(0x80, "4800") + PORT_DIPSETTING(0x40, "2400") + PORT_DIPSETTING(0x00, "1200") +INPUT_PORTS_END + +ROM_START(cp31) + ROM_REGION32_BE(0x40000, "user1", ROMREGION_ERASEFF) + + ROM_DEFAULT_BIOS("cp31dssp") + ROM_SYSTEM_BIOS(0, "cp31dbg", "CP31 Debug") + ROMX_LOAD( "cp31dbgboot.27c512", 0x0000, 0x10000, CRC(9bf057de) SHA1(b13cb16042e4c6ca63ae26058a78259c0849d0b6), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "cp31dssp", "CP31 DSSP") + ROMX_LOAD( "cp31dsspboot.27c512", 0x0000, 0x10000, CRC(607a0a55) SHA1(c257a88672ab39d2f3fad681d22e062182b0236d), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(2, "cp31os9", "CP31 OS9") + ROMX_LOAD( "cp31os9.27c512", 0x0000, 0x10000, CRC(607a0a55) SHA1(c257a88672ab39d2f3fad681d22e062182b0236d), ROM_BIOS(2)) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const tiny_rom_entry *vme_cp31_card_device::device_rom_region() const +{ + return ROM_NAME(cp31); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vme_cp31_card_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(cp31); +} + + +void vme_cp31_card_device::cpu_space_map(address_map &map) +{ + map(0xfffffff2, 0xffffffff).lr16(NAME([this](offs_t offset) -> u16 { return m_bim->iack(offset+1); })); +} + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void vme_cp31_card_device::device_add_mconfig(machine_config &config) +{ + M68030(config, m_maincpu, CLOCK50 / 2); + m_maincpu->set_addrmap(AS_PROGRAM, &vme_cp31_card_device::cp31_mem); + m_maincpu->set_addrmap(m68000_base_device::AS_CPU_SPACE, &vme_cp31_card_device::cpu_space_map); + + MC68153(config, m_bim, CLOCK32 / 8); + m_bim->out_int_callback().set(FUNC(vme_cp31_card_device::bim_irq_callback)); + + MPCC68561(config, m_mpcc, 1392000, 0, 0); // FIXME: XTAL unknown + m_mpcc->out_txd_cb().set(RS232P1_TAG, FUNC(rs232_port_device::write_txd)); + m_mpcc->out_dtr_cb().set(RS232P1_TAG, FUNC(rs232_port_device::write_dtr)); + m_mpcc->out_rts_cb().set(RS232P1_TAG, FUNC(rs232_port_device::write_rts)); + m_mpcc->out_int_cb().set(m_bim, FUNC(bim68153_device::int1_w)); + + rs232_port_device &rs232p1(RS232_PORT(config, RS232P1_TAG, default_rs232_devices, "terminal")); + rs232p1.rxd_handler().set(m_mpcc, FUNC(mpcc68561_device::write_rx)); + rs232p1.cts_handler().set(m_mpcc, FUNC(mpcc68561_device::cts_w)); + rs232p1.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); + + RTC62421(config, m_rtc, 32.768_kHz_XTAL); + m_rtc->out_int_handler().set(m_pit1, FUNC(pit68230_device::h2_w)); + + // H1 is SYSFAIL and H3 is ACFAIL + PIT68230(config, m_pit1, 8064000); // via c33_txt + m_pit1->pa_in_callback().set_ioport("SA1"); + m_pit1->pb_out_callback().set(*this, FUNC(vme_cp31_card_device::pit1_pb_w)); + m_pit1->pc_in_callback().set(*this, FUNC(vme_cp31_card_device::pit1_pc_r)); +// m_pit1->pc_out_callback().set(*this, FUNC(vme_cp31_card_device::pit1_pc_w)); + m_pit1->timer_irq_callback().set(m_bim, FUNC(bim68153_device::int2_w)); + m_pit1->port_irq_callback().set(m_bim, FUNC(bim68153_device::int3_w)); + + PIT68230(config, m_pit2, 8064000); // via c33_txt + m_pit2->port_irq_callback().set(m_pit1, FUNC(pit68230_device::h4_w)); +} + +uint32_t vme_cp31_card_device::trap_r(offs_t offset, uint32_t mem_mask) +{ + if (!machine().side_effects_disabled()) set_bus_error((offset << 2), true, mem_mask); + + return 0xffffffff; +} + +void vme_cp31_card_device::bim_irq_callback(int state) +{ + LOGINT("%s(%02x)\n", FUNCNAME, state); + + bim_irq_state = state; + bim_irq_level = m_bim->get_irq_level(); + LOGINT(" - BIM irq level %s\n", bim_irq_level == CLEAR_LINE ? "Cleared" : "Asserted"); + update_irq_to_maincpu(); +} + +// TODO: IRQ masking +void vme_cp31_card_device::update_irq_to_maincpu() +{ + LOGINT("%s()\n", FUNCNAME); + LOGINT(" - bim_irq_level: %02x\n", bim_irq_level); + LOGINT(" - bim_irq_state: %02x\n", bim_irq_state); + switch (bim_irq_level & 0x07) + { + case 1: m_maincpu->set_input_line(M68K_IRQ_1, bim_irq_state); break; + case 2: m_maincpu->set_input_line(M68K_IRQ_2, bim_irq_state); break; + case 3: m_maincpu->set_input_line(M68K_IRQ_3, bim_irq_state); break; + case 4: m_maincpu->set_input_line(M68K_IRQ_4, bim_irq_state); break; + case 5: m_maincpu->set_input_line(M68K_IRQ_5, bim_irq_state); break; + case 6: m_maincpu->set_input_line(M68K_IRQ_6, bim_irq_state); break; + case 7: m_maincpu->set_input_line(M68K_IRQ_7, bim_irq_state); break; + default: logerror("Programmatic error in %s, please report\n", FUNCNAME); + } +} + + +void vme_cp31_card_device::trap_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOG("%s(%08x,%08X)\n", FUNCNAME, offset << 2, data); + if (!machine().side_effects_disabled()) set_bus_error((offset << 2), false, mem_mask); +} + +// PC4 - IRQ7 state, PC6 - FPCP SENSE (0 = FPCP installed) +uint8_t vme_cp31_card_device::pit1_pc_r() +{ + uint8_t data = 0; + + LOG("%s(%02X)\n", FUNCNAME, data); + + return data; +} + +// IRQ masking +void vme_cp31_card_device::pit1_pb_w(uint8_t data) +{ + LOG("%s(%02X)\n", FUNCNAME, data); +} + +void vme_cp31_card_device::set_bus_error(uint32_t address, bool rw, uint32_t mem_mask) +{ + if (m_bus_error) + { + return; + } + LOG("bus error at %08x & %08x (%s)\n", address, mem_mask, rw ? "read" : "write"); + if (!ACCESSING_BITS_16_31) + { + address++; + } + m_bus_error = true; + m_maincpu->set_buserror_details(address, rw, m_maincpu->get_fc()); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_bus_error_timer->adjust(m_maincpu->cycles_to_attotime(16)); // let rmw cycles complete +} + +vme_cp31_card_device::vme_cp31_card_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_vme_card_interface(mconfig, *this) + , m_maincpu(*this, "maincpu") + , m_bim(*this, "bim") + , m_mpcc(*this, "mpcc") + , m_rtc(*this, "rtc") + , m_pit1(*this, "pit1") + , m_pit2(*this, "pit2") + , m_p_ram(*this, "dram") + , m_sysrom(*this, "user1") +{ +} + +// + +vme_cp31_card_device::vme_cp31_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : vme_cp31_card_device(mconfig, VME_CP31, tag, owner, clock) +{ +} + +void vme_cp31_card_device::device_start() +{ + m_bus_error_timer = timer_alloc(FUNC(vme_cp31_card_device::bus_error_off), this); +} + +void vme_cp31_card_device::device_reset() +{ + address_space &program = m_maincpu->space(AS_PROGRAM); + + program.install_rom(0x00000000, 0x00000007, m_sysrom); // do it here for F3 + m_rom_shadow_tap.remove(); + m_rom_shadow_tap = program.install_read_tap( + 0xff000000, 0xff007fff, + "rom_shadow_r", + [this] (offs_t offset, u32 &data, u32 mem_mask) + { + if (!machine().side_effects_disabled()) + { + // delete this tap + m_rom_shadow_tap.remove(); + + // reinstall RAM over the ROM shadow + m_maincpu->space(AS_PROGRAM).install_ram(0x00000000, 0x00000007, m_p_ram); + } + }, + &m_rom_shadow_tap); +} + +TIMER_CALLBACK_MEMBER(vme_cp31_card_device::bus_error_off) +{ + m_bus_error = false; +} |