diff --git a/src/devices/cpu/upd7810/upd7810.cpp b/src/devices/cpu/upd7810/upd7810.cpp
index 4f706c09a137b..ff7dc46c5f34a 100644
--- a/src/devices/cpu/upd7810/upd7810.cpp
+++ b/src/devices/cpu/upd7810/upd7810.cpp
@@ -813,6 +813,12 @@ void upd7801_device::write_pc(uint8_t data)
m_pc_out_cb(data);
}
+void upd7810_device::write_smh(uint8_t data)
+{
+ if (!BIT(SMH, 2) && BIT(data, 2)) IRR |= INTFST;
+ SMH = data;
+}
+
void upd7810_device::upd7810_take_irq()
{
uint16_t vector = 0;
diff --git a/src/devices/cpu/upd7810/upd7810.h b/src/devices/cpu/upd7810/upd7810.h
index cdda6dd8077bc..e7d8eb2c12a59 100644
--- a/src/devices/cpu/upd7810/upd7810.h
+++ b/src/devices/cpu/upd7810/upd7810.h
@@ -202,6 +202,7 @@ class upd7810_device : public cpu_device
virtual void configure_ops();
virtual uint8_t read_pc();
virtual void write_pc(uint8_t data);
+ void write_smh(uint8_t data);
static const struct opcode_s s_op48[256];
static const struct opcode_s s_op4C[256];
diff --git a/src/devices/cpu/upd7810/upd7810_opcodes.cpp b/src/devices/cpu/upd7810/upd7810_opcodes.cpp
index f9580278be536..89117d84b95f5 100644
--- a/src/devices/cpu/upd7810/upd7810_opcodes.cpp
+++ b/src/devices/cpu/upd7810/upd7810_opcodes.cpp
@@ -1013,7 +1013,7 @@ void upd7810_device::MOV_ANM_A()
/* 4d c9: 0100 1101 1100 1001 */
void upd7810_device::MOV_SMH_A()
{
- SMH = A;
+ write_smh(A);
}
/* 4d ca: 0100 1101 1100 1010 */
@@ -4093,7 +4093,10 @@ void upd7810_device::MVI_ANM_xx()
/* 64 81: 0110 0100 1000 0001 xxxx xxxx */
void upd7810_device::MVI_SMH_xx()
{
- RDOPARG( SMH );
+ uint8_t imm;
+
+ RDOPARG( imm );
+ write_smh(imm);
}
/* 64 83: 0110 0100 1000 0011 xxxx xxxx */
@@ -4125,7 +4128,7 @@ void upd7810_device::ANI_SMH_xx()
uint8_t imm;
RDOPARG( imm );
- SMH &= imm;
+ write_smh(SMH & imm);
SET_Z(SMH);
}
@@ -4169,7 +4172,7 @@ void upd7810_device::XRI_SMH_xx()
uint8_t imm;
RDOPARG( imm );
- SMH ^= imm;
+ write_smh(SMH ^ imm);
SET_Z(SMH);
}
@@ -4213,7 +4216,7 @@ void upd7810_device::ORI_SMH_xx()
uint8_t imm;
RDOPARG( imm );
- SMH |= imm;
+ write_smh(SMH | imm);
SET_Z(SMH);
}
@@ -4263,7 +4266,7 @@ void upd7810_device::ADINC_SMH_xx()
tmp = SMH + imm;
ZHC_ADD( tmp, SMH, 0 );
- SMH = tmp;
+ write_smh(tmp);
SKIP_NC;
}
@@ -4371,7 +4374,7 @@ void upd7810_device::SUINB_SMH_xx()
RDOPARG( imm );
tmp = SMH - imm;
ZHC_SUB( tmp, SMH, 0 );
- SMH = tmp;
+ write_smh(tmp);
SKIP_NC;
}
@@ -4469,7 +4472,7 @@ void upd7810_device::ADI_SMH_xx()
tmp = SMH + imm;
ZHC_ADD( tmp, SMH, 0 );
- SMH = tmp;
+ write_smh(tmp);
}
/* 64 c3: 0110 0100 1100 0011 xxxx xxxx */
@@ -4562,7 +4565,7 @@ void upd7810_device::ACI_SMH_xx()
tmp = SMH + imm + (PSW & CY);
ZHC_ADD( tmp, SMH, (PSW & CY) );
- SMH = tmp;
+ write_smh(tmp);
}
/* 64 d3: 0110 0100 1101 0011 xxxx xxxx */
@@ -4653,7 +4656,7 @@ void upd7810_device::SUI_SMH_xx()
RDOPARG( imm );
tmp = SMH - imm;
ZHC_SUB( tmp, SMH, 0 );
- SMH = tmp;
+ write_smh(tmp);
}
/* 64 e3: 0110 0100 1110 0011 xxxx xxxx */
@@ -4746,7 +4749,7 @@ void upd7810_device::SBI_SMH_xx()
RDOPARG( imm );
tmp = SMH - imm - (PSW & CY);
ZHC_SUB( tmp, SMH, (PSW & CY) );
- SMH = tmp;
+ write_smh(tmp);
}
/* 64 f3: 0110 0100 1111 0011 xxxx xxxx */
@@ -8746,7 +8749,7 @@ void upd7810_device::SETB()
MKL |= (1 << bit);
break;
case 0x19: /* SMH */
- SMH |= (1 << bit);
+ write_smh(SMH | (1 << bit));
break;
case 0x1b: /* EOM */
EOM |= (1 << bit);
@@ -8796,7 +8799,7 @@ void upd7810_device::CLR()
MKL &= ~(1 << bit);
break;
case 0x19: /* SMH */
- SMH &= ~(1 << bit);
+ write_smh(SMH & ~(1 << bit));
break;
case 0x1b: /* EOM */
EOM &= ~(1 << bit);
diff --git a/src/mame/layout/pg1000.lay b/src/mame/layout/pg1000.lay
new file mode 100644
index 0000000000000..d73bf9138e447
--- /dev/null
+++ b/src/mame/layout/pg1000.lay
@@ -0,0 +1,915 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 66764d1f8d8c7..c9ccfe8f6bf5c 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -40009,6 +40009,9 @@ mt32
@source:roland/roland_mt80s.cpp
mt80s
+@source:roland/roland_pg1000.cpp
+pg1000
+
@source:roland/roland_pr100.cpp
pr100
pr100_201
diff --git a/src/mame/roland/pg1000.cpp b/src/mame/roland/pg1000.cpp
deleted file mode 100644
index f5eca493dc752..0000000000000
--- a/src/mame/roland/pg1000.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Felipe Sanches
-/****************************************************************************
-
- Skeleton device for Roland PG-1000 programmer.
-
-****************************************************************************/
-
-#include "emu.h"
-#include "pg1000.h"
-
-DEFINE_DEVICE_TYPE(PG1000, pg1000_device, "pg1000", "Roland PG-1000 Programmer")
-
-pg1000_device::pg1000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, PG1000, tag, owner, clock)
- , m_pgcpu(*this, "pgcpu")
-{
-}
-
-void pg1000_device::device_start()
-{
-}
-
-void pg1000_device::device_add_mconfig(machine_config &config)
-{
- UPD78C10(config, m_pgcpu, 12_MHz_XTAL);
-}
-
-ROM_START(pg1000)
- ROM_DEFAULT_BIOS("v2.00")
- ROM_SYSTEM_BIOS(0, "v2.00", "Version 2.00")
- ROM_SYSTEM_BIOS(1, "v1.01", "Version 1.01")
- ROM_SYSTEM_BIOS(2, "v1.00", "Version 1.00")
-
- ROM_REGION(0x8000, "pgcpu", 0)
- ROMX_LOAD("roland_pg-1000_v2.00.ic4", 0x000, 0x2000, CRC(c8bc1f62) SHA1(796d5efd09b411d370f93b32283aa33a4435dec4), ROM_BIOS(0))
- ROMX_LOAD("roland_pg-1000_v1.01.ic4", 0x000, 0x2000, CRC(9f9bcf76) SHA1(da5a45c65a04c35d7a615c6f043ccaf958b0d65e), ROM_BIOS(1))
- ROMX_LOAD("roland_pg-1000_v1.00.ic4", 0x000, 0x2000, CRC(c09ef84e) SHA1(d780d4d53e57918e6ea8098f54f5c9b43aeec287), ROM_BIOS(2))
-ROM_END
-
-const tiny_rom_entry *pg1000_device::device_rom_region() const
-{
- return ROM_NAME(pg1000);
-}
diff --git a/src/mame/roland/pg1000.h b/src/mame/roland/pg1000.h
deleted file mode 100644
index 9298f76f1156a..0000000000000
--- a/src/mame/roland/pg1000.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Felipe Sanches
-
-#ifndef MAME_ROLAND_PG1000_H
-#define MAME_ROLAND_PG1000_H
-
-#include "cpu/upd7810/upd7810.h"
-
-
-class pg1000_device : public device_t
-{
-public:
- pg1000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
-
-protected:
- virtual void device_start() override ATTR_COLD;
- virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
- virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
-
-private:
- required_device m_pgcpu;
-};
-
-DECLARE_DEVICE_TYPE(PG1000, pg1000_device)
-
-#endif // MAME_ROLAND_PG1000_H
diff --git a/src/mame/roland/roland_d50.cpp b/src/mame/roland/roland_d50.cpp
index c053474485df8..6b7e7d0a4b817 100644
--- a/src/mame/roland/roland_d50.cpp
+++ b/src/mame/roland/roland_d50.cpp
@@ -9,7 +9,6 @@
#include "emu.h"
#include "mb63h149.h"
-#include "pg1000.h"
#include "cpu/upd78k/upd78k3.h"
#include "machine/bankdev.h"
@@ -207,8 +206,6 @@ void roland_d50_state::d50(machine_config &config)
//keyscan.int_callback().set_inputline(m_maincpu, upd78312_device::INT2_LINE);
//MB87136(config, "synthe", 32.768_MHz_XTAL);
-
- PG1000(config, "programmer");
}
void roland_d50_state::d550(machine_config &config)
diff --git a/src/mame/roland/roland_pg1000.cpp b/src/mame/roland/roland_pg1000.cpp
new file mode 100644
index 0000000000000..c93711e98c3ef
--- /dev/null
+++ b/src/mame/roland/roland_pg1000.cpp
@@ -0,0 +1,508 @@
+// license:BSD-3-Clause
+// copyright-holders:Felipe Sanches
+/****************************************************************************
+
+ Roland PG-1000 programmer.
+
+ To be used alongside Roland D-50/D-550/MT-32
+
+-----------------------------------------------------------------------------
+
+ Notes:
+ midiin1 is the usual "MIDI IN" port.
+ midiin2 is the "Parameter In" port.
+
+ usage:
+ mame pg1000 -midiin1 "ctrl" -midiin2 "synth" -midiout "synth"
+
+ where:
+ "ctrl" is a MIDI OUT device such as
+ an external usb midi keyboard controller.
+
+ "synth" is a D-50 or a D-550.
+ (and I guess it may work with a Roland MT-32 as well)
+
+ During development, I tested this setup using a real Roland D-550.
+
+-----------------------------------------------------------------------------
+
+ Known driver bug:
+
+ This driver is almost perfectly functional, but remains marked with the
+ MACHINE_NOT_WORKING flag due to an unresolved issue related to its
+ MIDI ports.
+
+ While running it hooked up to an USB-MIDI controller, the MIDI messages
+ are not perfectly repeated from MIDI IN to MIDI OUT as they should be.
+ Instead, sometimes we get some data corruption, specially when using
+ the sustain pedal.
+
+ I suspect this may be some CPU bug, perhaps an incorrect or incomplete
+ implementation of one of the upd7810 instructions used in the serial
+ port code-path.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "bus/midi/midi.h"
+#include "cpu/upd7810/upd7810.h"
+#include "video/hd44780.h"
+#include "emupal.h"
+#include "screen.h"
+#include "pg1000.lh"
+
+namespace {
+
+class pg1000_state : public driver_device
+{
+public:
+ pg1000_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_lcdc(*this, "lcdc")
+ , m_row(*this, "ROW%u", 0U)
+ , m_led(*this, "LED%u", 0U)
+ , m_top_slider(*this, "top_slider_%u", 0U)
+ , m_middle_slider(*this, "middle_slider_%u", 0U)
+ , m_bottom_slider(*this, "bottom_slider_%u", 0U)
+ , m_paramin(*this, "paramin")
+ , m_mdin(*this, "mdin")
+ , m_mdout(*this, "mdout")
+ , m_scan(0)
+ , m_an_select(0)
+ , m_mdin_bit(true)
+ , m_paramin_bit(true)
+ , m_midi_in_enable(false)
+ , m_param_in_enable(false)
+ {
+ }
+
+ void pg1000(machine_config &config);
+
+protected:
+ virtual void machine_start() override ATTR_COLD;
+
+private:
+ u8 sw_r();
+ void led_w(u8 data);
+ void mem_map(address_map &map) ATTR_COLD;
+ void palette_init(palette_device &palette);
+
+ required_device m_maincpu;
+ required_device m_lcdc;
+ required_ioport_array<2> m_row;
+ output_finder<6> m_led;
+ required_ioport_array<13> m_top_slider;
+ required_ioport_array<23> m_middle_slider;
+ required_ioport_array<20> m_bottom_slider;
+ optional_device m_paramin;
+ optional_device m_mdin;
+ optional_device m_mdout;
+
+ u8 m_scan;
+ u8 m_an_select;
+ bool m_mdin_bit;
+ bool m_paramin_bit;
+ bool m_midi_in_enable;
+ bool m_param_in_enable;
+};
+
+
+void pg1000_state::machine_start()
+{
+ m_led.resolve();
+
+ save_item(NAME(m_scan));
+ save_item(NAME(m_an_select));
+ save_item(NAME(m_mdin_bit));
+ save_item(NAME(m_paramin_bit));
+ save_item(NAME(m_midi_in_enable));
+ save_item(NAME(m_param_in_enable));
+}
+
+u8 pg1000_state::sw_r()
+{
+ u8 value = 0xff;
+ if (!BIT(m_scan, 1))
+ value = m_row[1]->read();
+
+ if (!BIT(m_scan, 0))
+ value = (value & 0xfc) | (m_row[0]->read() & 3);
+
+ return value;
+}
+
+void pg1000_state::led_w(u8 data)
+{
+ m_scan = data & 3;
+ for (int i=0; i<=5; i++)
+ m_led[i] = BIT(data, i+2);
+}
+
+static INPUT_PORTS_START(pg1000)
+ PORT_START("ROW0")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("MANUAL") PORT_CODE(KEYCODE_X)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PARAMETER REQUEST") PORT_CODE(KEYCODE_Z)
+ PORT_BIT(0xfc, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("ROW1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PREVIOUS VALUE") PORT_CODE(KEYCODE_R)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("MIDI CHANNEL") PORT_CODE(KEYCODE_E)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("COMMON SELECT UPPER") PORT_CODE(KEYCODE_W)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("COMMON SELECT LOWER") PORT_CODE(KEYCODE_Q)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PARTIAL SELECT UPPER 1") PORT_CODE(KEYCODE_D)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PARTIAL SELECT UPPER 2") PORT_CODE(KEYCODE_F)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PARTIAL SELECT LOWER 1") PORT_CODE(KEYCODE_A)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PARTIAL SELECT LOWER 2") PORT_CODE(KEYCODE_S)
+
+
+ PORT_START("top_slider_0")
+ PORT_ADJUSTER(128, "WG PITCH: COARSE") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_1")
+ PORT_ADJUSTER(128, "WG PITCH: FINE") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_2")
+ PORT_ADJUSTER(128, "WG PITCH: KF") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_3")
+ PORT_ADJUSTER(128, "WG PITCH: LFO MODE") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_4")
+ PORT_ADJUSTER(128, "WG PITCH: ENV MODE") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_5")
+ PORT_ADJUSTER(128, "WG PITCH: BEND MODE") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_6")
+ PORT_ADJUSTER(128, "WG WAVEFORM: WF") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_7")
+ PORT_ADJUSTER(128, "WG WAVEFORM: PW") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_8")
+ PORT_ADJUSTER(128, "WG WAVEFORM: PW VELO") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_9")
+ PORT_ADJUSTER(128, "WG WAVEFORM: PW AFTER") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_10")
+ PORT_ADJUSTER(128, "WG WAVEFORM: PWM LFO SEL") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_11")
+ PORT_ADJUSTER(128, "WG WAVEFORM: PWM DEPTH") PORT_MINMAX(0, 255)
+
+ PORT_START("top_slider_12")
+ PORT_ADJUSTER(128, "WG WAVEFORM: PCM") PORT_MINMAX(0, 255)
+
+
+ PORT_START("middle_slider_0")
+ PORT_ADJUSTER(128, "TVF: CUTOFF FREQ") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_1")
+ PORT_ADJUSTER(128, "TVF: RESO") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_2")
+ PORT_ADJUSTER(128, "TVF: KF") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_3")
+ PORT_ADJUSTER(128, "TVF: BIAS DIREC") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_4")
+ PORT_ADJUSTER(128, "TVF: BIAS POINT") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_5")
+ PORT_ADJUSTER(128, "TVF: BIAS LEVEL") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_6")
+ PORT_ADJUSTER(128, "TVF: ENV DEPTH") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_7")
+ PORT_ADJUSTER(128, "TVF: ENV VELO") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_8")
+ PORT_ADJUSTER(128, "TVF: LFO SELECT") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_9")
+ PORT_ADJUSTER(128, "TVF: LFO DEPTH") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_10")
+ PORT_ADJUSTER(128, "TVF: AFTER RANGE") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_11")
+ PORT_ADJUSTER(128, "TVF ENV: T1") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_12")
+ PORT_ADJUSTER(128, "TVF ENV: T2") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_13")
+ PORT_ADJUSTER(128, "TVF ENV: T3") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_14")
+ PORT_ADJUSTER(128, "TVF ENV: T4") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_15")
+ PORT_ADJUSTER(128, "TVF ENV: T5") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_16")
+ PORT_ADJUSTER(128, "TVF ENV: TKF") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_17")
+ PORT_ADJUSTER(128, "TVA ENV: T1") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_18")
+ PORT_ADJUSTER(128, "TVA ENV: T2") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_19")
+ PORT_ADJUSTER(128, "TVA ENV: T3") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_20")
+ PORT_ADJUSTER(128, "TVA ENV: T4") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_21")
+ PORT_ADJUSTER(128, "TVA ENV: T5") PORT_MINMAX(0, 255)
+
+ PORT_START("middle_slider_22")
+ PORT_ADJUSTER(128, "TVA ENV: TKF") PORT_MINMAX(0, 255)
+
+
+ PORT_START("bottom_slider_0")
+ PORT_ADJUSTER(128, "TVA: LEVEL") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_1")
+ PORT_ADJUSTER(128, "TVA: VELO") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_2")
+ PORT_ADJUSTER(128, "TVA: BIAS DIREC") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_3")
+ PORT_ADJUSTER(128, "TVA: BIAS POINT") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_4")
+ PORT_ADJUSTER(128, "TVA: BIAS LEVEL") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_5")
+ PORT_ADJUSTER(128, "TVA: LFO SELECT") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_6")
+ PORT_ADJUSTER(128, "TVA: LFO DEPTH") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_7")
+ PORT_ADJUSTER(128, "TVA: AFTER RANGE") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_8")
+ PORT_ADJUSTER(128, "TVF ENV: L1") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_9")
+ PORT_ADJUSTER(128, "TVF ENV: L2") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_10")
+ PORT_ADJUSTER(128, "TVF ENV: L3") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_11")
+ PORT_ADJUSTER(128, "TVF ENV: SUS L") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_12")
+ PORT_ADJUSTER(128, "TVF ENV: END L") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_13")
+ PORT_ADJUSTER(128, "TVF ENV: DKF") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_14")
+ PORT_ADJUSTER(128, "TVA ENV: L1") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_15")
+ PORT_ADJUSTER(128, "TVA ENV: L2") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_16")
+ PORT_ADJUSTER(128, "TVA ENV: L3") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_17")
+ PORT_ADJUSTER(128, "TVA ENV: SUS L") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_18")
+ PORT_ADJUSTER(128, "TVA ENV: END L") PORT_MINMAX(0, 255)
+
+ PORT_START("bottom_slider_19")
+ PORT_ADJUSTER(128, "TVA ENV: T1 VELO") PORT_MINMAX(0, 255)
+INPUT_PORTS_END
+
+
+void pg1000_state::mem_map(address_map &map)
+{
+ map(0x0000, 0x1fff).rom().region("maincpu", 0);
+ map(0xa000, 0xa000).lw8(NAME([this] (u8 data) {
+ m_lcdc->db_w(data);
+ m_lcdc->e_w(0);
+ m_lcdc->e_w(1);
+ }));
+ map(0xc000, 0xdfff).ram();
+}
+
+void pg1000_state::palette_init(palette_device &palette)
+{
+ palette.set_pen_color(0, rgb_t(11, 183, 253));
+ palette.set_pen_color(1, rgb_t(0, 60, 130));
+}
+
+void pg1000_state::pg1000(machine_config &config)
+{
+ MIDI_PORT(config, "mdin", midiin_slot, "midiin").rxd_handler().set(
+ [this] (int state) { m_mdin_bit = state; }
+ );
+
+ MIDI_PORT(config, "paramin", midiin_slot, "midiin").rxd_handler().set(
+ [this] (int state) { m_paramin_bit = state; }
+ );
+
+ MIDI_PORT(config, "mdout", midiout_slot, "midiout");
+
+ UPD78C10(config, m_maincpu, 12_MHz_XTAL);
+ m_maincpu->set_addrmap(AS_PROGRAM, &pg1000_state::mem_map);
+ m_maincpu->pa_in_cb().set(FUNC(pg1000_state::sw_r));
+ m_maincpu->pb_out_cb().set(FUNC(pg1000_state::led_w));
+ m_maincpu->rxd_func().set([this]() {
+ return int(
+ (m_mdin_bit && m_midi_in_enable) ||
+ (m_paramin_bit && m_param_in_enable) ||
+ (!m_midi_in_enable && !m_param_in_enable) /* due to pull-up */
+ );
+ });
+ m_maincpu->pc_out_cb().set([this](u8 data)
+ {
+ m_mdout->write_txd(BIT(data, 0));
+ m_midi_in_enable = BIT(data, 2);
+ m_param_in_enable = BIT(data, 3);
+ m_lcdc->rs_w(BIT(data, 4));
+ m_an_select = (data >> 5) & 7;
+ });
+ m_maincpu->an0_func().set([this] { /* IC11 */
+ switch(m_an_select)
+ {
+ case 7: return m_bottom_slider[1]->read(); /* TVA: VELO */
+ case 6: return m_bottom_slider[0]->read(); /* TVA: LEVEL */
+ case 5: return m_bottom_slider[2]->read(); /* TVA: BIAS DIREC */
+ case 4: return m_middle_slider[0]->read(); /* TVF: CUTOFF FREQ */
+ case 3: return m_middle_slider[4]->read(); /* TVF: BIAS POINT */
+ case 2: return m_middle_slider[1]->read(); /* TVF: RESO */
+ case 1: return m_middle_slider[2]->read(); /* TVF: KF */
+ case 0: return m_middle_slider[3]->read(); /* TVF: BIAS DIREC */
+ }
+ return (unsigned int) 0xff; // std::unreachable();
+ });
+ m_maincpu->an1_func().set([this] { /* IC14 */
+ switch(m_an_select)
+ {
+ case 7: return m_bottom_slider[13]->read(); /* TVF ENV: DKF */
+ case 6: return m_bottom_slider[12]->read(); /* TVF ENV: END L */
+ case 5: return m_bottom_slider[14]->read(); /* TVA ENV: L1 */
+ case 4: return m_bottom_slider[11]->read(); /* TVF ENV: SUS L */
+ case 3: return m_middle_slider[17]->read(); /* TVA ENV: T1 */
+ case 2: return m_middle_slider[14]->read(); /* TVF ENV: T4 */
+ case 1: return m_middle_slider[15]->read(); /* TVF ENV: T5 */
+ case 0: return m_middle_slider[16]->read(); /* TVF ENV: TKF */
+ }
+ return (unsigned int) 0xff; // std::unreachable();
+ });
+ m_maincpu->an2_func().set([this] { /* IC8 */
+ switch(m_an_select)
+ {
+ case 7: return m_top_slider[12]->read(); /* WG WAVEFORM: PCM */
+ case 6: return m_middle_slider[22]->read(); /* TVA ENV: TKF */
+ case 5: return m_top_slider[11]->read(); /* WG WAVEFORM: PWM DEPTH */
+ case 4: return m_middle_slider[21]->read(); /* TVA ENV: T5 */
+ case 3: return m_top_slider[10]->read(); /* WG WAVEFORM: PWM LFO SEL */
+ case 2: return m_top_slider[7]->read(); /* WG WAVEFORM: PW */
+ case 1: return m_top_slider[8]->read(); /* WG WAVEFORM: PW VELO */
+ case 0: return m_top_slider[9]->read(); /* WG WAVEFORM: PW AFTER */
+ }
+ return (unsigned int) 0xff; // std::unreachable();
+ });
+ m_maincpu->an3_func().set([this] { /* IC13 */
+ switch(m_an_select)
+ {
+ case 7: return m_bottom_slider[9]->read(); /* TVF ENV: L2 */
+ case 6: return m_bottom_slider[8]->read(); /* TVF ENV: L1 */
+ case 5: return m_bottom_slider[10]->read(); /* TVF ENV: L3 */
+ case 4: return m_bottom_slider[7]->read(); /* TVA: AFTER RANGE */
+ case 3: return m_middle_slider[13]->read(); /* TVF ENV: T3 */
+ case 2: return m_middle_slider[9]->read(); /* TVF: LFO DEPTH */
+ case 1: return m_middle_slider[10]->read(); /* TVF: AFTER RANGE */
+ case 0: return m_middle_slider[11]->read(); /* TVF ENV: T1 */
+ }
+ return (unsigned int) 0xff; // std::unreachable();
+ });
+ m_maincpu->an4_func().set([this] { /* IC9 */
+ switch(m_an_select)
+ {
+ case 7: return m_top_slider[0]->read(); /* WG PITCH: COARSE */
+ case 6: return m_top_slider[1]->read(); /* WG PITCH: FINE */
+ case 5: return m_middle_slider[12]->read(); /* TVF ENV: T2 */
+ case 4: return m_top_slider[2]->read(); /* WG PITCH: KF */
+ case 3: return m_top_slider[6]->read(); /* WG WAVEFORM: WF */
+ case 2: return m_top_slider[3]->read(); /* WG PITCH: LFO MODE */
+ case 1: return m_top_slider[4]->read(); /* WG PITCH: ENV MODE */
+ case 0: return m_top_slider[5]->read(); /* WG PITCH: BEND MODE */
+ }
+ return (unsigned int) 0xff; // std::unreachable();
+ });
+ m_maincpu->an5_func().set([this] { /* IC12 */
+ switch(m_an_select)
+ {
+ case 7: return m_bottom_slider[5]->read(); /* TVA: LFO SELECT */
+ case 6: return m_bottom_slider[4]->read(); /* TVA: BIAS LEVEL */
+ case 5: return m_bottom_slider[6]->read(); /* TVA: LFO DEPTH */
+ case 4: return m_bottom_slider[3]->read(); /* TVA: BIAS POINT */
+ case 3: return m_middle_slider[8]->read(); /* TVF: LFO SELECT */
+ case 2: return m_middle_slider[5]->read(); /* TVF: BIAS LEVEL */
+ case 1: return m_middle_slider[6]->read(); /* TVF: ENV DEPTH */
+ case 0: return m_middle_slider[7]->read(); /* TVF: ENV VELO */
+ }
+ return (unsigned int) 0xff; // std::unreachable();
+ });
+ m_maincpu->an6_func().set([this] { /* IC15 */
+ switch(m_an_select)
+ {
+ case 7: return m_bottom_slider[17]->read(); /* TVA ENV: SUS L */
+ case 6: return m_bottom_slider[16]->read(); /* TVA ENV: L3 */
+ case 5: return m_bottom_slider[18]->read(); /* TVA ENV: END L */
+ case 4: return m_bottom_slider[15]->read(); /* TVA ENV: L2 */
+ case 3: return m_bottom_slider[19]->read(); /* TVA ENV: T1 VELO */
+ case 2: return m_middle_slider[18]->read(); /* TVA ENV: T2 */
+ case 1: return m_middle_slider[19]->read(); /* TVA ENV: T3 */
+ case 0: return m_middle_slider[20]->read(); /* TVA ENV: T4 */
+ }
+ return (unsigned int) 0xff; // std::unreachable();
+ });
+
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
+ screen.set_refresh_hz(60);
+ screen.set_screen_update("lcdc", FUNC(hd44780_device::screen_update));
+ screen.set_size(6*16, 8*2+1);
+ screen.set_visarea_full();
+ screen.set_palette("palette");
+
+ PALETTE(config, "palette", FUNC(pg1000_state::palette_init), 2);
+
+ /* Actual device is LM16255 */
+ HD44780(config, m_lcdc, 270'000); // TODO: clock not measured, datasheet typical clock used
+ m_lcdc->set_lcd_size(2, 16);
+
+ config.set_default_layout(layout_pg1000);
+}
+
+ROM_START(pg1000)
+ ROM_DEFAULT_BIOS("v2.00")
+ ROM_SYSTEM_BIOS(0, "v2.00", "Version 2.00")
+ ROM_SYSTEM_BIOS(1, "v1.01", "Version 1.01")
+ ROM_SYSTEM_BIOS(2, "v1.00", "Version 1.00")
+
+ ROM_REGION(0x8000, "maincpu", 0)
+ ROMX_LOAD("roland_pg-1000_v2.00.ic4", 0x000, 0x2000, CRC(c8bc1f62) SHA1(796d5efd09b411d370f93b32283aa33a4435dec4), ROM_BIOS(0))
+ ROMX_LOAD("roland_pg-1000_v1.01.ic4", 0x000, 0x2000, CRC(9f9bcf76) SHA1(da5a45c65a04c35d7a615c6f043ccaf958b0d65e), ROM_BIOS(1))
+ ROMX_LOAD("roland_pg-1000_v1.00.ic4", 0x000, 0x2000, CRC(c09ef84e) SHA1(d780d4d53e57918e6ea8098f54f5c9b43aeec287), ROM_BIOS(2))
+ROM_END
+
+} // anonymous namespace
+
+SYST(1987, pg1000, 0, 0, pg1000, pg1000, pg1000_state, empty_init, "Roland", "PG-1000 Linear Synthesizer Programmer", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE)