Skip to content

Commit

Permalink
- New Z80 CPU derivate Toshiba TLCS-Z80 [Felipe Sanches]
Browse files Browse the repository at this point in the history
- Improving emulation of SONY PVE-500 video editing station [Felipe Sanches]
  • Loading branch information
mmicko committed Apr 4, 2014
1 parent 1e8afab commit c82ab8d
Show file tree
Hide file tree
Showing 7 changed files with 413 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ readme svneol=native#text/plain
README svneol=native#text/plain
src/mame/layout/gunnrose.lay svneol=native#text/plain
src/mess/drivers/ymmu100.ppm -text
src/mess/layout/pve500.lay svneol=native#text/plain
5 changes: 3 additions & 2 deletions src/emu/cpu/cpu.mak
Original file line number Diff line number Diff line change
Expand Up @@ -2209,14 +2209,15 @@ $(CPUOBJ)/tlcs900/dasm900.o: $(CPUSRC)/tlcs900/dasm900.c

ifneq ($(filter Z80,$(CPUS)),)
OBJDIRS += $(CPUOBJ)/z80
CPUOBJS += $(CPUOBJ)/z80/z80.o $(CPUOBJ)/z80/z80daisy.o
CPUOBJS += $(CPUOBJ)/z80/z80.o $(CPUOBJ)/z80/tlcs_z80.o $(CPUOBJ)/z80/z80daisy.o
DASMOBJS += $(CPUOBJ)/z80/z80dasm.o
endif

$(CPUOBJ)/z80/z80.o: $(CPUSRC)/z80/z80.c \
$(CPUSRC)/z80/z80.h


$(CPUOBJ)/z80/tlcs_z80.o: $(CPUSRC)/z80/tlcs_z80.c \
$(CPUSRC)/z80/z80.h

#-------------------------------------------------
# Sharp LR35902 (Game Boy CPU)
Expand Down
98 changes: 98 additions & 0 deletions src/emu/cpu/z80/tlcs_z80.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*****************************************************************************
*
* tlcs_z80.c
* TOSHIBA TLCS Z80 emulation
*/

#include "emu.h"
#include "z80.h"
#include "machine/z80ctc.h"
#include "machine/z80pio.h"
#include "machine/z80sio.h"

//TODO: These interfaces should default to DEVCB_NULL pointers and
// the actual callbacks should be provided by the driver that instantiates the TLCS-Z80 CPU.
// We need methods for the driver to provide these interface configurations to the CPU core.
// something like:
// m_tlcsz80->set_internal_ctc_interface (ctc_intf);
// m_tlcsz80->set_internal_pio_interface (pio_intf);
// m_tlcsz80->set_internal_sio_interface (sio_intf);

static Z80CTC_INTERFACE( ctc_intf )
{
DEVCB_CPU_INPUT_LINE(DEVICE_SELF_OWNER, INPUT_LINE_IRQ0), /* interrupt handler */
DEVCB_NULL, /* ZC/TO0 callback */
DEVCB_NULL, /* ZC/TO1 callback */
DEVCB_NULL /* ZC/TO2 callback */
};

static Z80PIO_INTERFACE( pio_intf )
{
DEVCB_CPU_INPUT_LINE(DEVICE_SELF_OWNER, INPUT_LINE_IRQ0),
DEVCB_NULL,
DEVCB_NULL,
DEVCB_NULL,
DEVCB_NULL,
DEVCB_NULL,
DEVCB_NULL
};

static const z80sio_interface sio_intf =
{
DEVCB_CPU_INPUT_LINE(DEVICE_SELF_OWNER, INPUT_LINE_IRQ0), /* interrupt handler */
DEVCB_NULL, /* DTR changed handler */
DEVCB_NULL, /* RTS changed handler */
DEVCB_NULL, /* BREAK changed handler */
DEVCB_NULL, /* transmit handler */
DEVCB_NULL /* receive handler */
};

/* Daisy Chaining */

static const z80_daisy_config tlcsz80_daisy_chain[] =
{
{ TLCSZ80_INTERNAL_CTC_TAG },
{ TLCSZ80_INTERNAL_PIO_TAG },
{ TLCSZ80_INTERNAL_SIO_TAG },
{ NULL }
};

static ADDRESS_MAP_START( tlcs_z80_internal_io_map, AS_IO, 8, tlcs_z80_device )
AM_RANGE(0x10, 0x13) AM_DEVREADWRITE(TLCSZ80_INTERNAL_CTC_TAG, z80ctc_device, read, write)
AM_RANGE(0x18, 0x1B) AM_DEVREADWRITE(TLCSZ80_INTERNAL_SIO_TAG, z80sio_device, read, write)
AM_RANGE(0x1C, 0x1F) AM_DEVREADWRITE(TLCSZ80_INTERNAL_PIO_TAG, z80pio_device, read, write)
// AM_RANGE(0xF0, 0xF0) TODO: Watchdog Timer: Stand-by mode Register
// AM_RANGE(0xF1, 0xF1) TODO: Watchdog Timer: command Register
// AM_RANGE(0xF4, 0xF4) TODO: Daisy chain interrupt precedence Register
ADDRESS_MAP_END

//This is wrong!
//We should use the same clock as declared in the TLCS_Z80 instantiation in the driver that uses it.
#define TLCS_Z80_CLOCK 8000000

static MACHINE_CONFIG_FRAGMENT( tlcs_z80 )
MCFG_Z80CTC_ADD(TLCSZ80_INTERNAL_CTC_TAG, TLCS_Z80_CLOCK, ctc_intf)
MCFG_Z80SIO_ADD(TLCSZ80_INTERNAL_SIO_TAG, TLCS_Z80_CLOCK, sio_intf)
MCFG_Z80PIO_ADD(TLCSZ80_INTERNAL_PIO_TAG, TLCS_Z80_CLOCK, pio_intf)
MACHINE_CONFIG_END

tlcs_z80_device::tlcs_z80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: z80_device(mconfig, TLCS_Z80, "TLCS-Z80", tag, owner, clock, "tlcs_z80", __FILE__),
m_z80ctc(*this, TLCSZ80_INTERNAL_CTC_TAG),
m_io_space_config( "io", ENDIANNESS_LITTLE, 8, 8, 0, ADDRESS_MAP_NAME( tlcs_z80_internal_io_map ) )
{ }


WRITE_LINE_MEMBER( tlcs_z80_device::ctc_trg0 ) { m_z80ctc->trg0(state ? 0 : 1); }
WRITE_LINE_MEMBER( tlcs_z80_device::ctc_trg1 ) { m_z80ctc->trg1(state ? 0 : 1); }
WRITE_LINE_MEMBER( tlcs_z80_device::ctc_trg2 ) { m_z80ctc->trg2(state ? 0 : 1); }
WRITE_LINE_MEMBER( tlcs_z80_device::ctc_trg3 ) { m_z80ctc->trg3(state ? 0 : 1); }


machine_config_constructor tlcs_z80_device::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME( tlcs_z80 );
}

const device_type TLCS_Z80 = &device_creator<tlcs_z80_device>;

35 changes: 35 additions & 0 deletions src/emu/cpu/z80/z80.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
#define __Z80_H__

#include "z80daisy.h"
#include "machine/z80ctc.h"

#define TLCSZ80_INTERNAL_CTC_TAG "tlcsz80_int_ctc"
#define TLCSZ80_INTERNAL_PIO_TAG "tlcsz80_int_pio"
#define TLCSZ80_INTERNAL_SIO_TAG "tlcsz80_int_sio"

enum
{
Expand Down Expand Up @@ -301,4 +306,34 @@ class nsc800_device : public z80_device

extern const device_type NSC800;

class tlcs_z80_device : public z80_device
{
public:
tlcs_z80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32);

required_device<z80ctc_device> m_z80ctc;

DECLARE_WRITE8_MEMBER( ctc_w );
DECLARE_WRITE_LINE_MEMBER( ctc_trg0 );
DECLARE_WRITE_LINE_MEMBER( ctc_trg1 );
DECLARE_WRITE_LINE_MEMBER( ctc_trg2 );
DECLARE_WRITE_LINE_MEMBER( ctc_trg3 );

protected:
virtual machine_config_constructor device_mconfig_additions() const;

const address_space_config m_io_space_config;

const address_space_config *memory_space_config(address_spacenum spacenum) const
{
switch (spacenum)
{
case AS_IO: return &m_io_space_config;
default: return z80_device::memory_space_config(spacenum);
}
}
};

extern const device_type TLCS_Z80;

#endif /* __Z80_H__ */
163 changes: 145 additions & 18 deletions src/mess/drivers/pve500.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@

#include "emu.h"
#include "cpu/z80/z80.h"
#include "machine/z80ctc.h"
#include "machine/z80sio.h"
#include "pve500.lh"

#define IO_EXPANDER_PORTA 0
#define IO_EXPANDER_PORTB 1
#define IO_EXPANDER_PORTC 2
#define IO_EXPANDER_PORTD 3
#define IO_EXPANDER_PORTE 4

class pve500_state : public driver_device
{
Expand All @@ -33,25 +42,62 @@ class pve500_state : public driver_device
, m_subcpu(*this, "subcpu")
{ }

DECLARE_WRITE8_MEMBER(dualport_ram_left_w);
DECLARE_WRITE8_MEMBER(dualport_ram_right_w);
DECLARE_READ8_MEMBER(dualport_ram_left_r);
DECLARE_READ8_MEMBER(dualport_ram_right_r);

DECLARE_WRITE8_MEMBER(io_expander_w);
DECLARE_READ8_MEMBER(io_expander_r);
DECLARE_DRIVER_INIT(pve500);
private:
UINT8 dualport_7FE_data;
UINT8 dualport_7FF_data;

virtual void machine_start();
virtual void machine_reset();
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_subcpu;
required_device<tlcs_z80_device> m_maincpu;
required_device<tlcs_z80_device> m_subcpu;
UINT8 io_SEL, io_LD, io_LE, io_SC, io_KY;
};


static Z80CTC_INTERFACE( external_ctc_intf )
{
DEVCB_NULL, /* interrupt handler */
DEVCB_NULL, /* ZC/TO0 callback */
DEVCB_NULL, /* ZC/TO1 callback */
DEVCB_NULL /* ZC/TO2 callback */
};

static const z80sio_interface external_sio_intf =
{
DEVCB_NULL, /* interrupt handler */
DEVCB_NULL, /* DTR changed handler */
DEVCB_NULL, /* RTS changed handler */
DEVCB_NULL, /* BREAK changed handler */
DEVCB_NULL, /* transmit handler */
DEVCB_NULL /* receive handler */
};

static ADDRESS_MAP_START(maincpu_io, AS_IO, 8, pve500_state)
AM_RANGE(0x00, 0x03) AM_DEVREADWRITE("external_sio", z80sio_device, read, write)
AM_RANGE(0x08, 0x0B) AM_DEVREADWRITE("external_ctc", z80ctc_device, read, write)
ADDRESS_MAP_END

static ADDRESS_MAP_START(maincpu_prg, AS_PROGRAM, 8, pve500_state)
AM_RANGE (0x0000, 0xBFFF) AM_ROM // ICB7: 48kbytes EEPROM
AM_RANGE (0xC000, 0xDFFF) AM_RAM // ICD6: 8kbytes of RAM
AM_RANGE (0xE7FE, 0xE7FE) AM_MIRROR(0x1800) AM_READ(dualport_ram_left_r)
AM_RANGE (0xE7FF, 0xE7FF) AM_MIRROR(0x1800) AM_WRITE(dualport_ram_left_w)
AM_RANGE (0xE000, 0xE7FF) AM_MIRROR(0x1800) AM_RAM AM_SHARE("sharedram") // ICF5: 2kbytes of RAM shared between the two CPUs
ADDRESS_MAP_END

static ADDRESS_MAP_START(subcpu_prg, AS_PROGRAM, 8, pve500_state)
AM_RANGE (0x0000, 0x7FFF) AM_ROM // ICG5: 32kbytes EEPROM
AM_RANGE (0x8000, 0xBFFF) AM_READWRITE(io_expander_r, io_expander_w) // ICG3: I/O Expander
AM_RANGE (0x8000, 0xBFFF) AM_MIRROR(0x3FF8) AM_READWRITE(io_expander_r, io_expander_w) // ICG3: I/O Expander
AM_RANGE (0xC7FE, 0xC7FE) AM_MIRROR(0x1800) AM_WRITE(dualport_ram_right_w)
AM_RANGE (0xC7FF, 0xC7FF) AM_MIRROR(0x1800) AM_READ(dualport_ram_right_r)
AM_RANGE (0xC000, 0xC7FF) AM_MIRROR(0x3800) AM_RAM AM_SHARE("sharedram") // ICF5: 2kbytes of RAM shared between the two CPUs
ADDRESS_MAP_END

Expand All @@ -66,45 +112,126 @@ INPUT_PORTS_END

void pve500_state::machine_start()
{
io_LD = 0;
io_SC = 0;
io_LE = 0;
io_SEL = 0;
io_KY = 0;

for (int i=0; i<27; i++)
output_set_digit_value(i, 0xff);
}

void pve500_state::machine_reset()
{
}

READ8_MEMBER(pve500_state::dualport_ram_left_r)
{
//printf("dualport_ram: Left READ\n");
m_subcpu->ctc_trg1(1); //(INT_Right)
return dualport_7FE_data;
}

WRITE8_MEMBER(pve500_state::dualport_ram_left_w)
{
//printf("dualport_ram: Left WRITE\n");
dualport_7FF_data = data;
m_subcpu->ctc_trg1(0); //(INT_Right)
}

READ8_MEMBER(pve500_state::dualport_ram_right_r)
{
//printf("dualport_ram: Right READ\n");
m_maincpu->ctc_trg1(1); //(INT_Left)
return dualport_7FF_data;
}

WRITE8_MEMBER(pve500_state::dualport_ram_right_w)
{
//printf("dualport_ram: Right WRITE\n");
dualport_7FE_data = data;
m_maincpu->ctc_trg1(0); //(INT_Left)
}

READ8_MEMBER(pve500_state::io_expander_r)
{
/* Implement-me ! */
return 0;
switch (offset){
case IO_EXPANDER_PORTA:
return io_SC;
case IO_EXPANDER_PORTB:
return io_LE;
case IO_EXPANDER_PORTC:
return io_KY;
case IO_EXPANDER_PORTD:
return io_LD;
case IO_EXPANDER_PORTE:
return io_SEL & 0x0F; //This is a 4bit port.
default:
return 0;
}
}

WRITE8_MEMBER(pve500_state::io_expander_w)
{
/* Implement-me !*/
//printf("io_expander_w: offset=%d data=%02X\n", offset, data);
switch (offset){
case IO_EXPANDER_PORTA:
io_SC = data;
break;
case IO_EXPANDER_PORTB:
io_LE = data;
break;
case IO_EXPANDER_PORTC:
io_KY = data;
break;
case IO_EXPANDER_PORTD:
io_LD = data;
break;
case IO_EXPANDER_PORTE:
io_SEL = data;
for (int i=0; i<4; i++){
if (io_SEL & (1 << i)){
switch (io_SC){
case 1: output_set_digit_value(8*i + 0, io_LD & 0x7F); break;
case 2: output_set_digit_value(8*i + 1, io_LD & 0x7F); break;
case 4: output_set_digit_value(8*i + 2, io_LD & 0x7F); break;
case 8: output_set_digit_value(8*i + 3, io_LD & 0x7F); break;
case 16: output_set_digit_value(8*i + 4, io_LD & 0x7F); break;
case 32: output_set_digit_value(8*i + 5, io_LD & 0x7F); break;
case 64: output_set_digit_value(8*i + 6, io_LD & 0x7F); break;
case 128: output_set_digit_value(8*i + 7, io_LD & 0x7F); break;
default:
/*software should not do it.
any idea how to emulate that in case it does? */ break;
}
}
}
break;
default:
break;
}
}

static MACHINE_CONFIG_START( pve500, pve500_state )
/*
I think we should emulate the TOSHIBA TLCS-Z80 and instantiate it here.
TLCS-Z80 = Z80 CPU + internal CTC + internal SIO + some other things
The PVE-500 board uses both the internal and additional external CTCs and SIOs
*/
MCFG_CPU_ADD("maincpu", Z80, XTAL_12MHz / 2) /* Actual chip is TMPZ84C015BF-6 (TOSHIBA TLCS-Z80) */
MCFG_CPU_ADD("maincpu", TLCS_Z80, XTAL_12MHz / 2) /* TMPZ84C015BF-6 (TOSHIBA TLCS-Z80) */
MCFG_CPU_PROGRAM_MAP(maincpu_prg)
// MCFG_Z80CTC_ADD("ctc", XTAL_?MHz, maincpu_ctc_intf)
// MCFG_Z80SIO_ADD("sio", XTAL_12MHz / 2, maincpu_sio_intf)
MCFG_CPU_IO_MAP(maincpu_io)
MCFG_Z80CTC_ADD("external_ctc", XTAL_12MHz / 2, external_ctc_intf)
MCFG_Z80SIO_ADD("external_sio", XTAL_12MHz / 2, external_sio_intf)

MCFG_CPU_ADD("subcpu", Z80, XTAL_12MHz / 2) /* Actual chip is TMPZ84C015BF-6 (TOSHIBA TLCS-Z80) */
MCFG_CPU_ADD("subcpu", TLCS_Z80, XTAL_12MHz / 2) /* TMPZ84C015BF-6 (TOSHIBA TLCS-Z80) */
MCFG_CPU_PROGRAM_MAP(subcpu_prg)
// MCFG_Z80CTC_ADD("ctc", XTAL_?MHz, subcpu_ctc_intf)
// MCFG_Z80SIO_ADD("sio", XTAL_12MHz / 2, subcpu_sio_intf)

/* TODO:
-> There are a few LEDs and a sequence of 7-seg displays with atotal of 27 digits
-> Sound hardware consists of a buzzer connected to a signal of the maincpu SIO and a logic-gate that attaches/detaches it from the
system clock Which apparently means you can only beep the buzzer to a certain predefined tone or keep it mute.
*/

/* video hardware */
MCFG_DEFAULT_LAYOUT(layout_pve500)

MACHINE_CONFIG_END

ROM_START( pve500 )
Expand Down
Loading

0 comments on commit c82ab8d

Please sign in to comment.