From 3fb7a4616c60219f5980006466508219ad57c84e Mon Sep 17 00:00:00 2001 From: Christian Brunschen <6741909+cbrunschen@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:58:50 +0100 Subject: [PATCH 1/4] Add internal layout panels for the VFX family of keyboards (vfx, vfxsd, sd1 and sd132). --- src/mame/ensoniq/esqpanel.cpp | 211 +++++- src/mame/ensoniq/esqpanel.h | 40 +- src/mame/ensoniq/esqvfd.cpp | 240 ++++++- src/mame/ensoniq/esqvfd.h | 25 +- src/mame/layout/esq1by22.lay | 9 + src/mame/layout/sd1.lay | 1197 +++++++++++++++++++++++++++++++++ src/mame/layout/vfx.lay | 1064 +++++++++++++++++++++++++++++ src/mame/layout/vfxsd.lay | 1197 +++++++++++++++++++++++++++++++++ 8 files changed, 3940 insertions(+), 43 deletions(-) create mode 100644 src/mame/layout/sd1.lay create mode 100644 src/mame/layout/vfx.lay create mode 100644 src/mame/layout/vfxsd.lay diff --git a/src/mame/ensoniq/esqpanel.cpp b/src/mame/ensoniq/esqpanel.cpp index 1343ab289d1aa..cb6cacab748f5 100644 --- a/src/mame/ensoniq/esqpanel.cpp +++ b/src/mame/ensoniq/esqpanel.cpp @@ -5,10 +5,26 @@ */ #include "emu.h" #include "esqpanel.h" - #include "http.h" +#include "ioport.h" #include "main.h" +#include "vfx.lh" +#include "vfxsd.lh" +#include "sd1.lh" + +#include + + +#define VERBOSE 0 +#include "logmacro.h" + +template inline static void logerror(Format &&fmt, Params &&... args) { + util::stream_format(std::cerr, + "%s", + util::string_format(std::forward(fmt), std::forward(args)...)); +} + //************************************************************************** // External panel support //************************************************************************** @@ -413,7 +429,7 @@ DEFINE_DEVICE_TYPE(ESQPANEL2X16_SQ1, esqpanel2x16_sq1_device, "esqpanel216_sq1", esqpanel_device::esqpanel_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_serial_interface(mconfig, *this), - m_light_states(0x3f), // maximum number of lights + m_light_states(0x40), // maximum number of lights m_write_tx(*this), m_write_analog(*this) { @@ -450,6 +466,8 @@ void esqpanel_device::device_start() void esqpanel_device::device_reset() { + device_t::device_reset(); + // panel comms is at 62500 baud (double the MIDI rate), 8N2 set_data_frame(1, 8, PARITY_NONE, STOP_BITS_2); set_rcv_rate(62500); @@ -457,8 +475,8 @@ void esqpanel_device::device_reset() m_tx_busy = false; m_xmit_read = m_xmit_write = 0; - m_bCalibSecondByte = false; - m_bButtonLightSecondByte = false; + m_expect_calibration_second_byte = false; + m_expect_light_second_byte = false; attotime sample_time(0, ATTOSECONDS_PER_MILLISECOND); attotime initial_delay(0, ATTOSECONDS_PER_MILLISECOND); @@ -486,22 +504,22 @@ void esqpanel_device::rcv_complete() // Rx completed receiving byte receive_register_extract(); uint8_t data = get_received_char(); -// if (data >= 0xe0) printf("Got %02x from motherboard (second %s)\n", data, m_bCalibSecondByte ? "yes" : "no"); +// if (data >= 0xe0) LOG("Got %02x from motherboard (second %s)\n", data, m_expect_calibration_second_byte ? "yes" : "no"); send_to_display(data); m_external_panel_server->send_to_all(data); - if (m_bCalibSecondByte) + if (m_expect_calibration_second_byte) { -// printf("second byte is %02x\n", data); +// LOG("second byte is %02x\n", data); if (data == 0xfd) // calibration request { -// printf("let's send reply!\n"); +// LOG("let's send reply!\n"); xmit_char(0xff); // this is the correct response for "calibration OK" } - m_bCalibSecondByte = false; + m_expect_calibration_second_byte = false; } - else if (m_bButtonLightSecondByte) + else if (m_expect_light_second_byte) { // Lights on the Buttons, on the VFX-SD: // Number Button @@ -521,25 +539,22 @@ void esqpanel_device::rcv_complete() // Rx completed receiving byte // d Sounds // e 0 // f Cart - int lightNumber = data & 0x3f; + int light_number = data & 0x3f; // Light states: // 0 = Off // 2 = On // 3 = Blinking - m_light_states[lightNumber] = (data & 0xc0) >> 6; - - // TODO: do something with the button information! - // printf("Setting light %d to %s\n", lightNumber, lightState == 3 ? "Blink" : lightState == 2 ? "On" : "Off"); - m_bButtonLightSecondByte = false; + m_light_states[light_number] = (data & 0xc0) >> 6; + m_expect_light_second_byte = false; } else if (data == 0xfb) // request calibration { - m_bCalibSecondByte = true; + m_expect_calibration_second_byte = true; } else if (data == 0xff) // button light state command { - m_bButtonLightSecondByte = true; + m_expect_light_second_byte = true; } else { @@ -565,7 +580,7 @@ void esqpanel_device::rcv_complete() // Rx completed receiving byte void esqpanel_device::tra_complete() // Tx completed sending byte { -// printf("panel Tx complete\n"); +// LOG("panel Tx complete\n"); // is there more waiting to send? if (m_xmit_read != m_xmit_write) { @@ -588,7 +603,7 @@ void esqpanel_device::tra_callback() // Tx send bit void esqpanel_device::xmit_char(uint8_t data) { -// printf("Panel: xmit %02x\n", data); +// LOG("Panel: xmit %02x\n", data); // if tx is busy it'll pick this up automatically when it completes if (!m_tx_busy) @@ -645,6 +660,30 @@ void esqpanel_device::set_analog_value(offs_t offset, uint16_t value) m_write_analog(offset, value); } +void esqpanel_device::set_button(uint8_t button, bool pressed) +{ + // LOG("set_button(%d, %d)\r\n", button, pressed); + bool current = m_pressed_buttons.find(button) != m_pressed_buttons.end(); + if (pressed == current) + { + // LOG("- button %d already %d, skipping\r\n", button, pressed); + return; + } + + uint8_t sendme = (pressed ? 0x80 : 0) | (button & 0xff); + // LOG("button %d %s : sending char to mainboard: %02x\n", button, pressed ? "down" : "up", sendme); + xmit_char(sendme); + xmit_char(0x00); + if (pressed) + { + m_pressed_buttons.insert(button); + } + else + { + m_pressed_buttons.erase(button); + } +} + /* panel with 1x22 VFD display used in the EPS-16 and EPS-16 Plus */ void esqpanel1x22_device::device_add_mconfig(machine_config &config) @@ -679,14 +718,29 @@ esqpanel2x40_device::esqpanel2x40_device(const machine_config &mconfig, const ch void esqpanel2x40_vfx_device::device_add_mconfig(machine_config &config) { - ESQ2X40(config, m_vfd, 60); + ESQ2X40_VFX(config, m_vfd, 60); + + const std::string &name = owner()->shortname(); + if (name == "vfx") + config.set_default_layout(layout_vfx); + else if (name == "vfxsd") + config.set_default_layout(layout_vfxsd); + else // "sd1" or "sd132" + config.set_default_layout(layout_sd1); } esqpanel2x40_vfx_device::esqpanel2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : esqpanel_device(mconfig, ESQPANEL2X40_VFX, tag, owner, clock), - m_vfd(*this, "vfd") + m_vfd(*this, "vfd"), + m_lights(*this, "lights"), + m_buttons_0(*this, "buttons_0"), + m_buttons_32(*this, "buttons_32"), + m_analog_data_entry(*this, "analog_data_entry"), + m_analog_volume(*this, "analog_volume") { m_eps_mode = false; + // The VFX family have 16 lights on the panel. + m_light_states.resize(16); } bool esqpanel2x40_vfx_device::write_contents(std::ostream &o) @@ -694,13 +748,122 @@ bool esqpanel2x40_vfx_device::write_contents(std::ostream &o) m_vfd->write_contents(o); for (int i = 0; i < m_light_states.size(); i++) { - o.put(char(0xff)); - o.put((m_light_states[i] << 6) | i); + o.put((char)(0xff)); + o.put((char)(m_light_states[i] << 6) | i); } return true; } +void esqpanel2x40_vfx_device::update_lights() { + // set the lights according to their status and bllink phase. + int32_t lights = 0; + int32_t bit = 1; + for (int i = 0; i < 16; i++) + { + if (m_light_states[i] == 2 || (m_light_states[i] == 3 && ((m_blink_phase & 1) == 0))) + { + lights |= bit; + } + bit <<= 1; + } + m_lights = lights; +} + +TIMER_CALLBACK_MEMBER(esqpanel2x40_vfx_device::update_blink) { + m_blink_phase = (m_blink_phase + 1) & 3; + m_vfd->set_blink_on(m_blink_phase & 2); + update_lights(); +} + +void esqpanel2x40_vfx_device::device_start() +{ + esqpanel_device::device_start(); + + m_lights.resolve(); + m_blink_timer = timer_alloc(FUNC(esqpanel2x40_vfx_device::update_blink), this); + m_blink_timer->enable(false); +} + +void esqpanel2x40_vfx_device::device_reset() +{ + esqpanel_device::device_reset(); + + if (m_blink_timer) { + attotime sample_time(0, 250 * ATTOSECONDS_PER_MILLISECOND); + attotime initial_delay(0, 250 * ATTOSECONDS_PER_MILLISECOND); + + m_blink_timer->adjust(initial_delay, 0, sample_time); + m_blink_timer->enable(true); + } +} + +static INPUT_PORTS_START(esqpanel2x40_vfx_device) + PORT_START("buttons_0") + for (int i = 0; i < 32; i++) + { + PORT_BIT((1 << i), IP_ACTIVE_HIGH, IPT_KEYBOARD); + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(esqpanel2x40_vfx_device::button_change), i) + } + + PORT_START("buttons_32") + for (int i = 0; i < 32; i++) + { + PORT_BIT((1 << i), IP_ACTIVE_HIGH, IPT_KEYBOARD); + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(esqpanel2x40_vfx_device::button_change), 32 + i) + } + + PORT_START("analog_data_entry") + // An adjuster, but with range 0 .. 1023, to match the 10 bit resolution of the OTIS ADC + configurer.field_alloc(IPT_ADJUSTER, 0x200, 0x3ff, "Data Entry"); + configurer.field_set_min_max(0, 0x3ff); + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(esqpanel2x40_vfx_device::analog_value_change), 3) + + PORT_START("analog_volume") + // An adjuster, but with range 0 .. 1023, to match the 10 bit resolution of the OTIS ADC + configurer.field_alloc(IPT_ADJUSTER, 0x3ff, 0x3ff, "Volume"); + configurer.field_set_min_max(0, 0x3ff); + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(esqpanel2x40_vfx_device::analog_value_change), 5) + +INPUT_PORTS_END + +ioport_constructor esqpanel2x40_vfx_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(esqpanel2x40_vfx_device); +} + +// A button is pressed on the internal panel +INPUT_CHANGED_MEMBER(esqpanel2x40_vfx_device::button_change) +{ + // Update the internal state + esqpanel_device::set_button(param, newval != 0); +} + +// An anlog value was changed on the internal panel +INPUT_CHANGED_MEMBER(esqpanel2x40_vfx_device::analog_value_change) +{ + int channel = param; + int clamped = std::clamp((int)newval, 0, 1023); + int value = clamped << 6; + esqpanel_device::set_analog_value(channel, value); +} + +ioport_value esqpanel2x40_vfx_device::get_adjuster_value(required_ioport &ioport) +{ + auto field = ioport->fields().first(); + ioport_field::user_settings user_settings; + field->get_user_settings(user_settings); + return user_settings.value; +} + +void esqpanel2x40_vfx_device::set_adjuster_value(required_ioport &ioport, const ioport_value & value) +{ + auto field = ioport->fields().first(); + ioport_field::user_settings user_settings; + field->get_user_settings(user_settings); + user_settings.value = value; + field->set_user_settings(user_settings); +} // --- SQ1 - Parduz -------------------------------------------------------------------------------------------------------------------------- void esqpanel2x16_sq1_device::device_add_mconfig(machine_config &config) diff --git a/src/mame/ensoniq/esqpanel.h b/src/mame/ensoniq/esqpanel.h index 468865739bafb..c5858b3d98d6b 100644 --- a/src/mame/ensoniq/esqpanel.h +++ b/src/mame/ensoniq/esqpanel.h @@ -10,6 +10,8 @@ #include "diserial.h" +#include +#include #include @@ -30,7 +32,8 @@ class esqpanel_device : public device_t, public device_serial_interface auto write_analog() { return m_write_analog.bind(); } void xmit_char(uint8_t data); - void set_analog_value(offs_t offset, uint16_t value); + virtual void set_analog_value(offs_t offset, uint16_t value); + virtual void set_button(uint8_t button, bool pressed); protected: // construction/destruction @@ -48,6 +51,7 @@ class esqpanel_device : public device_t, public device_serial_interface virtual void send_to_display(uint8_t data) = 0; + std::set m_pressed_buttons; TIMER_CALLBACK_MEMBER(check_external_panel_server); virtual const std::string get_front_panel_html_file() const { return ""; } @@ -63,8 +67,8 @@ class esqpanel_device : public device_t, public device_serial_interface private: static const int XMIT_RING_SIZE = 16; - bool m_bCalibSecondByte = false; - bool m_bButtonLightSecondByte = false; + bool m_expect_calibration_second_byte = false; + bool m_expect_light_second_byte = false; devcb_write_line m_write_tx; devcb_write16 m_write_analog; @@ -103,16 +107,42 @@ class esqpanel2x40_vfx_device : public esqpanel_device { public: esqpanel2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + DECLARE_INPUT_CHANGED_MEMBER(button_change); + DECLARE_INPUT_CHANGED_MEMBER(analog_value_change); + protected: virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; - + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override; virtual void send_to_display(uint8_t data) override { m_vfd->write_char(data); } virtual const std::string get_front_panel_html_file() const override { return "/esqpanel/vfx/FrontPanel.html"; } virtual const std::string get_front_panel_js_file() const override { return "/esqpanel/vfx/FrontPanel.js"; } virtual bool write_contents(std::ostream &o) override; - required_device m_vfd; + static constexpr uint8_t AT_NORMAL = 0x00; + static constexpr uint8_t AT_UNDERLINE = 0x01; + static constexpr uint8_t AT_BLINK = 0x02; + +private: + emu_timer *m_blink_timer = nullptr; + uint8_t m_blink_phase; + + required_device m_vfd; + + output_finder<> m_lights; + + required_ioport m_buttons_0; + required_ioport m_buttons_32; + required_ioport m_analog_data_entry; + required_ioport m_analog_volume; + + TIMER_CALLBACK_MEMBER(update_blink); + void update_lights(); + + ioport_value get_adjuster_value(required_ioport &ioport); + void set_adjuster_value(required_ioport &ioport, const ioport_value & value); }; class esqpanel2x40_sq1_device : public esqpanel_device { diff --git a/src/mame/ensoniq/esqvfd.cpp b/src/mame/ensoniq/esqvfd.cpp index f8aa3435f56b0..136b41af90ab6 100644 --- a/src/mame/ensoniq/esqvfd.cpp +++ b/src/mame/ensoniq/esqvfd.cpp @@ -14,6 +14,7 @@ DEFINE_DEVICE_TYPE(ESQ1X22, esq1x22_device, "esq1x22", "Ensoniq 1x22 VFD") DEFINE_DEVICE_TYPE(ESQ2X40, esq2x40_device, "esq2x40", "Ensoniq 2x40 VFD") DEFINE_DEVICE_TYPE(ESQ2X40_SQ1, esq2x40_sq1_device, "esq2x40_sq1", "Ensoniq 2x40 VFD (SQ-1 variant)") +DEFINE_DEVICE_TYPE(ESQ2X40_VFX, esq2x40_vfx_device, "esq2x40_vfx", "Ensoniq 2x40 VFD (VFX Family variant)") // adapted from bfm_bd1, rearranged to work with ASCII data used by the Ensoniq h/w static const uint16_t font[]= @@ -116,6 +117,110 @@ static const uint16_t font[]= 0x0000, // 0000 0000 0000 0000 (DEL) }; +/** + * Character data as used in the VFX family. Bit 0..13 are ordered to match + * led14seg. Bit 14 activates the dot after a character; bit 15 the underline. + * See layout/{vfx|vfxsd|sd1}.lay . + */ +static const uint16_t font_vfx[] = { + 0x0000, // 0000 0000 0000 0000 SPACE + 0x543f, // 0101 0100 0011 1111 '0.' + 0x0120, // 0000 0001 0010 0000 '"' + 0x4300, // 0100 0011 0000 0000 '1.' + 0x03ed, // 0000 0011 1110 1101 '$' + 0x40db, // 0100 0000 1101 1011 '2.' + 0x0000, // 0000 0000 0000 0000 '&' + 0x0800, // 0000 1000 0000 0000 ''' + 0x40cf, // 0100 0000 1100 1111 '3.' + 0x40e6, // 0100 0000 1110 0110 '4.' + 0x3fc0, // 0011 1111 1100 0000 '*' + 0x03c0, // 0000 0011 1100 0000 '+' + 0x0000, // 0000 0000 0000 0000 ',' + 0x00c0, // 0000 0000 1100 0000 '-' + 0x4000, // 0100 0000 0000 0000 '.' + 0x1400, // 0001 0100 0000 0000 '/' + 0x143f, // 0001 0100 0011 1111 '0' + 0x0300, // 0000 0011 0000 0000 '1' + 0x00db, // 0000 0000 1101 1011 '2' + 0x00cf, // 0000 0000 1100 1111 '3' + 0x00e6, // 0000 0000 1110 0110 '4' + 0x00ed, // 0000 0000 1110 1101 '5' + 0x00fd, // 0000 0000 1111 1101 '6' + 0x0007, // 0000 0000 0000 0111 '7' + 0x00ff, // 0000 0000 1111 1111 '8' + 0x00ef, // 0000 0000 1110 1111 '9' + 0x0000, // 0000 0000 0000 0000 ':' + 0x40fd, // 0100 0000 1111 1101 '6.' + 0x3000, // 0011 0000 0000 0000 '(' + 0x00c8, // 0000 0000 1100 1000 '=' + 0x0c00, // 0000 1100 0000 0000 ')' + 0x0000, // 0000 0000 0000 0000 '?' + 0x025f, // 0000 0010 0101 1111 '@' + 0x00f7, // 0000 0000 1111 0111 'A' + 0x038f, // 0000 0011 1000 1111 'B' + 0x0039, // 0000 0000 0011 1001 'C' + 0x030f, // 0000 0011 0000 1111 'D' + 0x00f9, // 0000 0000 1111 1001 'E' + 0x00f1, // 0000 0000 1111 0001 'F' + 0x00bd, // 0000 0000 1011 1101 'G' + 0x00f6, // 0000 0000 1111 0110 'H' + 0x0309, // 0000 0011 0000 1001 'I' + 0x001e, // 0000 0000 0001 1110 'J' + 0x3070, // 0011 0000 0111 0000 'K' + 0x0038, // 0000 0000 0011 1000 'L' + 0x1836, // 0001 1000 0011 0110 'M' + 0x2836, // 0010 1000 0011 0110 'N' + 0x003f, // 0000 0000 0011 1111 'O' + 0x00f3, // 0000 0000 1111 0011 'P' + 0x203f, // 0010 0000 0011 1111 'Q' + 0x20f3, // 0010 0000 1111 0011 'R' + 0x00ed, // 0000 0000 1110 1101 'S' + 0x0301, // 0000 0011 0000 0001 'T' + 0x003e, // 0000 0000 0011 1110 'U' + 0x1430, // 0001 0100 0011 0000 'V' + 0x2436, // 0010 0100 0011 0110 'W' + 0x3c00, // 0011 1100 0000 0000 'X' + 0x1a00, // 0001 1010 0000 0000 'Y' + 0x1409, // 0001 0100 0000 1001 'Z' + 0x0039, // 0000 0000 0011 1001 '[' + 0x40ff, // 0100 0000 1111 1111 '8.' + 0x000f, // 0000 0000 0000 1111 ']' + 0x2400, // 0010 0100 0000 0000 '^' + 0x0008, // 0000 0000 0000 1000 '_' + 0x0800, // 0000 1000 0000 0000 '`' + 0x00f7, // 0000 0000 1111 0111 'a' + 0x038f, // 0000 0011 1000 1111 'b' + 0x0039, // 0000 0000 0011 1001 'c' + 0x030f, // 0000 0011 0000 1111 'd' + 0x00f9, // 0000 0000 1111 1001 'e' + 0x00f1, // 0000 0000 1111 0001 'f' + 0x00bd, // 0000 0000 1011 1101 'g' + 0x00f6, // 0000 0000 1111 0110 'h' + 0x0309, // 0000 0011 0000 1001 'i' + 0x001e, // 0000 0000 0001 1110 'j' + 0x3070, // 0011 0000 0111 0000 'k' + 0x0038, // 0000 0000 0011 1000 'l' + 0x1836, // 0001 1000 0011 0110 'm' + 0x2836, // 0010 1000 0011 0110 'n' + 0x003f, // 0000 0000 0011 1111 'o' + 0x00f3, // 0000 0000 1111 0011 'p' + 0x203f, // 0010 0000 0011 1111 'q' + 0x20f3, // 0010 0000 1111 0011 'r' + 0x00ed, // 0000 0000 1110 1101 's' + 0x0301, // 0000 0011 0000 0001 't' + 0x003e, // 0000 0000 0011 1110 'u' + 0x1430, // 0001 0100 0011 0000 'v' + 0x2436, // 0010 0100 0011 0110 'w' + 0x3c00, // 0011 1100 0000 0000 'x' + 0x1a00, // 0001 1010 0000 0000 'y' + 0x1409, // 0001 0100 0000 1001 'z' + 0x0039, // 0000 0000 0011 1001 '{' + 0x0300, // 0000 0011 0000 0000 '|' + 0x000f, // 0000 0000 0000 1111 '}' + 0x2400, // 0010 0100 0000 0000 '~' + 0x0000, // 0000 0000 0000 0000 DEL +}; + esqvfd_device::esqvfd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dimensions_param &&dimensions) : device_t(mconfig, type, tag, owner, clock), m_vfds(std::move(std::get<0>(dimensions))), @@ -163,6 +268,53 @@ void esqvfd_device::update_display() } } +inline void esqvfd_device::cursor_left() +{ + m_cursx--; + if (m_cursx < 0) + { + m_cursx += m_cols; + m_cursy--; + if (m_cursy < 0) + m_cursy += m_rows; + } +} + +inline void esqvfd_device::cursor_right() +{ + m_cursx++; + if (m_cursx >= m_cols) + { + m_cursx -= m_cols; + m_cursy++; + if (m_cursy >= m_rows) + m_cursy -= m_rows; + } +} + +void esqvfd_device::set_blink_on(bool blink_on) { + m_blink_on = blink_on; + + for (int row = 0; row < m_rows; row++) + { + for (int col = 0; col < m_cols; col++) + { + m_dirty[row][col] |= m_attrs[row][col] & AT_BLINK; + } + } + update_display(); +} + +void esqvfd_device::clear() { + m_cursx = m_cursy = m_curattr = 0; + memset(m_chars, 0, sizeof(m_chars)); + memset(m_attrs, 0, sizeof(m_attrs)); + memset(m_dirty, 1, sizeof(m_dirty)); + + update_display(); +} + + /* 2x40 VFD display used in the ESQ-1, VFX-SD, SD-1, and others */ void esq2x40_device::device_add_mconfig(machine_config &config) @@ -220,11 +372,16 @@ void esq2x40_device::write_char(uint8_t data) m_curattr |= AT_UNDERLINE; break; + case 0xd4: // move curser one step right + cursor_right(); + break; + + case 0xd5: // move curser one step left + cursor_left(); + break; + case 0xd6: // clear screen - m_cursx = m_cursy = 0; - memset(m_chars, 0, sizeof(m_chars)); - memset(m_attrs, 0, sizeof(m_attrs)); - memset(m_dirty, 1, sizeof(m_dirty)); + clear(); break; case 0xf5: // save cursor position @@ -238,6 +395,10 @@ void esq2x40_device::write_char(uint8_t data) m_curattr = m_attrs[m_cursy][m_cursx]; break; + case 0xfd: // also clear screen? + clear(); + break; + default: // printf("Unknown control code %02x\n", data); break; @@ -250,12 +411,8 @@ void esq2x40_device::write_char(uint8_t data) m_chars[m_cursy][m_cursx] = data - ' '; m_attrs[m_cursy][m_cursx] = m_curattr; m_dirty[m_cursy][m_cursx] = 1; - m_cursx++; - if (m_cursx >= 39) - { - m_cursx = 39; - } + cursor_right(); } } @@ -293,15 +450,78 @@ bool esq2x40_device::write_contents(std::ostream &o) o.put((char) (m_chars[row][col] + ' ')); } } + + // move the cursor to the saved position + o.put((char) 0x80 | (m_cols * m_savedy + m_savedx)); + // and save the position + o.put((char) 0xf5); + + // move the cursor to the current cursor position + o.put((char) 0x80 | (m_cols * m_cursy + m_cursx)); + return true; } +esq2x40_device::esq2x40_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + esqvfd_device(mconfig, type, tag, owner, clock, make_dimensions<2, 40>(*this)) +{ +} esq2x40_device::esq2x40_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - esqvfd_device(mconfig, ESQ2X40, tag, owner, clock, make_dimensions<2, 40>(*this)) + esq2x40_device(mconfig, ESQ2X40, tag, owner, clock) { } +esq2x40_vfx_device::esq2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + esq2x40_device(mconfig, ESQ2X40_VFX, tag, owner, clock) +{ +} +void esq2x40_vfx_device::device_add_mconfig(machine_config &config) +{ + // Do not set a default layout. This display must be used + // within a layout that includes the VFD elements, such as + // vfx.lay, vfxsd.lay or sd1.lay. +} + +// Handles blinking of underline and of entire character, +void esq2x40_vfx_device::update_display() +{ + for (int row = 0; row < m_rows; row++) + { + for (int col = 0; col < m_cols; col++) + { + if (m_dirty[row][col]) + { + uint8_t c = m_chars[row][col]; + + uint32_t char_segments = font_vfx[c < 96 ? c : 0]; + auto attr = m_attrs[row][col]; + uint32_t segments; + + if ((attr & AT_BLINK) && !m_blink_on) // something is blinked off + { + if (attr & AT_UNDERLINE) // blink the underline off + segments = char_segments; + else // there is no underline, blink the entire character + segments = 0; + } + else + { + if (attr & AT_UNDERLINE) + segments = char_segments | 0x8000; + else + segments = char_segments; + } + + m_vfds->set((row * m_cols) + col, segments); + + m_dirty[row][col] = 0; + } + } + } +} + + /* 1x22 display from the VFX (not right, but it'll do for now) */ void esq1x22_device::device_add_mconfig(machine_config &config) diff --git a/src/mame/ensoniq/esqvfd.h b/src/mame/ensoniq/esqvfd.h index bbbe2ea7cc7c7..45fda97f00ff8 100644 --- a/src/mame/ensoniq/esqvfd.h +++ b/src/mame/ensoniq/esqvfd.h @@ -14,6 +14,10 @@ class esqvfd_device : public device_t { virtual void write_char(uint8_t data) = 0; virtual void update_display(); virtual bool write_contents(std::ostream &o) { return false; } + virtual void clear(); + virtual void cursor_left(); + virtual void cursor_right(); + virtual void set_blink_on(bool blink_on); // why isn't the font just stored in this order? static uint32_t conv_segments(uint16_t segin) { return bitswap<15>(segin, 12, 11, 7, 6, 4, 10, 3, 14, 15, 0, 13, 9, 5, 1, 2); } @@ -41,15 +45,14 @@ class esqvfd_device : public device_t { esqvfd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dimensions_param &&dimensions); static constexpr uint8_t AT_NORMAL = 0x00; - static constexpr uint8_t AT_BOLD = 0x01; - static constexpr uint8_t AT_UNDERLINE = 0x02; - static constexpr uint8_t AT_BLINK = 0x04; - static constexpr uint8_t AT_BLINKED = 0x80; // set when character should be blinked off + static constexpr uint8_t AT_UNDERLINE = 0x01; + static constexpr uint8_t AT_BLINK = 0x02; virtual void device_start() override ATTR_COLD; virtual void device_reset() override ATTR_COLD; output_helper::ptr m_vfds; + bool m_blink_on = false; int m_cursx = 0, m_cursy = 0; int m_savedx = 0, m_savedy = 0; int const m_rows = 0, m_cols = 0; @@ -74,6 +77,7 @@ class esq1x22_device : public esqvfd_device { class esq2x40_device : public esqvfd_device { public: + esq2x40_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); esq2x40_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual void write_char(uint8_t data) override; @@ -83,6 +87,18 @@ class esq2x40_device : public esqvfd_device { virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; }; +class esq2x40_vfx_device : public esq2x40_device { +public: + esq2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + virtual void update_display() override; + + template static dimensions_param make_dimensions(device_t &device) { return dimensions_param(std::make_unique >(device), R, C); } + +protected: + // device-level overrides + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + class esq2x40_sq1_device : public esqvfd_device { public: esq2x40_sq1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); @@ -99,5 +115,6 @@ class esq2x40_sq1_device : public esqvfd_device { DECLARE_DEVICE_TYPE(ESQ1X22, esq1x22_device) DECLARE_DEVICE_TYPE(ESQ2X40, esq2x40_device) DECLARE_DEVICE_TYPE(ESQ2X40_SQ1, esq2x40_sq1_device) +DECLARE_DEVICE_TYPE(ESQ2X40_VFX, esq2x40_vfx_device) #endif // MAME_ENSONIQ_ESQVFD_H diff --git a/src/mame/layout/esq1by22.lay b/src/mame/layout/esq1by22.lay index 3e36216065a8d..74e217b523554 100644 --- a/src/mame/layout/esq1by22.lay +++ b/src/mame/layout/esq1by22.lay @@ -12,15 +12,24 @@ license:CC0-1.0 + + + + + + + + + diff --git a/src/mame/layout/sd1.lay b/src/mame/layout/sd1.lay new file mode 100644 index 0000000000000..6fbc20c941da1 --- /dev/null +++ b/src/mame/layout/sd1.lay @@ -0,0 +1,1197 @@ + + + + + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/vfx.lay b/src/mame/layout/vfx.lay new file mode 100644 index 0000000000000..689896aa14e25 --- /dev/null +++ b/src/mame/layout/vfx.lay @@ -0,0 +1,1064 @@ + + + + + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/vfxsd.lay b/src/mame/layout/vfxsd.lay new file mode 100644 index 0000000000000..551cc388eba4e --- /dev/null +++ b/src/mame/layout/vfxsd.lay @@ -0,0 +1,1197 @@ + + + + + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + ]]> + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From e21a901cea0c68ae1908d61852c760f5a74682cd Mon Sep 17 00:00:00 2001 From: Christian Brunschen <6741909+cbrunschen@users.noreply.github.com> Date: Sun, 19 Oct 2025 13:35:08 +0100 Subject: [PATCH 2/4] Address some of the first round of comments. esqpenal.{h,cpp}: Remove errant logerror function. Pass the panel type into the esqpanel2x40_vfx_device constructor, and use that to specify the layout to use. esq5505.cpp: in the various keyboard configuration methods in the VFX family, pass the correct panel type. Also move the cartridge and panel from common() to vfx(), since the eps family for example use common() but have no cartridge, and a different panel which they were replacing. Also add a fallback layout with just the VFD, for those devices that are currently using the esqpanel2x40_vfx_device panel even though they're not actually in the VFX family. --- src/mame/ensoniq/esq5505.cpp | 82 ++++++++++++++++++-------------- src/mame/ensoniq/esqpanel.cpp | 21 ++++---- src/mame/ensoniq/esqpanel.h | 14 +++++- src/mame/layout/esq2by40_vfx.lay | 64 +++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 48 deletions(-) create mode 100644 src/mame/layout/esq2by40_vfx.lay diff --git a/src/mame/ensoniq/esq5505.cpp b/src/mame/ensoniq/esq5505.cpp index 72c58ad7d54f5..4fa94ff78bbc6 100644 --- a/src/mame/ensoniq/esq5505.cpp +++ b/src/mame/ensoniq/esq5505.cpp @@ -189,10 +189,12 @@ namespace { -#define GENERIC (0) -#define EPS (1) -#define SQ1 (2) -#define VFX (3) +enum esq5505_system_type : int { + GENERIC = 0, + EPS, + SQ1, + VFX +}; #define KEYBOARD_HACK (1) // turn on to play the SQ-1, SD-1, and SD-1 32-voice: Z and X are program up/down, A/S/D/F/G/H/J/K/L and Q/W/E/R/T/Y/U play notes @@ -233,12 +235,13 @@ class esq5505_state : public driver_device { } void common(machine_config &config); - void vfx(machine_config &config); - void sq1(machine_config &config); - void vfxsd(machine_config &config); - void sd132(machine_config &config); + void vfx(machine_config &config, int vfx_panel_type = esqpanel2x40_vfx_device::VFX); + void vfxsd(machine_config &config, int vfx_panel_type = esqpanel2x40_vfx_device::VFX_SD); + void sd1(machine_config &config, int vfx_panel_type = esqpanel2x40_vfx_device::SD_1); + void sd132(machine_config &config, int vfx_panel_type = esqpanel2x40_vfx_device::SD_1_32); void eps(machine_config &config); void common32(machine_config &config); + void sq1(machine_config &config); void ks32(machine_config &config); void init_eps(); @@ -785,15 +788,6 @@ void esq5505_state::common(machine_config &config) ES5510(config, m_esp, 10_MHz_XTAL); m_esp->set_disable(); - ENSONIQ_VFX_CARTRIDGE_SLOT(config, m_cartslot); - m_cartslot->option_add_internal("cart", ENSONIQ_VFX_CARTRIDGE); - m_cartslot->set_default_option("cart"); - m_cartslot->set_fixed(true); - - ESQPANEL2X40_VFX(config, m_panel); - m_panel->write_tx().set(m_duart, FUNC(mc68681_device::rx_b_w)); - m_panel->write_analog().set(FUNC(esq5505_state::analog_w)); - MC68681(config, m_duart, 4000000); m_duart->irq_cb().set_inputline(m_maincpu, M68K_IRQ_3); m_duart->a_tx_cb().set(m_mdout, FUNC(midi_port_device::write_txd)); @@ -831,9 +825,19 @@ void esq5505_state::common(machine_config &config) m_otis->add_route(7, "pump", 1.0, 7); } -void esq5505_state::vfx(machine_config &config) +void esq5505_state::vfx(machine_config &config, int panel_type) { common(config); + + ESQPANEL2X40_VFX(config, m_panel, panel_type); + m_panel->write_tx().set(m_duart, FUNC(mc68681_device::rx_b_w)); + m_panel->write_analog().set(FUNC(esq5505_state::analog_w)); + + ENSONIQ_VFX_CARTRIDGE_SLOT(config, m_cartslot); + m_cartslot->option_add_internal("cart", ENSONIQ_VFX_CARTRIDGE); + m_cartslot->set_default_option("cart"); + m_cartslot->set_fixed(true); + NVRAM(config, m_osram_nvram, nvram_device::DEFAULT_NONE); } @@ -845,7 +849,7 @@ void esq5505_state::eps(machine_config &config) m_duart->set_clock(10_MHz_XTAL / 2); - ESQPANEL1X22(config.replace(), m_panel); + ESQPANEL1X22(config, m_panel); m_panel->write_tx().set(m_duart, FUNC(mc68681_device::rx_b_w)); m_panel->write_analog().set(FUNC(esq5505_state::analog_w)); @@ -861,10 +865,10 @@ void esq5505_state::eps(machine_config &config) m_dmac->dma_write<0>().set(m_fdc, FUNC(wd1772_device::data_w)); } -void esq5505_state::vfxsd(machine_config &config) +void esq5505_state::vfxsd(machine_config &config, int panel_type) { - // Like the VFX - vfx(config); + // Like the VFX, but passing through the panel type + vfx(config, panel_type); // but with an updated memory map that includes FDC and sequence RAM m_maincpu->set_addrmap(AS_PROGRAM, &esq5505_state::vfxsd_map); // and nvram for the sequencer RAM as well @@ -879,6 +883,25 @@ void esq5505_state::vfxsd(machine_config &config) FLOPPY_CONNECTOR(config, m_floppy_connector, esq5505_state::floppy_drives, "35dd", esq5505_state::floppy_formats, true).enable_sound(true); } +void esq5505_state::sd1(machine_config &config, int panel_type) +{ + // Like the VFX-SD but with its own panel type + vfxsd(config, panel_type); +} + +// Like the sd1, but with some clock speeds faster. +void esq5505_state::sd132(machine_config &config, int panel_type) +{ + auto clock = 30.47618_MHz_XTAL / 2; + + // Like the SD-1 but with its own panel type + sd1(config, panel_type); + + m_maincpu->set_clock(clock); + m_otis->set_clock(clock); + m_pump->set_clock(clock); +} + // 32-voice machines with the VFX-SD type config void esq5505_state::common32(machine_config &config) { @@ -942,23 +965,12 @@ void esq5505_state::common32(machine_config &config) FLOPPY_CONNECTOR(config, m_floppy_connector, esq5505_state::floppy_drives, "35dd", esq5505_state::floppy_formats, true).enable_sound(true); } -// Like the VFX-SD config, but with some clock speeds faster. -void esq5505_state::sd132(machine_config &config) -{ - auto clock = 30.47618_MHz_XTAL / 2; - - vfxsd(config); - m_maincpu->set_clock(clock); - m_otis->set_clock(clock); - m_pump->set_clock(clock); -} - void esq5505_state::sq1(machine_config &config) { common(config); m_maincpu->set_addrmap(AS_PROGRAM, &esq5505_state::sq1_map); - ESQPANEL2X16_SQ1(config.replace(), m_panel); + ESQPANEL2X16_SQ1(config, m_panel); m_panel->write_tx().set(m_duart, FUNC(mc68681_device::rx_b_w)); m_panel->write_analog().set(FUNC(esq5505_state::analog_w)); } @@ -1277,7 +1289,7 @@ CONS( 1988, eps, 0, 0, eps, vfx, esq5505_state, init_eps, "Ensoniq", " CONS( 1989, vfx, 0, 0, vfx, vfx, esq5505_state, init_denib, "Ensoniq", "VFX", MACHINE_NOT_WORKING ) // 2x40 VFD CONS( 1989, vfxsd, 0, 0, vfxsd, vfx, esq5505_state, init_denib, "Ensoniq", "VFX-SD", MACHINE_NOT_WORKING ) // 2x40 VFD CONS( 1990, eps16p, eps, 0, eps, vfx, esq5505_state, init_eps, "Ensoniq", "EPS-16 Plus", MACHINE_NOT_WORKING ) // custom VFD: one alphanumeric 22-char row, one graphics-capable row (alpha row can also do bar graphs) -CONS( 1990, sd1, 0, 0, vfxsd, vfx, esq5505_state, init_denib, "Ensoniq", "SD-1 (21 voice)", MACHINE_NOT_WORKING ) // 2x40 VFD +CONS( 1990, sd1, 0, 0, sd1, vfx, esq5505_state, init_denib, "Ensoniq", "SD-1 (21 voice)", MACHINE_NOT_WORKING ) // 2x40 VFD CONS( 1990, sq1, 0, 0, sq1, sq1, esq5505_state, init_sq1, "Ensoniq", "SQ-1", MACHINE_NOT_WORKING ) // 2x16 LCD CONS( 1990, sqrack, sq1, 0, sq1, sq1, esq5505_state, init_sq1, "Ensoniq", "SQ-Rack", MACHINE_NOT_WORKING ) // 2x16 LCD CONS( 1991, sq2, 0, 0, ks32, sq1, esq5505_state, init_sq1, "Ensoniq", "SQ-2", MACHINE_NOT_WORKING ) // 2x16 LCD diff --git a/src/mame/ensoniq/esqpanel.cpp b/src/mame/ensoniq/esqpanel.cpp index cb6cacab748f5..a95b9234da537 100644 --- a/src/mame/ensoniq/esqpanel.cpp +++ b/src/mame/ensoniq/esqpanel.cpp @@ -9,6 +9,7 @@ #include "ioport.h" #include "main.h" +#include "esq2by40_vfx.lh" #include "vfx.lh" #include "vfxsd.lh" #include "sd1.lh" @@ -19,12 +20,6 @@ #define VERBOSE 0 #include "logmacro.h" -template inline static void logerror(Format &&fmt, Params &&... args) { - util::stream_format(std::cerr, - "%s", - util::string_format(std::forward(fmt), std::forward(args)...)); -} - //************************************************************************** // External panel support //************************************************************************** @@ -720,17 +715,19 @@ void esqpanel2x40_vfx_device::device_add_mconfig(machine_config &config) { ESQ2X40_VFX(config, m_vfd, 60); - const std::string &name = owner()->shortname(); - if (name == "vfx") + if (m_panel_type == VFX) config.set_default_layout(layout_vfx); - else if (name == "vfxsd") + else if (m_panel_type == VFX_SD) config.set_default_layout(layout_vfxsd); - else // "sd1" or "sd132" - config.set_default_layout(layout_sd1); + else if (m_panel_type == SD_1 || m_panel_type == SD_1_32) + config.set_default_layout(layout_sd1); + else // lowest common demonimator as the default: just the VFD. + config.set_default_layout(layout_esq2by40_vfx); } -esqpanel2x40_vfx_device::esqpanel2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : +esqpanel2x40_vfx_device::esqpanel2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, int panel_type, uint32_t clock) : esqpanel_device(mconfig, ESQPANEL2X40_VFX, tag, owner, clock), + m_panel_type(panel_type), m_vfd(*this, "vfd"), m_lights(*this, "lights"), m_buttons_0(*this, "buttons_0"), diff --git a/src/mame/ensoniq/esqpanel.h b/src/mame/ensoniq/esqpanel.h index c5858b3d98d6b..e533b0dc05e64 100644 --- a/src/mame/ensoniq/esqpanel.h +++ b/src/mame/ensoniq/esqpanel.h @@ -105,11 +105,21 @@ class esqpanel2x40_device : public esqpanel_device { class esqpanel2x40_vfx_device : public esqpanel_device { public: - esqpanel2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + esqpanel2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, int panel_type = UNKNOWN, uint32_t clock = 0); DECLARE_INPUT_CHANGED_MEMBER(button_change); DECLARE_INPUT_CHANGED_MEMBER(analog_value_change); + void set_family_member(int family_member); + + enum panel_types : int { + UNKNOWN = 0, + VFX, + VFX_SD, + SD_1, + SD_1_32 + }; + protected: virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; virtual void device_start() override ATTR_COLD; @@ -126,6 +136,8 @@ class esqpanel2x40_vfx_device : public esqpanel_device { static constexpr uint8_t AT_BLINK = 0x02; private: + int m_panel_type; + emu_timer *m_blink_timer = nullptr; uint8_t m_blink_phase; diff --git a/src/mame/layout/esq2by40_vfx.lay b/src/mame/layout/esq2by40_vfx.lay new file mode 100644 index 0000000000000..c4deeac0435ae --- /dev/null +++ b/src/mame/layout/esq2by40_vfx.lay @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 52d20feda8a145c405523166a69cd1c62d9e9bb0 Mon Sep 17 00:00:00 2001 From: Christian Brunschen <6741909+cbrunschen@users.noreply.github.com> Date: Sun, 19 Oct 2025 16:16:00 +0100 Subject: [PATCH 3/4] More comments addressed: 1. Fix indentation in esqpanel.cpp 2. Move the VFX-style VFD font to a ROM file --- src/mame/ensoniq/esqpanel.cpp | 2 +- src/mame/ensoniq/esqvfd.cpp | 122 +++++----------------------------- src/mame/ensoniq/esqvfd.h | 4 ++ 3 files changed, 20 insertions(+), 108 deletions(-) diff --git a/src/mame/ensoniq/esqpanel.cpp b/src/mame/ensoniq/esqpanel.cpp index a95b9234da537..4c873d798919f 100644 --- a/src/mame/ensoniq/esqpanel.cpp +++ b/src/mame/ensoniq/esqpanel.cpp @@ -720,7 +720,7 @@ void esqpanel2x40_vfx_device::device_add_mconfig(machine_config &config) else if (m_panel_type == VFX_SD) config.set_default_layout(layout_vfxsd); else if (m_panel_type == SD_1 || m_panel_type == SD_1_32) - config.set_default_layout(layout_sd1); + config.set_default_layout(layout_sd1); else // lowest common demonimator as the default: just the VFD. config.set_default_layout(layout_esq2by40_vfx); } diff --git a/src/mame/ensoniq/esqvfd.cpp b/src/mame/ensoniq/esqvfd.cpp index 136b41af90ab6..f6bbb92ede1db 100644 --- a/src/mame/ensoniq/esqvfd.cpp +++ b/src/mame/ensoniq/esqvfd.cpp @@ -117,110 +117,6 @@ static const uint16_t font[]= 0x0000, // 0000 0000 0000 0000 (DEL) }; -/** - * Character data as used in the VFX family. Bit 0..13 are ordered to match - * led14seg. Bit 14 activates the dot after a character; bit 15 the underline. - * See layout/{vfx|vfxsd|sd1}.lay . - */ -static const uint16_t font_vfx[] = { - 0x0000, // 0000 0000 0000 0000 SPACE - 0x543f, // 0101 0100 0011 1111 '0.' - 0x0120, // 0000 0001 0010 0000 '"' - 0x4300, // 0100 0011 0000 0000 '1.' - 0x03ed, // 0000 0011 1110 1101 '$' - 0x40db, // 0100 0000 1101 1011 '2.' - 0x0000, // 0000 0000 0000 0000 '&' - 0x0800, // 0000 1000 0000 0000 ''' - 0x40cf, // 0100 0000 1100 1111 '3.' - 0x40e6, // 0100 0000 1110 0110 '4.' - 0x3fc0, // 0011 1111 1100 0000 '*' - 0x03c0, // 0000 0011 1100 0000 '+' - 0x0000, // 0000 0000 0000 0000 ',' - 0x00c0, // 0000 0000 1100 0000 '-' - 0x4000, // 0100 0000 0000 0000 '.' - 0x1400, // 0001 0100 0000 0000 '/' - 0x143f, // 0001 0100 0011 1111 '0' - 0x0300, // 0000 0011 0000 0000 '1' - 0x00db, // 0000 0000 1101 1011 '2' - 0x00cf, // 0000 0000 1100 1111 '3' - 0x00e6, // 0000 0000 1110 0110 '4' - 0x00ed, // 0000 0000 1110 1101 '5' - 0x00fd, // 0000 0000 1111 1101 '6' - 0x0007, // 0000 0000 0000 0111 '7' - 0x00ff, // 0000 0000 1111 1111 '8' - 0x00ef, // 0000 0000 1110 1111 '9' - 0x0000, // 0000 0000 0000 0000 ':' - 0x40fd, // 0100 0000 1111 1101 '6.' - 0x3000, // 0011 0000 0000 0000 '(' - 0x00c8, // 0000 0000 1100 1000 '=' - 0x0c00, // 0000 1100 0000 0000 ')' - 0x0000, // 0000 0000 0000 0000 '?' - 0x025f, // 0000 0010 0101 1111 '@' - 0x00f7, // 0000 0000 1111 0111 'A' - 0x038f, // 0000 0011 1000 1111 'B' - 0x0039, // 0000 0000 0011 1001 'C' - 0x030f, // 0000 0011 0000 1111 'D' - 0x00f9, // 0000 0000 1111 1001 'E' - 0x00f1, // 0000 0000 1111 0001 'F' - 0x00bd, // 0000 0000 1011 1101 'G' - 0x00f6, // 0000 0000 1111 0110 'H' - 0x0309, // 0000 0011 0000 1001 'I' - 0x001e, // 0000 0000 0001 1110 'J' - 0x3070, // 0011 0000 0111 0000 'K' - 0x0038, // 0000 0000 0011 1000 'L' - 0x1836, // 0001 1000 0011 0110 'M' - 0x2836, // 0010 1000 0011 0110 'N' - 0x003f, // 0000 0000 0011 1111 'O' - 0x00f3, // 0000 0000 1111 0011 'P' - 0x203f, // 0010 0000 0011 1111 'Q' - 0x20f3, // 0010 0000 1111 0011 'R' - 0x00ed, // 0000 0000 1110 1101 'S' - 0x0301, // 0000 0011 0000 0001 'T' - 0x003e, // 0000 0000 0011 1110 'U' - 0x1430, // 0001 0100 0011 0000 'V' - 0x2436, // 0010 0100 0011 0110 'W' - 0x3c00, // 0011 1100 0000 0000 'X' - 0x1a00, // 0001 1010 0000 0000 'Y' - 0x1409, // 0001 0100 0000 1001 'Z' - 0x0039, // 0000 0000 0011 1001 '[' - 0x40ff, // 0100 0000 1111 1111 '8.' - 0x000f, // 0000 0000 0000 1111 ']' - 0x2400, // 0010 0100 0000 0000 '^' - 0x0008, // 0000 0000 0000 1000 '_' - 0x0800, // 0000 1000 0000 0000 '`' - 0x00f7, // 0000 0000 1111 0111 'a' - 0x038f, // 0000 0011 1000 1111 'b' - 0x0039, // 0000 0000 0011 1001 'c' - 0x030f, // 0000 0011 0000 1111 'd' - 0x00f9, // 0000 0000 1111 1001 'e' - 0x00f1, // 0000 0000 1111 0001 'f' - 0x00bd, // 0000 0000 1011 1101 'g' - 0x00f6, // 0000 0000 1111 0110 'h' - 0x0309, // 0000 0011 0000 1001 'i' - 0x001e, // 0000 0000 0001 1110 'j' - 0x3070, // 0011 0000 0111 0000 'k' - 0x0038, // 0000 0000 0011 1000 'l' - 0x1836, // 0001 1000 0011 0110 'm' - 0x2836, // 0010 1000 0011 0110 'n' - 0x003f, // 0000 0000 0011 1111 'o' - 0x00f3, // 0000 0000 1111 0011 'p' - 0x203f, // 0010 0000 0011 1111 'q' - 0x20f3, // 0010 0000 1111 0011 'r' - 0x00ed, // 0000 0000 1110 1101 's' - 0x0301, // 0000 0011 0000 0001 't' - 0x003e, // 0000 0000 0011 1110 'u' - 0x1430, // 0001 0100 0011 0000 'v' - 0x2436, // 0010 0100 0011 0110 'w' - 0x3c00, // 0011 1100 0000 0000 'x' - 0x1a00, // 0001 1010 0000 0000 'y' - 0x1409, // 0001 0100 0000 1001 'z' - 0x0039, // 0000 0000 0011 1001 '{' - 0x0300, // 0000 0011 0000 0000 '|' - 0x000f, // 0000 0000 0000 1111 '}' - 0x2400, // 0010 0100 0000 0000 '~' - 0x0000, // 0000 0000 0000 0000 DEL -}; - esqvfd_device::esqvfd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dimensions_param &&dimensions) : device_t(mconfig, type, tag, owner, clock), m_vfds(std::move(std::get<0>(dimensions))), @@ -472,10 +368,22 @@ esq2x40_device::esq2x40_device(const machine_config &mconfig, const char *tag, d { } +ROM_START( esq2x40_vfx_device ) + ROM_REGION16_BE( 192, "font", 0 ) + ROM_LOAD( "esqvfd_font_vfx.bin", 0, 192, CRC(58dc335b) SHA1(097fc3e1930a49ab61f73ea7a6191c892004f823) ) +ROM_END + +const tiny_rom_entry *esq2x40_vfx_device::device_rom_region() const +{ + return ROM_NAME( esq2x40_vfx_device ); +} + esq2x40_vfx_device::esq2x40_vfx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - esq2x40_device(mconfig, ESQ2X40_VFX, tag, owner, clock) + esq2x40_device(mconfig, ESQ2X40_VFX, tag, owner, clock), + m_font(*this, "font") { } + void esq2x40_vfx_device::device_add_mconfig(machine_config &config) { // Do not set a default layout. This display must be used @@ -494,9 +402,9 @@ void esq2x40_vfx_device::update_display() { uint8_t c = m_chars[row][col]; - uint32_t char_segments = font_vfx[c < 96 ? c : 0]; + uint16_t char_segments = m_font[c < 96 ? c : 0]; auto attr = m_attrs[row][col]; - uint32_t segments; + uint16_t segments; if ((attr & AT_BLINK) && !m_blink_on) // something is blinked off { diff --git a/src/mame/ensoniq/esqvfd.h b/src/mame/ensoniq/esqvfd.h index 45fda97f00ff8..8cc34162139da 100644 --- a/src/mame/ensoniq/esqvfd.h +++ b/src/mame/ensoniq/esqvfd.h @@ -97,6 +97,10 @@ class esq2x40_vfx_device : public esq2x40_device { protected: // device-level overrides virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + const tiny_rom_entry *device_rom_region() const override; + +private: + required_region_ptr m_font; }; class esq2x40_sq1_device : public esqvfd_device { From dba771f858aa8d54c4d0b0a3db41fc631412338b Mon Sep 17 00:00:00 2001 From: Christian Brunschen <6741909+cbrunschen@users.noreply.github.com> Date: Sun, 19 Oct 2025 19:23:39 +0100 Subject: [PATCH 4/4] Ran srcclean on all changed files. --- src/mame/ensoniq/esqpanel.h | 2 +- src/mame/layout/esq2by40_vfx.lay | 28 +- src/mame/layout/sd1.lay | 1878 +++++++++++++++--------------- src/mame/layout/vfx.lay | 1664 +++++++++++++------------- src/mame/layout/vfxsd.lay | 1878 +++++++++++++++--------------- 5 files changed, 2725 insertions(+), 2725 deletions(-) diff --git a/src/mame/ensoniq/esqpanel.h b/src/mame/ensoniq/esqpanel.h index e533b0dc05e64..a63622611a64e 100644 --- a/src/mame/ensoniq/esqpanel.h +++ b/src/mame/ensoniq/esqpanel.h @@ -117,7 +117,7 @@ class esqpanel2x40_vfx_device : public esqpanel_device { VFX, VFX_SD, SD_1, - SD_1_32 + SD_1_32 }; protected: diff --git a/src/mame/layout/esq2by40_vfx.lay b/src/mame/layout/esq2by40_vfx.lay index c4deeac0435ae..9c1b83bd071a5 100644 --- a/src/mame/layout/esq2by40_vfx.lay +++ b/src/mame/layout/esq2by40_vfx.lay @@ -9,32 +9,32 @@ license:CC0-1.0 - - - + + + - - + + - - + + - - - - + + + + - - - + + + diff --git a/src/mame/layout/sd1.lay b/src/mame/layout/sd1.lay index 6fbc20c941da1..4ed7f625ce72f 100644 --- a/src/mame/layout/sd1.lay +++ b/src/mame/layout/sd1.lay @@ -3,1195 +3,1195 @@ - - - - - + + + + + - ]]> - + ]]> + - - - - - + + + + + - ]]> - + ]]> + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - + + - - - - + + + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - - - + + + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + ]]> diff --git a/src/mame/layout/vfx.lay b/src/mame/layout/vfx.lay index 689896aa14e25..748ed8423f305 100644 --- a/src/mame/layout/vfx.lay +++ b/src/mame/layout/vfx.lay @@ -3,1062 +3,1062 @@ - - - - - + + + + + - ]]> - + ]]> + - - - - - + + + + + - ]]> - + ]]> + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - + + - - - - + + + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - - - + + + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + ]]> diff --git a/src/mame/layout/vfxsd.lay b/src/mame/layout/vfxsd.lay index 551cc388eba4e..2df847f26a864 100644 --- a/src/mame/layout/vfxsd.lay +++ b/src/mame/layout/vfxsd.lay @@ -3,1195 +3,1195 @@ - - - - - + + + + + - ]]> - + ]]> + - - - - - + + + + + - ]]> - + ]]> + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - + + - - - - + + + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - - - + + + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - ]]> - - - - - - ]]> - + + + + + ]]> + + + + + + ]]> + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + ]]>