diff --git a/.gitattributes b/.gitattributes index 108445bfb23..b998862313f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -632,6 +632,8 @@ src/emu/machine/intelfsh.c svneol=native#text/plain src/emu/machine/intelfsh.h svneol=native#text/plain src/emu/machine/laserdsc.c svneol=native#text/plain src/emu/machine/laserdsc.h svneol=native#text/plain +src/emu/machine/latch8.c svneol=native#text/plain +src/emu/machine/latch8.h svneol=native#text/plain src/emu/machine/mb3773.c svneol=native#text/plain src/emu/machine/mb3773.h svneol=native#text/plain src/emu/machine/mb87078.c svneol=native#text/plain diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 3caeb4c09d9..e1d5cc79733 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -138,6 +138,7 @@ EMUMACHINEOBJS = \ $(EMUMACHINE)/i2cmem.o \ $(EMUMACHINE)/idectrl.o \ $(EMUMACHINE)/intelfsh.o \ + $(EMUMACHINE)/latch8.o \ $(EMUMACHINE)/laserdsc.o \ $(EMUMACHINE)/mb3773.o \ $(EMUMACHINE)/mb87078.o \ diff --git a/src/emu/machine/latch8.c b/src/emu/machine/latch8.c new file mode 100644 index 00000000000..3668adcbcc2 --- /dev/null +++ b/src/emu/machine/latch8.c @@ -0,0 +1,254 @@ +/********************************************************************** + + 8 bit latch interface and emulation + + 2008/08 couriersud + +**********************************************************************/ + +#include "driver.h" +#include "memconv.h" +#include "sound/discrete.h" +#include "latch8.h" + +typedef struct _latch8_t latch8_t; +struct _latch8_t +{ + latch8_config *intf; + UINT8 value; + UINT8 has_node_map; + UINT8 has_devread; + UINT8 has_read; + const device_config *devices[8]; +}; + +/* ----------------------------------------------------------------------- */ + +INLINE latch8_t *get_safe_token(const device_config *device) { + assert( device != NULL ); + assert( device->token != NULL ); + assert( device->type == LATCH8 ); + return ( latch8_t * ) device->token; +} + + +static TIMER_CALLBACK( latch8_timerproc ) +{ + const device_config *device = ptr; + latch8_t *latch8 = get_safe_token(device); + UINT8 new_val = param & 0xFF; + UINT8 mask = param >> 8; + UINT8 old_val = latch8->value; + + latch8->value = (latch8->value & ~mask) | (new_val & mask); + + if (latch8->has_node_map) + { + int i; + UINT8 changed = old_val ^ latch8->value; + for (i=0; i<8; i++) + if (((changed & (1<intf->node_map[i] != 0) + discrete_sound_w(device->machine, latch8->intf->node_map[i] , (latch8->value >> i) & 1); + } +} + +/* ----------------------------------------------------------------------- */ + +READ8_DEVICE_HANDLER( latch8_r ) +{ + latch8_t *latch8 = get_safe_token(device); + UINT8 res; + + assert(offset == 0); + + res = latch8->value; + if (latch8->has_devread) + { + int i; + for (i=0; i<8; i++) + { + const device_config *read_dev = latch8->devices[i]; + if (read_dev != NULL) + { + res &= ~( 1 << i); + res |= ((latch8->intf->devread[i].devread_handler(read_dev, 0) >> latch8->intf->devread[i].from_bit) & 0x01) << i; + } + } + } + if (latch8->has_read) + { + int i; + for (i=0; i<8; i++) + { + if (latch8->intf->devread[i].read_handler != NULL) + { + res &= ~( 1 << i); + res |= ((latch8->intf->devread[i].read_handler(device->machine, 0) >> latch8->intf->devread[i].from_bit) & 0x01) << i; + } + } + } + + return (res & ~latch8->intf->mask) ^ latch8->intf->xor; +} + + +WRITE8_DEVICE_HANDLER( latch8_w ) +{ + assert(offset == 0); + + timer_call_after_resynch((void *)device, (0xFF << 8) | data, latch8_timerproc); +} + + +WRITE8_DEVICE_HANDLER( latch8_reset) +{ + latch8_t *latch8 = get_safe_token(device); + + assert(offset == 0); + + latch8->value = 0; +} + +/* read bit x */ +/* return (latch >> x) & 0x01 */ + +INLINE UINT8 latch8_bitx_r(const device_config *device, offs_t offset, int bit) +{ + latch8_t *latch8 = get_safe_token(device); + + assert( offset == 0); + + return (latch8->value >> bit) & 0x01; +} + +READ8_DEVICE_HANDLER( latch8_bit0_r) { return latch8_bitx_r(device, offset, 0); } +READ8_DEVICE_HANDLER( latch8_bit1_r) { return latch8_bitx_r(device, offset, 1); } +READ8_DEVICE_HANDLER( latch8_bit2_r) { return latch8_bitx_r(device, offset, 2); } +READ8_DEVICE_HANDLER( latch8_bit3_r) { return latch8_bitx_r(device, offset, 3); } +READ8_DEVICE_HANDLER( latch8_bit4_r) { return latch8_bitx_r(device, offset, 4); } +READ8_DEVICE_HANDLER( latch8_bit5_r) { return latch8_bitx_r(device, offset, 5); } +READ8_DEVICE_HANDLER( latch8_bit6_r) { return latch8_bitx_r(device, offset, 6); } +READ8_DEVICE_HANDLER( latch8_bit7_r) { return latch8_bitx_r(device, offset, 7); } + +READ8_DEVICE_HANDLER( latch8_bit0_q_r) { return latch8_bitx_r(device, offset, 0) ^ 1; } +READ8_DEVICE_HANDLER( latch8_bit1_q_r) { return latch8_bitx_r(device, offset, 1) ^ 1; } +READ8_DEVICE_HANDLER( latch8_bit2_q_r) { return latch8_bitx_r(device, offset, 2) ^ 1; } +READ8_DEVICE_HANDLER( latch8_bit3_q_r) { return latch8_bitx_r(device, offset, 3) ^ 1; } +READ8_DEVICE_HANDLER( latch8_bit4_q_r) { return latch8_bitx_r(device, offset, 4) ^ 1; } +READ8_DEVICE_HANDLER( latch8_bit5_q_r) { return latch8_bitx_r(device, offset, 5) ^ 1; } +READ8_DEVICE_HANDLER( latch8_bit6_q_r) { return latch8_bitx_r(device, offset, 6) ^ 1; } +READ8_DEVICE_HANDLER( latch8_bit7_q_r) { return latch8_bitx_r(device, offset, 7) ^ 1; } + +/* write bit x from data into bit determined by offset */ +/* latch = (latch & ~(1<> x) & 0x01) << offset) */ + +INLINE void latch8_bitx_w(const device_config *device, int bit, offs_t offset, UINT8 data) +{ + UINT8 mask = (1<> bit) & 0x01) << offset); + + assert( offset < 8); + + timer_call_after_resynch((void *) device, (mask << 8) | masked_data, latch8_timerproc); +} + +WRITE8_DEVICE_HANDLER( latch8_bit0_w ) { latch8_bitx_w(device, 0, offset, data); } +WRITE8_DEVICE_HANDLER( latch8_bit1_w ) { latch8_bitx_w(device, 1, offset, data); } +WRITE8_DEVICE_HANDLER( latch8_bit2_w ) { latch8_bitx_w(device, 2, offset, data); } +WRITE8_DEVICE_HANDLER( latch8_bit3_w ) { latch8_bitx_w(device, 3, offset, data); } +WRITE8_DEVICE_HANDLER( latch8_bit4_w ) { latch8_bitx_w(device, 4, offset, data); } +WRITE8_DEVICE_HANDLER( latch8_bit5_w ) { latch8_bitx_w(device, 0, offset, data); } +WRITE8_DEVICE_HANDLER( latch8_bit6_w ) { latch8_bitx_w(device, 0, offset, data); } +WRITE8_DEVICE_HANDLER( latch8_bit7_w ) { latch8_bitx_w(device, 0, offset, data); } + +/* ----------------------------------------------------------------------- */ + +/* device interface */ + +static DEVICE_START( latch8 ) +{ + latch8_t *latch8 = get_safe_token(device); + char unique_tag[30]; + int i; + + /* validate arguments */ + assert(strlen(device->tag) < 20); + + latch8->intf = device->inline_config; + + latch8->value = 0x0; + + /* setup nodemap */ + for (i=0; i<8; i++) + if (latch8->intf->node_map[i] ) + latch8->has_node_map = 1; + + /* setup device read handlers */ + for (i=0; i<8; i++) + if (latch8->intf->devread[i].tag != NULL) + { + if (latch8->devices[i] != NULL) + fatalerror("Device %s: Bit %d already has a handler.\n", device->tag, i); + latch8->devices[i] = devtag_get_device(device->machine, + latch8->intf->devread[i].type, + latch8->intf->devread[i].tag); + if (latch8->devices[i] == NULL) + fatalerror("Device %s: Unable to find device %s\n", device->tag, latch8->intf->devread[i].tag); + latch8->has_devread = 1; + } + + /* setup machine read handlers */ + for (i=0; i<8; i++) + if (latch8->intf->devread[i].read_handler != NULL) + { + if (latch8->devices[i] != NULL) + fatalerror("Device %s: Bit %d already has a handler.\n", device->tag, i); + latch8->has_read = 1; + } + + state_save_combine_module_and_tag(unique_tag, "latch8", device->tag); + + state_save_register_item(unique_tag, 0, latch8->value); +} + + +static DEVICE_RESET( latch8 ) +{ + latch8_t *latch8 = get_safe_token(device); + + latch8->value = 0; +} + + +static DEVICE_SET_INFO( latch8 ) +{ + switch (state) + { + /* no parameters to set */ + } +} + + +DEVICE_GET_INFO( latch8 ) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(latch8_t); break; + case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(latch8_config); break; + case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case DEVINFO_FCT_SET_INFO: info->set_info = DEVICE_SET_INFO_NAME(latch8); break; + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(latch8);break; + case DEVINFO_FCT_STOP: /* Nothing */ break; + case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(latch8);break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: info->s = "8 bit latch"; break; + case DEVINFO_STR_FAMILY: info->s = "Latches"; break; + case DEVINFO_STR_VERSION: info->s = "1.0"; break; + case DEVINFO_STR_SOURCE_FILE: info->s = __FILE__; break; + case DEVINFO_STR_CREDITS: info->s = "Copyright Nicola Salmoria and the MAME Team"; break; + } +} diff --git a/src/emu/machine/latch8.h b/src/emu/machine/latch8.h new file mode 100644 index 00000000000..b3c75cbfcc1 --- /dev/null +++ b/src/emu/machine/latch8.h @@ -0,0 +1,143 @@ +/********************************************************************** + + 8 bit latch interface and emulation + + Generic emulation of 74LS174/175, 74LS259 and other latches. + Apart from providing synched latch operation, these + latches can be configured to read their input bitwise from other + devices as well and individual bits can be connected to + discrete nodes. + + Please see audio/dkong.c for examples. + +**********************************************************************/ + +#ifndef __LATCH8_H_ +#define __LATCH8_H_ + +#define LATCH8 DEVICE_GET_INFO_NAME(latch8) + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _latch8_devread latch8_devread; +struct _latch8_devread +{ + /* only for byte reads, does not affect bit reads and node_map */ + UINT32 from_bit; + device_type type; + const char *tag; + read8_device_func devread_handler; + read8_machine_func read_handler; +}; + +typedef struct _latch8_config latch8_config; +struct _latch8_config +{ + /* only for byte reads, does not affect bit reads and node_map */ + UINT32 mask; + UINT32 xor; /* after mask */ + UINT32 node_map[8]; + latch8_devread devread[8]; +}; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +/* add device */ +#define MDRV_LATCH8_ADD(_tag) \ + MDRV_DEVICE_ADD(_tag, LATCH8) + +/* Bit mask specifying bits to be masked *out* */ +#define MDRV_LATCH8_MASK(_mask) \ + MDRV_DEVICE_CONFIG_DATA32(latch8_config, mask, _mask) + +/* Bit mask specifying bits to be inverted */ +#define MDRV_LATCH8_INVERT(_xor) \ + MDRV_DEVICE_CONFIG_DATA32(latch8_config, xor, _xor) + +/* Write bit to discrete node */ +#define MDRV_LATCH8_DISCRETE_NODE(_bit, _node) \ + MDRV_DEVICE_CONFIG_DATA32(latch8_config, node_map[_bit], _node) + +/* Upon read, replace bits by reading from another device handler */ +#define MDRV_LATCH8_DEVREAD(_bit, _type, _tag, _handler, _from_bit) \ + MDRV_DEVICE_CONFIG_DATA32(latch8_config, devread[_bit].from_bit, _from_bit) \ + MDRV_DEVICE_CONFIG_DATAPTR(latch8_config, devread[_bit].type, _type) \ + MDRV_DEVICE_CONFIG_DATAPTR(latch8_config, devread[_bit].tag, _tag) \ + MDRV_DEVICE_CONFIG_DATAPTR(latch8_config, devread[_bit].devread_handler, _handler) + +/* Upon read, replace bits by reading from another machine handler */ +#define MDRV_LATCH8_READ(_bit, _handler, _from_bit) \ + MDRV_DEVICE_CONFIG_DATA32(latch8_config, devread[_bit].from_bit, _from_bit) \ + MDRV_DEVICE_CONFIG_DATAPTR(latch8_config, devread[_bit].read_handler, _handler) + +/* remove device */ +#define MDRV_LATCH8_REMOVE(_tag) \ + MDRV_DEVICE_REMOVE(LATCH8, _type) + +/* Accessor macros */ + +#define AM_LATCH8_READ(_tag) \ + AM_DEVREAD(LATCH8, _tag, latch8_r) + +#define AM_LATCH8_READBIT(_tag, _bit) \ + AM_DEVREAD(LATCH8, _tag, latch8_bit ## _bit ## _q_r) + +#define AM_LATCH8_WRITE(_tag) \ + AM_DEVWRITE(LATCH8, _tag, latch8_w) + +#define AM_LATCH8_READWRITE(_tag) \ + AM_DEVREADWRITE(LATCH8, _tag, latch8_r, latch8_w) + +/* device interface */ +DEVICE_GET_INFO( latch8 ); + +/* write & read full byte */ + +READ8_DEVICE_HANDLER( latch8_r); +WRITE8_DEVICE_HANDLER( latch8_w); + +/* reset the latch */ + +WRITE8_DEVICE_HANDLER( latch8_reset); + +/* read bit x */ +/* return (latch >> x) & 0x01 */ + +READ8_DEVICE_HANDLER( latch8_bit0_r); +READ8_DEVICE_HANDLER( latch8_bit1_r); +READ8_DEVICE_HANDLER( latch8_bit2_r); +READ8_DEVICE_HANDLER( latch8_bit3_r); +READ8_DEVICE_HANDLER( latch8_bit4_r); +READ8_DEVICE_HANDLER( latch8_bit5_r); +READ8_DEVICE_HANDLER( latch8_bit6_r); +READ8_DEVICE_HANDLER( latch8_bit7_r); + +/* read inverted bit x */ +/* return (latch >> x) & 0x01 */ + +READ8_DEVICE_HANDLER( latch8_bit0_q_r); +READ8_DEVICE_HANDLER( latch8_bit1_q_r); +READ8_DEVICE_HANDLER( latch8_bit2_q_r); +READ8_DEVICE_HANDLER( latch8_bit3_q_r); +READ8_DEVICE_HANDLER( latch8_bit4_q_r); +READ8_DEVICE_HANDLER( latch8_bit5_q_r); +READ8_DEVICE_HANDLER( latch8_bit6_q_r); +READ8_DEVICE_HANDLER( latch8_bit7_q_r); + +/* write bit x from data into bit determined by offset */ +/* latch = (latch & ~(1<> x) & 0x01) << offset) */ + +WRITE8_DEVICE_HANDLER( latch8_bit0_w ); +WRITE8_DEVICE_HANDLER( latch8_bit1_w ); +WRITE8_DEVICE_HANDLER( latch8_bit2_w ); +WRITE8_DEVICE_HANDLER( latch8_bit3_w ); +WRITE8_DEVICE_HANDLER( latch8_bit4_w ); +WRITE8_DEVICE_HANDLER( latch8_bit5_w ); +WRITE8_DEVICE_HANDLER( latch8_bit6_w ); +WRITE8_DEVICE_HANDLER( latch8_bit7_w ); + +#endif /* __LATCH8_H_ */