From 23b6a0c6cce63c8bfc4377cbf793f395243732dc Mon Sep 17 00:00:00 2001 From: hap Date: Wed, 29 Jul 2020 20:16:59 +0200 Subject: [PATCH] ssystem3: added chess unit lcd svg screen [hap, Berger, Achim] --- src/devices/machine/6821pia.h | 2 +- src/devices/video/hlcd0438.cpp | 41 ++++-- src/devices/video/hlcd0438.h | 14 +- src/mame/drivers/saitek_ssystem3.cpp | 199 ++++++++++++++++++++------- src/mame/drivers/tamag1.cpp | 1 + 5 files changed, 188 insertions(+), 69 deletions(-) diff --git a/src/devices/machine/6821pia.h b/src/devices/machine/6821pia.h index cceff8a5a09..f6ffa71ca8b 100644 --- a/src/devices/machine/6821pia.h +++ b/src/devices/machine/6821pia.h @@ -57,7 +57,7 @@ public: uint8_t read_alt(offs_t offset) { return read(((offset << 1) & 0x02) | ((offset >> 1) & 0x01)); } void write_alt(offs_t offset, uint8_t data) { write(((offset << 1) & 0x02) | ((offset >> 1) & 0x01), data); } - uint8_t port_b_z_mask() const { return ~m_ddr_b; } // see first note in .c + uint8_t port_b_z_mask() const { return ~m_ddr_b; } // see notes void porta_w(uint8_t data); void write_porta_line(int line, bool state); diff --git a/src/devices/video/hlcd0438.cpp b/src/devices/video/hlcd0438.cpp index e349654e592..42317ddb087 100644 --- a/src/devices/video/hlcd0438.cpp +++ b/src/devices/video/hlcd0438.cpp @@ -5,8 +5,7 @@ Hughes HLCD 0438 LCD Driver 32 segment outputs, may also be used as a column driver -TODO: -- OSC (LCD phi pin) +LCD pin can be driven manually, or oscillating. */ @@ -32,15 +31,23 @@ hlcd0438_device::hlcd0438_device(const machine_config &mconfig, const char *tag, void hlcd0438_device::device_start() { + // resolve callbacks m_write_segs.resolve_safe(); m_write_data.resolve_safe(); + // timer (when LCD pin is oscillator) + m_lcd_timer = timer_alloc(); + attotime period = (clock() != 0) ? attotime::from_hz(2 * clock()) : attotime::never; + m_lcd_timer->adjust(period, 0, period); + // register for savestates save_item(NAME(m_data_in)); save_item(NAME(m_data_out)); save_item(NAME(m_clk)); save_item(NAME(m_load)); + save_item(NAME(m_lcd)); save_item(NAME(m_shift)); + save_item(NAME(m_latch)); } @@ -48,13 +55,6 @@ void hlcd0438_device::device_start() // handlers //------------------------------------------------- -void hlcd0438_device::update_output() -{ - // load output latches while LOAD pin is high - if (m_load) - m_write_segs(0, m_shift); -} - void hlcd0438_device::clock_w(int state) { state = state ? 1 : 0; @@ -67,10 +67,29 @@ void hlcd0438_device::clock_w(int state) m_shift = m_shift << 1 | m_data_in; - // output m_write_data(m_data_out); - update_output(); + load_w(m_load); } m_clk = state; } + +void hlcd0438_device::load_w(int state) +{ + m_load = state ? 1 : 0; + + // load to output latches while LOAD pin is high + if (m_load) + m_latch = m_shift; +} + +void hlcd0438_device::lcd_w(int state) +{ + state = state ? 1 : 0; + + // LCD pin drives backplate + if (state != m_lcd) + m_write_segs(m_lcd, m_latch); + + m_lcd = state; +} diff --git a/src/devices/video/hlcd0438.h b/src/devices/video/hlcd0438.h index a8a1b68d465..2b1ec257d1c 100644 --- a/src/devices/video/hlcd0438.h +++ b/src/devices/video/hlcd0438.h @@ -24,7 +24,7 @@ SEG 28 7 | | 34 DATA IN SEG 27 8 | | 33 SEG 4 SEG 26 9 | | 32 SEG 5 - SEG 25 10 | HLCD 0438 | 31 LCD phi + SEG 25 10 | HLCD 0438 | 31 LCD SEG 24 11 | | 30 BP SEG 23 12 | | 29 SEG 6 SEG 22 13 | | 28 SEG 7 @@ -45,29 +45,33 @@ public: hlcd0438_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); // configuration helpers - auto write_segs() { return m_write_segs.bind(); } // SEG pins + auto write_segs() { return m_write_segs.bind(); } // BP pin in offset, SEG pins in data auto write_data() { return m_write_data.bind(); } // DATA OUT pin hlcd0438_device &set_load(int state) { m_load = state ? 1 : 0; return *this; } // if hardwired, can just set LOAD pin state here void data_w(int state) { m_data_in = state ? 1 : 0; } int data_r() { return m_data_out; } - void load_w(int state) { m_load = state ? 1 : 0; update_output(); } void clock_w(int state); + void load_w(int state); + void lcd_w(int state); protected: // device-level overrides virtual void device_start() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override { lcd_w(!m_lcd); } private: + emu_timer *m_lcd_timer; + // pin state int m_data_in = 0; int m_data_out = 0; int m_clk = 0; int m_load = 0; + int m_lcd = 0; u32 m_shift = 0; - - void update_output(); + u32 m_latch = 0; devcb_write32 m_write_segs; devcb_write_line m_write_data; diff --git a/src/mame/drivers/saitek_ssystem3.cpp b/src/mame/drivers/saitek_ssystem3.cpp index 3036d4c0aed..e7baa307ca1 100644 --- a/src/mame/drivers/saitek_ssystem3.cpp +++ b/src/mame/drivers/saitek_ssystem3.cpp @@ -8,7 +8,7 @@ both SciSys and Novag. Which company was responsible for which part of the manufacturing chain is unknown. The software is by SciSys (no mention of Novag in the ROM, it has "COPYRIGHT SCISYS LTD 1979"). -This is their 1st original product. MK II was licensed from Commodore, and +This is their 1st original product. MK II was licensed from Peter Jennings, and MK I was, to put it bluntly, a bootleg. The chess engine is by Mike Johnson, with support from David Levy. @@ -25,7 +25,7 @@ Master Unit: Chess Unit: - PCB label: Radofin XM-2057-0C -- Fairchild F6808P CPU @ ~6MHz (M6808 compatible) +- Fairchild F6808P CPU @ ~6.8MHz (M6808 compatible) - Fairchild F6821P PIA - 2KB ROM(2316), 128x8 RAM(F6810P) - 2*HLCD0438, chessboard LCD @@ -54,7 +54,9 @@ TODO: Should be doable to add, but 6522 device doesn't support live clock changes. - LCD TC pin? connects to the display, source is a 50hz timer(from power supply), probably to keep refreshing the LCD when inactive, there is no need to emulate it -- finish chess unit lcd emulation +- chess unit screen briefly shows glitches when the subcpu receives an NMI in the + middle of updating the LCD, BTANB? +- add chessboard screen to artwork - dump/add printer unit - dump/add ssystem3 1980 program revision, were the BTANB fixed? - ssystem4 softwarelist if a prototype cartridge is ever dumped @@ -97,15 +99,20 @@ public: ssystem3_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), + m_subcpu(*this, "subcpu"), m_via(*this, "via"), m_pia(*this, "pia"), - m_lcd(*this, "lcd"), - m_display(*this, "display"), + m_lcd1(*this, "lcd1"), + m_lcd2(*this, "lcd2_%u", 0), + m_display(*this, "display%u", 0), m_dac(*this, "dac"), m_nvram(*this, "nvram"), - m_inputs(*this, "IN.%u", 0) + m_inputs(*this, "IN.%u", 0), + m_out_lcd2(*this, "s%u.%u", 0U, 0U) { } + DECLARE_INPUT_CHANGED_MEMBER(cu_plug); + // machine configs void ssystem3(machine_config &config); void ssystem4(machine_config &config); @@ -118,13 +125,16 @@ protected: private: // devices/pointers required_device m_maincpu; + optional_device m_subcpu; required_device m_via; optional_device m_pia; - required_device m_lcd; - required_device m_display; + required_device m_lcd1; + optional_device_array m_lcd2; + optional_device_array m_display; required_device m_dac; optional_shared_ptr m_nvram; - required_ioport_array<4+2> m_inputs; + optional_ioport_array<4+3> m_inputs; + output_finder<8, 48> m_out_lcd2; // address maps void ssystem3_map(address_map &map); @@ -132,7 +142,7 @@ private: void chessunit_map(address_map &map); // I/O handlers - void lcd_q_w(u32 data) { m_lcd_q = data; } + void lcd1_output_w(u32 data) { m_lcd1_data = data; } void input_w(u8 data); u8 input_r(); void control_w(u8 data); @@ -141,26 +151,34 @@ private: void nvram_w(offs_t offset, u8 data); u8 nvram_r(offs_t offset); - void pia_a_w(u8 data); - u8 pia_a_r(); - void pia_b_w(u8 data); - u8 pia_b_r(); - void pia_cb2_w(int state); + void lcd2_pwm_w(offs_t offset, u8 data); + void lcd2_update(); + template void lcd2_output_w(offs_t offset, u32 data); + void cu_pia_a_w(u8 data); + u8 cu_pia_a_r(); + void cu_pia_b_w(u8 data); + u8 cu_pia_b_r(); u8 m_inp_mux = 0; u8 m_control = 0; u8 m_shift = 0; - u32 m_lcd_q = 0; + u32 m_lcd1_data = 0; + u64 m_lcd2_data = 0; + u8 m_lcd2_select = 0; bool m_xor_kludge = false; }; void ssystem3_state::machine_start() { + m_out_lcd2.resolve(); + // register for savestates save_item(NAME(m_inp_mux)); save_item(NAME(m_control)); save_item(NAME(m_shift)); - save_item(NAME(m_lcd_q)); + save_item(NAME(m_lcd1_data)); + save_item(NAME(m_lcd2_data)); + save_item(NAME(m_lcd2_select)); } @@ -206,28 +224,28 @@ void ssystem3_state::control_w(u8 data) // PB1: LCD DI // PB2: LCD CLK - m_lcd->di_w(BIT(data, 1)); - m_lcd->clk_w(BIT(data, 2)); + m_lcd1->di_w(BIT(data, 1)); + m_lcd1->clk_w(BIT(data, 2)); // PB2 also clocks a 4015B // DA: LCD DO, DB: Q3A if (data & ~m_control & 4) { - m_shift = m_shift << 1 | m_lcd->do_r(); + m_shift = m_shift << 1 | m_lcd1->do_r(); // weird TTL maze, I assume it's a hw kludge to fix a bug after the maskroms were already manufactured - u8 xorval = m_xor_kludge && (BIT(m_shift, 3) & ~(BIT(m_shift, 1) ^ BIT(m_shift, 4)) & ~(BIT(m_lcd_q, 7) & BIT(m_lcd_q, 23))) ? 0x12 : 0; + u8 xorval = m_xor_kludge && (BIT(m_shift, 3) & ~(BIT(m_shift, 1) ^ BIT(m_shift, 4)) & ~(BIT(m_lcd1_data, 7) & BIT(m_lcd1_data, 23))) ? 0x12 : 0; // update display for (int i = 0; i < 4; i++) - m_display->write_row(i, m_lcd_q >> (8*i) & 0xff); - m_display->write_row(4, (m_shift ^ xorval) | 0x100); - m_display->update(); + m_display[0]->write_row(i, m_lcd1_data >> (8*i) & 0xff); + m_display[0]->write_row(4, (m_shift ^ xorval) | 0x100); + m_display[0]->update(); } // PB3: device serial out if (m_inputs[5]->read() & 2) - m_pia->ca1_w(BIT(data, 3)); + m_pia->ca1_w(BIT(~data, 3)); // PB7: tied to PB6 (pulse timer 2) m_via->write_pb6(BIT(data, 7)); @@ -239,9 +257,10 @@ u8 ssystem3_state::control_r() { u8 data = 0; - // PB4: device busy - // PB5: device attached? - //data ^= 0x30; + // PB4: device busy (unused on chess unit) + // PB5: device attached + if (m_inputs[5]->read() & 2) + data ^= 0x30; return ~data; } @@ -264,26 +283,74 @@ u8 ssystem3_state::nvram_r(offs_t offset) // Chess Unit -void ssystem3_state::pia_a_w(u8 data) +INPUT_CHANGED_MEMBER(ssystem3_state::cu_plug) { + m_subcpu->set_input_line(INPUT_LINE_RESET, newval ? CLEAR_LINE : ASSERT_LINE); + + if (newval) + m_pia->reset(); + else + m_display[1]->clear(); } -u8 ssystem3_state::pia_a_r() +void ssystem3_state::lcd2_pwm_w(offs_t offset, u8 data) { - return 0; + m_out_lcd2[offset & 0x3f][offset >> 6] = data; } -void ssystem3_state::pia_b_w(u8 data) +void ssystem3_state::lcd2_update() { + if (m_inputs[5]->read() & 2) + m_display[1]->matrix(1 << m_lcd2_select, m_lcd2_data); } -u8 ssystem3_state::pia_b_r() +template +void ssystem3_state::lcd2_output_w(offs_t offset, u32 data) { - return 0; + if (!offset) + data = 0; + + m_lcd2_data = u64(data) << 32 | m_lcd2_data >> 32; + + if (N == 1) + lcd2_update(); } -void ssystem3_state::pia_cb2_w(int state) +void ssystem3_state::cu_pia_a_w(u8 data) { + // PA0-PA2: CD4051 to LCD column + m_lcd2_select = data & 7; + lcd2_update(); +} + +u8 ssystem3_state::cu_pia_a_r() +{ + // PA7: serial data in + return ~m_control << 4 & 0x80; +} + +void ssystem3_state::cu_pia_b_w(u8 data) +{ + // PB3: LCD LOAD (both) + // PB4: LCD LCD (both) + CD4051 COM OUT/IN + // PB6: LCD CLOCK (both) + // PB7: LCD DATA IN (1st) + m_lcd2[0]->data_w(BIT(data, 7)); + + for (int i = 0; i < 2; i++) + m_lcd2[i]->clock_w(BIT(data, 6)); + + for (int i = 0; i < 2; i++) + m_lcd2[i]->load_w(BIT(~data, 3)); + + for (int i = 0; i < 2; i++) + m_lcd2[i]->lcd_w(BIT(data, 4)); +} + +u8 ssystem3_state::cu_pia_b_r() +{ + // PB5: look switch + return m_inputs[6]->read() << 5 & 0x20; } @@ -310,9 +377,9 @@ void ssystem3_state::ssystem4_map(address_map &map) void ssystem3_state::chessunit_map(address_map &map) { - map(0x3600, 0x367f).ram(); + map(0x3000, 0x307f).mirror(0x0f80).ram(); map(0x4000, 0x47ff).mirror(0xb800).rom(); - map(0xa000, 0xa003).rw(m_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); + map(0x8000, 0x8003).mirror(0x3ffc).rw(m_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); } @@ -350,7 +417,7 @@ static INPUT_PORTS_START( ssystem4 ) PORT_CONFNAME( 0x01, 0x01, "Sound" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x01, DEF_STR( On ) ) - PORT_CONFNAME( 0x02, 0x02, "LCD Light" ) + PORT_CONFNAME( 0x02, 0x02, "LCD 1 Light" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x02, DEF_STR( On ) ) @@ -368,14 +435,22 @@ static INPUT_PORTS_START( ssystem3 ) PORT_MODIFY("IN.3") PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) PORT_NAME("Time") // spring-loaded + PORT_MODIFY("IN.4") // switches + PORT_CONFNAME( 0x04, 0x04, "LCD 2 Light" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x04, DEF_STR( On ) ) + PORT_MODIFY("IN.5") // accessories/diodes PORT_CONFNAME( 0x01, 0x01, "Memory Unit" ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x01, DEF_STR( On ) ) - PORT_CONFNAME( 0x02, 0x02, "Chess Unit" ) + PORT_CONFNAME( 0x02, 0x02, "Chess Unit" ) PORT_CHANGED_MEMBER(DEVICE_SELF, ssystem3_state, cu_plug, 0) PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x02, DEF_STR( On ) ) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_CUSTOM) + + PORT_START("IN.6") // chess unit + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_TOGGLE PORT_CODE(KEYCODE_O) PORT_NAME("Look") INPUT_PORTS_END @@ -397,16 +472,16 @@ void ssystem3_state::ssystem4(machine_config &config) m_via->readpb_handler().set(FUNC(ssystem3_state::control_r)); /* video hardware */ - MD4332B(config, m_lcd); - m_lcd->write_q().set(FUNC(ssystem3_state::lcd_q_w)); + MD4332B(config, m_lcd1); + m_lcd1->write_q().set(FUNC(ssystem3_state::lcd1_output_w)); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_SVG)); screen.set_refresh_hz(60); screen.set_size(1920/2, 729/2); screen.set_visarea_full(); - PWM_DISPLAY(config, m_display).set_size(5, 9); - m_display->set_bri_levels(0.25); + PWM_DISPLAY(config, m_display[0]).set_size(5, 9); + m_display[0]->set_bri_levels(0.25); config.set_default_layout(layout_saitek_ssystem4); @@ -423,22 +498,39 @@ void ssystem3_state::ssystem3(machine_config &config) /* basic machine hardware */ m_maincpu->set_addrmap(AS_PROGRAM, &ssystem3_state::ssystem3_map); - m6808_cpu_device &subcpu(M6808(config, "subcpu", 6000000)); // LC circuit - subcpu.set_addrmap(AS_PROGRAM, &ssystem3_state::chessunit_map); + M6808(config, m_subcpu, 6800000); // LC circuit, measured + m_subcpu->set_addrmap(AS_PROGRAM, &ssystem3_state::chessunit_map); config.set_perfect_quantum(m_maincpu); PIA6821(config, m_pia, 0); - m_pia->irqa_handler().set_inputline("subcpu", INPUT_LINE_NMI); - m_pia->writepa_handler().set(FUNC(ssystem3_state::pia_a_w)); - m_pia->readpa_handler().set(FUNC(ssystem3_state::pia_a_r)); - m_pia->writepb_handler().set(FUNC(ssystem3_state::pia_b_w)); - m_pia->readpb_handler().set(FUNC(ssystem3_state::pia_b_r)); - m_pia->cb2_handler().set(FUNC(ssystem3_state::pia_cb2_w)); + m_pia->irqa_handler().set_inputline(m_subcpu, INPUT_LINE_NMI); + m_pia->writepa_handler().set(FUNC(ssystem3_state::cu_pia_a_w)); + m_pia->readpa_handler().set(FUNC(ssystem3_state::cu_pia_a_r)); + m_pia->writepb_handler().set(FUNC(ssystem3_state::cu_pia_b_w)); + m_pia->readpb_handler().set(FUNC(ssystem3_state::cu_pia_b_r)); + m_pia->cb2_handler().set(m_pia, FUNC(pia6821_device::ca2_w)); NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); - m_display->set_segmask(0xf, 0x7f); // 7segs are at expected positions + /* video hardware */ + HLCD0438(config, m_lcd2[0], 0); + m_lcd2[0]->write_segs().set(FUNC(ssystem3_state::lcd2_output_w<0>)); + m_lcd2[0]->write_data().set(m_lcd2[1], FUNC(hlcd0438_device::data_w)); + + HLCD0438(config, m_lcd2[1], 0); + m_lcd2[1]->write_segs().set(FUNC(ssystem3_state::lcd2_output_w<1>)); + + screen_device &screen(SCREEN(config, "chessunit", SCREEN_TYPE_SVG)); + screen.set_refresh_hz(60); + screen.set_size(1060, 1080); + screen.set_visarea_full(); + + PWM_DISPLAY(config, m_display[1]).set_size(8, 48); + m_display[1]->set_refresh(attotime::from_hz(30)); + m_display[1]->output_x().set(FUNC(ssystem3_state::lcd2_pwm_w)); + + m_display[0]->set_segmask(0xf, 0x7f); // 7segs are at expected positions config.set_default_layout(layout_saitek_ssystem3); } @@ -464,6 +556,9 @@ ROM_START( ssystem3 ) ROM_REGION(53552, "screen", 0) ROM_LOAD("ssystem3.svg", 0, 53552, CRC(6047f88f) SHA1(2ff9cfce01cd3811a3f46f84b47fdc4ea2cf2ba8) ) + + ROM_REGION(748939, "chessunit", 0) + ROM_LOAD("chessunit.svg", 0, 748939, CRC(713a46fd) SHA1(6119162fb7c00f81aeca0dfe274475dc8575dd70) ) ROM_END ROM_START( ssystem4 ) diff --git a/src/mame/drivers/tamag1.cpp b/src/mame/drivers/tamag1.cpp index 84dc32cc379..649a6ca54cc 100644 --- a/src/mame/drivers/tamag1.cpp +++ b/src/mame/drivers/tamag1.cpp @@ -1,5 +1,6 @@ // license:BSD-3-Clause // copyright-holders:hap +// thanks-to:digshadow, segher /*************************************************************************** Bandai Tamagotchi generation 1 hardware