From 7a1cd3d27ae2bf7ab77181e0c93b61d44f375ccc Mon Sep 17 00:00:00 2001 From: Nigel Barnes Date: Sun, 29 Sep 2024 22:07:28 +0100 Subject: New systems marked not working ------------------------------ Triple X [Nigel Barnes, Binary Dinosaurs] --- src/mame/mame.lst | 3 + src/mame/misc/triplex.cpp | 430 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 433 insertions(+) create mode 100644 src/mame/misc/triplex.cpp diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 6d167754ff0..7e4e4cc2db7 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -32212,6 +32212,9 @@ tomsadvs // toratora // (c) 1980 Game Plan toratorab // (c) 1980 Game Plan +@source:misc/triplex.cpp +triplex // Torch Triple X + @source:misc/triton.cpp triton41 // 1978 Transam Triton L4.1 triton51 // 1979 Transam Triton L5.1 diff --git a/src/mame/misc/triplex.cpp b/src/mame/misc/triplex.cpp new file mode 100644 index 00000000000..9ae0a68b363 --- /dev/null +++ b/src/mame/misc/triplex.cpp @@ -0,0 +1,430 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/************************************************************************************************************ + + Torch Triple X + + Known components: + - 68010 CPU + - 68451 MMU + - 68450 DMA + - 6845 CRTC + - 6303 MPU + - 6840 Timer + - HD146818 RTC + - 6850 UART + - NCR5380 SCSI + - AM7990 LANCE 20MHz + - 8530 SCC + - 20MHz XTAL + - 16MHz XTAL + - 4.9152MHz XTAL + + TODO: + - emulate the OMTI 5200 controller board, with floppy. + - dump keyboard MCU and implement full keyboard, with mouse. + +************************************************************************************************************/ + +#include "emu.h" + +#include "bus/bbc/1mhzbus/1mhzbus.h" +#include "bus/nscsi/devices.h" +#include "bus/rs232/rs232.h" +#include "bus/rs232/keyboard.h" +#include "cpu/m68000/m68010.h" +#include "cpu/m6800/m6801.h" +#include "machine/6840ptm.h" +#include "machine/6850acia.h" +#include "machine/am79c90.h" +#include "machine/hd63450.h" +#include "machine/input_merger.h" +#include "machine/mc146818.h" +#include "machine/ncr5380.h" +#include "machine/z80scc.h" +#include "sound/spkrdev.h" +#include "video/mc6845.h" + +#include "emupal.h" +#include "screen.h" +#include "softlist_dev.h" +#include "speaker.h" + + +namespace { + +class triplex_state : public driver_device +{ +public: + triplex_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_dmac(*this, "dmac") + , m_mpu(*this, "mpu") + , m_crtc(*this, "crtc") + , m_kbd(*this, "kbd") + , m_speaker(*this, "speaker") + , m_vram(*this, "vram", 0x10000, ENDIANNESS_LITTLE) + , m_vram_bank(*this, "vram_bank") + , m_palette(*this, "palette") + , m_ncr5380(*this, "scsi:7:ncr5380") + , m_serial_c(*this, "serial_c") + { + } + + void triplex(machine_config &config); + +protected: + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD; + +private: + required_device m_maincpu; + required_device m_dmac; + required_device m_mpu; + required_device m_crtc; + required_device m_kbd; + required_device m_speaker; + memory_share_creator m_vram; + required_memory_bank m_vram_bank; + required_device m_palette; + required_device m_ncr5380; + required_device m_serial_c; + + void mem_map(address_map &map) ATTR_COLD; + void mpu_map(address_map &map) ATTR_COLD; + + u16 buserror_r(offs_t offset); + void buserror_w(offs_t offset, u16 data); + + u8 mpu_p1_r(); + void mpu_p1_w(u8 data); + u8 mpu_p2_r(); + void mpu_p2_w(u8 data); + + MC6845_UPDATE_ROW(crtc_update_row); + MC6845_ON_UPDATE_ADDR_CHANGED(crtc_update_addr); + + u8 m_vmode = 0; + int m_keyclk = 0; +}; + + +void triplex_state::machine_start() +{ + m_vram_bank->configure_entries(0, 2, m_vram, 0x8000); + + save_item(NAME(m_vmode)); +} + +void triplex_state::machine_reset() +{ + m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + + m_vmode = 0; +} + + +void triplex_state::mpu_map(address_map &map) +{ + map(0x0100, 0x0107).rw("ptm", FUNC(ptm6840_device::read), FUNC(ptm6840_device::write)); + map(0x0200, 0x0201).rw("acia", FUNC(acia6850_device::read), FUNC(acia6850_device::write)); + map(0x0300, 0x033f).rw("rtc", FUNC(mc146818_device::read_direct), FUNC(mc146818_device::write_direct)); + map(0x0400, 0x0400).rw("crtc", FUNC(mc6845_device::status_r), FUNC(mc6845_device::address_w)); + map(0x0401, 0x0401).rw("crtc", FUNC(mc6845_device::register_r), FUNC(mc6845_device::register_w)); + map(0x0500, 0x050f).w("palette", FUNC(palette_device::write8)).share("palette"); + map(0x0600, 0x06ff).rw("xbus", FUNC(bbc_1mhzbus_slot_device::fred_r), FUNC(bbc_1mhzbus_slot_device::fred_w)); + map(0x0700, 0x07ff).rw("xbus", FUNC(bbc_1mhzbus_slot_device::jim_r), FUNC(bbc_1mhzbus_slot_device::jim_w)); + map(0x4000, 0x0bfff).bankrw("vram_bank"); + map(0xc000, 0xffff).rom().region("rom", 0); +} + + +void triplex_state::mem_map(address_map &map) +{ + map(0x000000, 0x00ffff).lrw8(NAME([this](offs_t offset) { return m_vram[offset]; }), NAME([this](offs_t offset, u8 data) { m_vram[offset] = data; })); + map(0x040000, 0x040007).rw("scc", FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask16(0x00ff); + //map(0x060000, 0x060000) // IACK + map(0x080000, 0x08003f).rw("dmac", FUNC(hd63450_device::read), FUNC(hd63450_device::write)); + //map(0x0a0000, 0x0a00ff).rw("mmu", FUNC(mc68451_device::read), FUNC(mc68451_device::write)); + map(0x0c0000, 0x0c0003).rw("lance", FUNC(am7990_device::regs_r), FUNC(am7990_device::regs_w)); + map(0x0e0000, 0x0e000f).rw(m_ncr5380, FUNC(ncr5380_device::read), FUNC(ncr5380_device::write)).umask16(0xff00); + map(0x100000, 0x1fffff).ram(); // main memory + map(0x200000, 0x2fffff).ram(); // limpet board (VMEbus) + map(0x300000, 0x7fffff).rw(FUNC(triplex_state::buserror_r), FUNC(triplex_state::buserror_w)); +} + + +u16 triplex_state::buserror_r(offs_t offset) +{ + if(!machine().side_effects_disabled()) + { + m_maincpu->set_buserror_details(0x100000 + offset*2, true, m_maincpu->get_fc()); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + } + return 0xffff; +} + +void triplex_state::buserror_w(offs_t offset, u16 data) +{ + if(!machine().side_effects_disabled()) + { + m_maincpu->set_buserror_details(0x100000 + offset*2, false, m_maincpu->get_fc()); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, ASSERT_LINE); + m_maincpu->set_input_line(M68K_LINE_BUSERROR, CLEAR_LINE); + } +} + + +u8 triplex_state::mpu_p1_r() +{ + // P10 FAIL + return 0x00; +} + +void triplex_state::mpu_p1_w(u8 data) +{ + //logerror("%s mpu_p1_w: %02x\n", machine().describe_context(), data); + + // P11 POWERUP + + // P12 VIDSEL + m_vram_bank->set_entry(BIT(data, 2)); + + // P13 PRESET + m_maincpu->set_input_line(INPUT_LINE_HALT, BIT(data, 3)); + m_maincpu->set_input_line(INPUT_LINE_RESET, BIT(data, 3)); + + // P14 PROCINT + //m_dmac->pcl0_w(BIT(data, 4)); + + // P15/6 VMODE + m_vmode = BIT(data, 5, 2); + + // P17 SSDTR + m_serial_c->write_dtr(BIT(data, 7)); +} + + +u8 triplex_state::mpu_p2_r() +{ + u8 data = 0x00; + + // P20 VSYNC + data |= m_crtc->vsync_r() << 0; + + // P22 KEYCLK + data |= m_keyclk << 2; + + // P23 KEYRX + data |= m_kbd->rxd_r() << 3; + + //logerror("%s mpu_p2_r: %02x\n", machine().describe_context(), data); + return data; +} + +void triplex_state::mpu_p2_w(u8 data) +{ + //logerror("%s mpu_p2_w: %02x\n", machine().describe_context(), data); + + // P21 AUDIO + m_speaker->level_w(BIT(data, 1)); + + // P24 KEYTX + m_kbd->write_txd(BIT(data, 4)); +} + + +MC6845_UPDATE_ROW(triplex_state::crtc_update_row) +{ + // Mode Horizontal Vertical Bits/pixel Colours + // 0 640 256 2 4 + // 1 320 256 4 16 + // 2 640 512 1 2 + // 3 320 512 2 4 + + u32 *p = &bitmap.pix(y); + rgb_t const *const palette = m_palette->palette()->entry_list_raw(); + + u16 offset = (y * 0x100) + 2; + + for (int x_pos = 0; x_pos < (x_count*2); x_pos++) + { + u8 data = m_vram[offset + x_pos]; + + switch (m_vmode) + { + case 0: case 3: + *p++ = palette[BIT(data, 6, 2)]; + *p++ = palette[BIT(data, 4, 2)]; + *p++ = palette[BIT(data, 2, 2)]; + *p++ = palette[BIT(data, 0, 2)]; + break; + case 1: + *p++ = palette[BIT(data, 4, 4)]; + *p++ = palette[BIT(data, 0, 4)]; + break; + case 2: + *p++ = palette[BIT(data, 7, 1)]; + *p++ = palette[BIT(data, 6, 1)]; + *p++ = palette[BIT(data, 5, 1)]; + *p++ = palette[BIT(data, 4, 1)]; + *p++ = palette[BIT(data, 3, 1)]; + *p++ = palette[BIT(data, 2, 1)]; + *p++ = palette[BIT(data, 1, 1)]; + *p++ = palette[BIT(data, 0, 1)]; + break; + } + } +} + + +MC6845_ON_UPDATE_ADDR_CHANGED(triplex_state::crtc_update_addr) +{ + //logerror("crtc_update_addr: address %04x strobe %d\n", address, strobe); +} + + +void triplex_keyboard_devices(device_slot_interface &device) +{ + device.option_add("keyboard", SERIAL_KEYBOARD); +} + +static DEVICE_INPUT_DEFAULTS_START(keyboard) + DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0xff, RS232_BAUD_1200) + 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 + + +void triplex_state::triplex(machine_config &config) +{ + M68010(config, m_maincpu, 16_MHz_XTAL / 2); + m_maincpu->set_addrmap(AS_PROGRAM, &triplex_state::mem_map); + + HD63450(config, m_dmac, 16_MHz_XTAL / 2, m_maincpu); // HD68450 + m_dmac->irq_callback().set_inputline(m_maincpu, M68K_IRQ_3); + m_dmac->dma_read<0>().set(m_ncr5380, FUNC(ncr5380_device::dma_r)); + m_dmac->dma_write<0>().set(m_ncr5380, FUNC(ncr5380_device::dma_w)); + + // TODO: MC68451 MMU + + am7990_device &lance(AM7990(config, "lance", 20_MHz_XTAL)); + lance.intr_out().set_inputline(m_maincpu, M68K_IRQ_2); + lance.dma_in().set([this](offs_t offset) { return m_maincpu->space(AS_PROGRAM).read_word(offset); }); + lance.dma_out().set([this](offs_t offset, u16 data, u16 mem_mask) { m_maincpu->space(AS_PROGRAM).write_word(offset, data, mem_mask); }); + + NSCSI_BUS(config, "scsi"); + NSCSI_CONNECTOR(config, "scsi:0", default_scsi_devices, "harddisk"); // OMTI 5200 (with floppy controller) + NSCSI_CONNECTOR(config, "scsi:1", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:2", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:3", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:4", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:5", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:6", default_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:7").option_set("ncr5380", NCR5380).machine_config([this](device_t *device) { + downcast(*device).irq_handler().set_inputline(m_maincpu, M68K_IRQ_4); + downcast(*device).drq_handler().set(":dmac", FUNC(hd63450_device::drq0_w)); + }); + + scc8530_device &scc(SCC8530N(config, "scc", 4.9152_MHz_XTAL)); + scc.out_int_callback().set_inputline(m_maincpu, M68K_IRQ_5); + scc.out_wreqa_callback().set("dmac", FUNC(hd63450_device::drq1_w)); + scc.out_dtra_callback().set("dmac", FUNC(hd63450_device::drq2_w)); + scc.out_wreqb_callback().set("dmac", FUNC(hd63450_device::drq3_w)); + scc.out_txda_callback().set("serial_a", FUNC(rs232_port_device::write_txd)); + scc.out_rtsa_callback().set("serial_a", FUNC(rs232_port_device::write_rts)); + scc.out_txdb_callback().set("serial_b", FUNC(rs232_port_device::write_txd)); + scc.out_rtsb_callback().set("serial_b", FUNC(rs232_port_device::write_rts)); + scc.out_dtrb_callback().set("serial_b", FUNC(rs232_port_device::write_dtr)); + + rs232_port_device &serial_a(RS232_PORT(config, "serial_a", default_rs232_devices, nullptr)); // X25 + serial_a.rxd_handler().set("scc", FUNC(scc85230_device::rxa_w)); + serial_a.cts_handler().set("scc", FUNC(scc85230_device::ctsa_w)); + serial_a.dcd_handler().set("scc", FUNC(scc85230_device::dcda_w)); + serial_a.rxc_handler().set("scc", FUNC(scc85230_device::rxca_w)); + + rs232_port_device &serial_b(RS232_PORT(config, "serial_b", default_rs232_devices, nullptr)); // Terminal or modem + serial_b.rxd_handler().set("scc", FUNC(scc85230_device::rxb_w)); + serial_b.cts_handler().set("scc", FUNC(scc85230_device::ctsb_w)); + serial_b.dcd_handler().set("scc", FUNC(scc85230_device::dcdb_w)); + + // Service Processor + HD6303R(config, m_mpu, 16_MHz_XTAL / 4); + m_mpu->set_addrmap(AS_PROGRAM, &triplex_state::mpu_map); + m_mpu->in_p1_cb().set(FUNC(triplex_state::mpu_p1_r)); + m_mpu->out_p1_cb().set(FUNC(triplex_state::mpu_p1_w)); + m_mpu->in_p2_cb().set(FUNC(triplex_state::mpu_p2_r)); + m_mpu->out_p2_cb().set(FUNC(triplex_state::mpu_p2_w)); + m_mpu->out_ser_tx_cb().set("kbd", FUNC(rs232_port_device::write_txd)); + + INPUT_MERGER_ANY_HIGH(config, "irqs").output_handler().set_inputline(m_mpu, M6801_IRQ1_LINE); + + SPEAKER(config, "mono").front_center(); + SPEAKER_SOUND(config, "speaker").add_route(ALL_OUTPUTS, "mono", 0.5); + + RS232_PORT(config, m_kbd, triplex_keyboard_devices, "keyboard"); + m_kbd->set_option_device_input_defaults("keyboard", DEVICE_INPUT_DEFAULTS_NAME(keyboard)); + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_raw(16_MHz_XTAL, 1024, 0, 720, 312, 0, 256); + screen.set_screen_update("crtc", FUNC(mc6845_device::screen_update)); + + SY6845E(config, m_crtc, 16_MHz_XTAL / 8); + m_crtc->set_screen("screen"); + m_crtc->set_show_border_area(false); + m_crtc->set_char_width(8); + m_crtc->set_update_row_callback(FUNC(triplex_state::crtc_update_row)); + m_crtc->set_on_update_addr_change_callback(FUNC(triplex_state::crtc_update_addr)); + m_crtc->out_vsync_callback().set_inputline(m_mpu, M6801_TIN_LINE); + m_crtc->out_vsync_callback().append_inputline(m_maincpu, M68K_IRQ_6); + + PALETTE(config, "palette").set_format(palette_device::RGB_332_inverted, 16); + + mc146818_device &rtc(MC146818(config, "rtc", 32.768_kHz_XTAL)); + rtc.set_24hrs(true); + rtc.set_binary(true); + rtc.irq().set("irqs", FUNC(input_merger_device::in_w<0>)); + + ptm6840_device &ptm(PTM6840(config, "ptm", 16_MHz_XTAL / 16)); + ptm.set_external_clocks(4.9152_MHz_XTAL/16, 4.9152_MHz_XTAL/16, 4.9152_MHz_XTAL/16); + ptm.o1_callback().set("acia", FUNC(acia6850_device::write_rxc)); + ptm.o2_callback().set("acia", FUNC(acia6850_device::write_txc)); + ptm.o3_callback().set([this](int state) { m_keyclk = state; if (state) m_mpu->clock_serial(); }); // KEYCLK + ptm.irq_callback().set("irqs", FUNC(input_merger_device::in_w<1>)); + + acia6850_device &acia(ACIA6850(config, "acia", 0)); + acia.txd_handler().set(m_serial_c, FUNC(rs232_port_device::write_txd)); + acia.rts_handler().set(m_serial_c, FUNC(rs232_port_device::write_rts)); + acia.irq_handler().set("irqs", FUNC(input_merger_device::in_w<2>)); + + RS232_PORT(config, m_serial_c, default_rs232_devices, "printer"); // Printer + m_serial_c->rxd_handler().set("acia", FUNC(acia6850_device::write_rxd)); + m_serial_c->dcd_handler().set("acia", FUNC(acia6850_device::write_dcd)); + m_serial_c->cts_handler().set("acia", FUNC(acia6850_device::write_cts)); + + BBC_1MHZBUS_SLOT(config, "xbus", 16_MHz_XTAL / 16, bbcm_1mhzbus_devices, nullptr); // TODO: modem board + + //SOFTWARE_LIST(config, "flop_list").set_original("triplex_flop"); +} + + +ROM_START(triplex) + ROM_REGION(0x4000, "rom", 0) + ROM_SYSTEM_BIOS(0, "13", "Caretaker 1.3") + ROMX_LOAD("caretaker_iss1.3.bin", 0x0000, 0x4000, CRC(a3031aa1) SHA1(4d0f9ca854bbf236890bb1c342977a493df1e3d4), ROM_BIOS(0)) + + ROM_SYSTEM_BIOS(1, "12", "Caretaker 1.2") + ROMX_LOAD("caretaker_iss1.2.bin", 0x0000, 0x4000, CRC(3b1aa08b) SHA1(92bd672d0e13921cd51a9254031270cd0bb34d73), ROM_BIOS(1)) + + //DISK_REGION("scsi:0:harddisk") + //DISK_IMAGE("torch_system5", 0, NO_DUMP) // HDD images at https://bitsavers.org/bits/Torch/, not verified until machine working. +ROM_END + +} // anonymous namespace + + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP(1985, triplex, 0, 0, triplex, 0, triplex_state, empty_init, "Torch Computers", "Triple X", MACHINE_NOT_WORKING) -- cgit v1.2.3