summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/prophet600.cpp
blob: d4b8201f856e20eb15e7d7acaad59d5be8fa8adb (plain) (tree)
1
2
3
4
5
6
7
8




                                                                            


                                                                 











                                           
 
            
                    

                                                                                      





                                                                                                 



                                                                                





                                  

                                  
 
                                                                                     

                                                                                       
 










                                                                            


                          
 

    



                                                                          




                                                                                                


                                             
                                                                                          


                                              
                                               

                             

                                 

           


                                                
                                              
 

                                                    












                                                  

                                       
 




                                                


                             






                                                                         
                               

  
                                                     



                                                          





                                                             

                                                 



                                                                 



























                                                                

                                      
                             
         
                                                                                                                      
         
                                  
         
                                   
         
                                  
         
                                   









                                       
                                                  
                                                                           







                                      
                                            

 

                                     





                                                     



                                       






                                  


                                                                    

                                                               







                                                                      
                         


                            




                                                         
                                                             






                                                                                                            





                                                                                                               
 
 
                                      
 
                           


                                                         
                                                  


                                                            
 
                                                     
 





                                                                             
 


                                                                              

                                                         
                                                                             


                                                            
                                                                                                    
                                                                                   










                                                                                                                    
                                                                                                                                                              
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/***************************************************************************

    prophet600.cpp - Sequential Circuits Prophet-600, designed by Dave Smith

    This was the first commercial synthesizer with built-in MIDI.

    Skeleton driver by R. Belmont

    Hardware:
        CPU: Z80 CPU + 8253 PIT + 6850 UART

    Memory map:
    0x0000-0x1fff: ROM
    0x2000-0x27ff: RAM 1
    0x3000-0x37ff: RAM 2
    0x4000-0x4001: DAC for CV/gate drive
    0x6000-0x6001: 6850 writes
    0xe000-0xe001: 6850 reads

    I/O map:
    00-07:  8253 PIT
    08: set row to scan for keyboard/panel input and LED / lamp output
    09: read: analog comparitor, some value vs. the DAC.  write: output for LEDs/lamps
        comparitor bits:
        bit 1: FFFStatus
        bit 2: output of 8253 channel 2
        bit 3: ADCCompare: returns sign of if current value is > or < the DAC value

    0a: read: keyboard/panel input scan bits, write: select a pot on the panel for the comparitor
    0b: write: update all gate signals
    0c: ???
    0d: write: select which CV signal will be updated with the current DAC value
    0e: write: mask, masks
        bit 0: FFFP -FF P
        bit 1: mask gate from 8253
        bit 3: FFFD FF D
        bit 4: FFFCL -FF CL


    Info:
    - Prophet 600 Technical Manual

    - https://github.com/gligli/p600fw - GPLv3 licensed complete replacement firmware
    for the Prophet 600, but written in C and runs on an AVR that replaces the original
    Z80.

***************************************************************************/

#include "emu.h"
#include "machine/clock.h"
#include "cpu/z80/z80.h"
#include "bus/midi/midi.h"
#include "machine/6850acia.h"
#include "machine/pit8253.h"

#include "prophet600.lh"

#define MAINCPU_TAG "z80"
#define PIT_TAG     "pit"
#define UART_TAG    "uart"

enum
{
	CV_CV_Osc1A = 0, CV_Osc2A, CV_Osc3A, CV_Osc4A, CV_Osc5A, CV_Osc6A,
	CV_Osc1B, CV_Osc2B, CV_Osc3B, CV_Osc4B, CV_Osc5B, CV_Osc6B,
	CV_Flt1, CV_Flt2, CV_Flt3, CV_Flt4, CV_Flt5, CV_Flt6,
	CV_Amp1, CV_Amp2, CV_Amp3, CV_Amp4, CV_Amp5, CV_Amp6,
	CV_PModOscB, CV_VolA, CV_VolB, CV_MasterVol, CV_APW, CV_ExtFilter, CV_Resonance, CV_BPW,

	CV_MAX
};

class prophet600_state : public driver_device
{
public:
	prophet600_state(const machine_config &mconfig, device_type type, const char *tag)
	: driver_device(mconfig, type, tag),
		m_maincpu(*this, MAINCPU_TAG),
		m_acia(*this, UART_TAG),
		m_digits(*this, "digit%u", 0U),
		m_dac(0),
		m_scanrow(0),
		m_comparitor(0),
		m_nmi_gate(false)
	{ }

	void prophet600(machine_config &config);

private:
	virtual void machine_start() override;

	DECLARE_WRITE_LINE_MEMBER( pit_ch0_tick_w );
	DECLARE_WRITE_LINE_MEMBER( pit_ch2_tick_w );
	DECLARE_WRITE_LINE_MEMBER( acia_irq_w );
	DECLARE_WRITE_LINE_MEMBER( acia_clock_w );

	DECLARE_WRITE8_MEMBER(dac_w);
	DECLARE_WRITE8_MEMBER(scanrow_w);
	DECLARE_WRITE8_MEMBER(led_w);
	DECLARE_READ8_MEMBER(scan_r);
	DECLARE_WRITE8_MEMBER(potmux_w);
	DECLARE_READ8_MEMBER(comparitor_r);
	DECLARE_WRITE8_MEMBER(mask_w);
	DECLARE_WRITE8_MEMBER(cv_w);
	DECLARE_WRITE8_MEMBER(gate_w);

	void cpu_map(address_map &map);
	void io_map(address_map &map);

	required_device<cpu_device> m_maincpu;
	required_device<acia6850_device> m_acia;

	output_finder<2> m_digits;

	uint16_t m_dac;
	uint8_t m_scanrow;
	uint8_t m_comparitor;

	bool m_nmi_gate;

	// gates
	bool m_ASaw, m_ATri, m_Sync, m_BSaw, m_BTri, m_PModFA, m_PModFil;

	// control voltages
	uint16_t m_CVs[CV_MAX];
};

WRITE_LINE_MEMBER( prophet600_state::pit_ch0_tick_w )
{
	m_maincpu->set_input_line(INPUT_LINE_IRQ0, state);
}

WRITE_LINE_MEMBER( prophet600_state::pit_ch2_tick_w )
{
	m_comparitor &= ~0x04;
	m_comparitor |= (state == ASSERT_LINE) ? 0x04 : 0x00;
}

WRITE_LINE_MEMBER( prophet600_state::acia_irq_w )
{
	if (!m_nmi_gate)
	{
		m_maincpu->set_input_line(INPUT_LINE_NMI, state);
	}
}

WRITE_LINE_MEMBER( prophet600_state::acia_clock_w )
{
	m_acia->write_txc(state);
	m_acia->write_rxc(state);
}

WRITE8_MEMBER( prophet600_state::dac_w )
{
	if (offset)
	{
		m_dac &= 0xff;
		m_dac |= (data<<8);
		return;
	}

	m_dac &= 0xff00;
	m_dac |= data;
}

// also selects LEDs and keyboard keys to check
WRITE8_MEMBER(prophet600_state::scanrow_w)
{
	m_scanrow = data;
}

// scanrow 0x10 = LEDs, 0x20 = 7-segment #1, 0x40 = 7-segment #2
WRITE8_MEMBER(prophet600_state::led_w)
{
	if (m_scanrow & 0x10)
	{
		// LEDs in row 0x10 are Seq1=0, Seq2=1, ArpUD=2, ArpAssign=3, Preset=4, Record=5, ToTape=6, FromTape=7
	}
	else if (m_scanrow & 0x20)
	{
		m_digits[0] = data;
	}
	else if (m_scanrow & 0x40)
	{
		m_digits[1] = data;
	}
}

READ8_MEMBER(prophet600_state::scan_r)
{
	return 0;
}

WRITE8_MEMBER(prophet600_state::mask_w)
{
	m_nmi_gate = (data & 0x02) ? true : false;
	if (m_nmi_gate) // gate is set, comparitor line is pulled up to Vcc
	{
		m_comparitor |= 0x04;
	}
	else
	{
		m_comparitor &= ~0x04;
	}

//  printf("8253 gate = %x\n", data & 0x02);
}

WRITE8_MEMBER(prophet600_state::cv_w)
{
	int cvnum = data & 7;

	if (!(cvnum & 0x08)) m_CVs[cvnum] = m_dac;
	if (!(cvnum & 0x10)) m_CVs[cvnum+8] = m_dac;
	if (!(cvnum & 0x20)) m_CVs[cvnum+16] = m_dac;
	if (!(cvnum & 0x40)) m_CVs[cvnum+24] = m_dac;
}

WRITE8_MEMBER(prophet600_state::gate_w)
{
	m_ASaw = (data & 0x01);
	m_ATri = (data & 0x02);
	m_Sync = (data & 0x04);
	m_BSaw = (data & 0x08);
	m_BTri = (data & 0x10);
	m_PModFA = (data & 0x20);
	m_PModFil = (data & 0x40);
}

/* Pots: Mixer=0,Cutoff=1,Resonance=2,FilEnvAmt=3,FilRel=4,FilSus=5,
    FilDec=6,FilAtt=7,AmpRel=8,AmpSus=9,AmpDec=10,AmpAtt=11,
    Glide=12,BPW=13,MVol=14,MTune=15,PitchWheel=16,ModWheel=22,
    Speed,APW,PModFilEnv,LFOFreq,PModOscB,LFOAmt,FreqB,FreqA,FreqBFine
*/
WRITE8_MEMBER(prophet600_state::potmux_w)
{
}

READ8_MEMBER(prophet600_state::comparitor_r)
{
//  m_comparitor ^= 0x04;
	return m_comparitor;
}

void prophet600_state::cpu_map(address_map &map)
{
	map(0x0000, 0x1fff).rom().region(MAINCPU_TAG, 0);
	map(0x2000, 0x27ff).ram();
	map(0x3000, 0x37ff).ram();
	map(0x4000, 0x4001).w(FUNC(prophet600_state::dac_w));
	map(0x6000, 0x6001).w(m_acia, FUNC(acia6850_device::write));
	map(0xe000, 0xe001).r(m_acia, FUNC(acia6850_device::read));
}

void prophet600_state::io_map(address_map &map)
{
	map(0x00, 0x07).mirror(0xff00).rw(PIT_TAG, FUNC(pit8253_device::read), FUNC(pit8253_device::write));
	map(0x08, 0x08).mirror(0xff00).w(FUNC(prophet600_state::scanrow_w));
	map(0x09, 0x09).mirror(0xff00).rw(FUNC(prophet600_state::comparitor_r), FUNC(prophet600_state::led_w));
	map(0x0a, 0x0a).mirror(0xff00).rw(FUNC(prophet600_state::scan_r), FUNC(prophet600_state::potmux_w));
	map(0x0b, 0x0b).mirror(0xff00).w(FUNC(prophet600_state::gate_w));
	map(0x0d, 0x0d).mirror(0xff00).w(FUNC(prophet600_state::cv_w));
	map(0x0e, 0x0e).mirror(0xff00).w(FUNC(prophet600_state::mask_w));
}

void prophet600_state::machine_start()
{
	m_digits.resolve();
}

// master crystal is 8 MHz, all clocks derived from there
MACHINE_CONFIG_START(prophet600_state::prophet600)
	MCFG_DEVICE_ADD(MAINCPU_TAG, Z80, XTAL(8'000'000)/2)
	MCFG_DEVICE_PROGRAM_MAP(cpu_map)
	MCFG_DEVICE_IO_MAP(io_map)

	config.set_default_layout(layout_prophet600);

	pit8253_device &pit8253(PIT8253(config, PIT_TAG, XTAL(8'000'000)/4));
	pit8253.set_clk<0>(XTAL(8'000'000)/4);
	pit8253.set_clk<1>(XTAL(8'000'000)/4);
	pit8253.set_clk<2>(XTAL(8'000'000)/4);
	pit8253.out_handler<0>().set(FUNC(prophet600_state::pit_ch0_tick_w));
	pit8253.out_handler<2>().set(FUNC(prophet600_state::pit_ch2_tick_w));

	ACIA6850(config, m_acia, 0);
	m_acia->txd_handler().set("mdout", FUNC(midi_port_device::write_txd));
	m_acia->irq_handler().set(FUNC(prophet600_state::acia_irq_w));

	MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin")
	MCFG_MIDI_RX_HANDLER(WRITELINE(UART_TAG, acia6850_device, write_rxd))

	MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout")

	MCFG_DEVICE_ADD("acia_clock", CLOCK, XTAL(8'000'000)/16)  // 500kHz = 16 times the MIDI rate
	MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(*this, prophet600_state, acia_clock_w))

MACHINE_CONFIG_END

static INPUT_PORTS_START( prophet600 )
INPUT_PORTS_END

ROM_START( prpht600 )
	ROM_REGION(0x2000, MAINCPU_TAG, 0)
	ROM_LOAD( "p600.bin",     0x000000, 0x002000, CRC(78e3f048) SHA1(61548b6de3d9b5c0ae76f8e751ece0b57de17118) )
ROM_END

CONS( 1983, prpht600, 0, 0, prophet600, prophet600, prophet600_state, empty_init, "Sequential Circuits", "Prophet-600", MACHINE_NOT_WORKING|MACHINE_NO_SOUND )