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)