summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/upd7002.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/machine/upd7002.c')
-rw-r--r--src/mess/machine/upd7002.c234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/mess/machine/upd7002.c b/src/mess/machine/upd7002.c
new file mode 100644
index 00000000000..5b753ac9231
--- /dev/null
+++ b/src/mess/machine/upd7002.c
@@ -0,0 +1,234 @@
+/******************************************************************************
+ uPD7002 Analogue to Digital Converter
+
+ MESS Driver By:
+
+ Gordon Jefferyes
+ mess_bbc@gjeffery.dircon.co.uk
+
+******************************************************************************/
+
+#include "emu.h"
+#include "upd7002.h"
+
+
+typedef struct _uPD7002_t uPD7002_t;
+struct _uPD7002_t
+{
+ /* Pointer to our interface */
+ const uPD7002_interface *intf;
+
+ /* Status Register
+ D0 and D1 define the currently selected input channel
+ D2 flag output
+ D3 0 = 8 bit mode 1 = 12 bit mode
+ D4 2nd MSB of conversion
+ D5 MSB of conversion
+ D6 0 = busy, 1 = not busy (~busy)
+ D7 0 = conversion completed, 1 = conversion not completed (~EOC)
+ */
+ int status;
+
+ /* High data byte
+ This byte contains the 8 most significant bits of the analogue to digital conversion. */
+ int data1;
+
+ /* Low data byte
+ In 12 bit mode: Bits 7 to 4 define the four low order bits of the conversion.
+ In 8 bit mode. All bits 7 to 4 are inaccurate.
+ Bits 3 to 0 are always set to low. */
+ int data0;
+
+
+ /* temporary store of the next A to D conversion */
+ int digitalvalue;
+
+ /* this counter is used to check a full end of conversion has been reached
+ if the uPD7002 is half way through one conversion and a new conversion is requested
+ the counter at the end of the first conversion will not match and not be processed
+ only then at the end of the second conversion will the conversion complete function run */
+ int conversion_counter;
+};
+
+
+/*****************************************************************************
+ Implementation
+*****************************************************************************/
+
+INLINE uPD7002_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == UPD7002);
+
+ return (uPD7002_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+READ8_DEVICE_HANDLER ( uPD7002_EOC_r )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ return (uPD7002->status>>7)&0x01;
+}
+
+
+static TIMER_CALLBACK(uPD7002_conversioncomplete)
+{
+ device_t *device = (device_t *)ptr;
+ uPD7002_t *uPD7002 = get_safe_token(device);
+
+ int counter_value = param;
+ if (counter_value==uPD7002->conversion_counter)
+ {
+ // this really always does a 12 bit conversion
+ uPD7002->data1 = uPD7002->digitalvalue>>8;
+ uPD7002->data0 = uPD7002->digitalvalue&0xf0;
+
+ // set the status register with top 2 MSB, not busy and conversion complete
+ uPD7002->status = (uPD7002->status & 0x0f)|((uPD7002->data1 & 0xc0)>>2)|0x40;
+
+ // call the EOC function with EOC from status
+ // uPD7002_EOC_r(0) this has just been set to 0
+ if (uPD7002->intf->EOC_func) (uPD7002->intf->EOC_func)(device,0);
+ uPD7002->conversion_counter=0;
+ }
+}
+
+
+READ8_DEVICE_HANDLER ( uPD7002_r )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+
+ switch(offset&0x03)
+ {
+ case 0:
+ return uPD7002->status;
+
+ case 1:
+ return uPD7002->data1;
+
+ case 2: case 3:
+ return uPD7002->data0;
+ }
+ return 0;
+}
+
+
+
+WRITE8_DEVICE_HANDLER ( uPD7002_w )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ /* logerror("write to uPD7002 $%02X = $%02X\n",offset,data); */
+
+ switch(offset&0x03)
+ {
+ case 0:
+ /*
+ Data Latch/AD start
+ D0 and D1 together define which one of the four input channels is selected
+ D2 flag input, normally set to 0????
+ D3 defines whether an 8 (0) or 12 (1) bit resolution conversion should occur
+ D4 to D7 not used.
+
+ an 8 bit conversion typically takes 4ms
+ an 12 bit conversion typically takes 10ms
+
+ writing to this register will initiate a conversion.
+ */
+
+ /* set D6=0 busy ,D7=1 conversion not complete */
+ uPD7002->status=(data & 0x0f) | 0x80;
+
+ // call the EOC function with EOC from status
+ // uPD7002_EOC_r(0) this has just been set to 1
+ if (uPD7002->intf->EOC_func) uPD7002->intf->EOC_func(device, 1);
+
+ /* the uPD7002 works by sampling the analogue value at the start of the conversion
+ so it is read hear and stored until the end of the A to D conversion */
+
+ // this function should return a 16 bit value.
+ uPD7002->digitalvalue = uPD7002->intf->get_analogue_func(device, uPD7002->status & 0x03);
+
+ uPD7002->conversion_counter++;
+
+ // call a timer to start the conversion
+ if (uPD7002->status & 0x08)
+ {
+ // 12 bit conversion takes 10ms
+ device->machine().scheduler().timer_set(attotime::from_msec(10), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device);
+ } else {
+ // 8 bit conversion takes 4ms
+ device->machine().scheduler().timer_set(attotime::from_msec(4), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device);
+ }
+ break;
+
+ case 1: case 2:
+ /* Nothing */
+ break;
+
+ case 3:
+ /* Test Mode: Used for inspecting the device, The data input-output terminals assume an input
+ state and are connected to the A/D counter. Therefore, the A/D conversion data
+ read out after this is meaningless.
+ */
+ break;
+ }
+}
+
+/* Device Interface */
+
+static DEVICE_START( uPD7002 )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ // validate arguments
+
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+ assert(device->static_config() != NULL);
+
+ uPD7002->intf = (const uPD7002_interface*)device->static_config();
+ uPD7002->status = 0;
+ uPD7002->data1 = 0;
+ uPD7002->data0 = 0;
+ uPD7002->digitalvalue = 0;
+ uPD7002->conversion_counter = 0;
+
+ // register for state saving
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->status);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data1);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data0);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->digitalvalue);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->conversion_counter);
+}
+
+static DEVICE_RESET( uPD7002 )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ uPD7002->status = 0;
+ uPD7002->data1 = 0;
+ uPD7002->data0 = 0;
+ uPD7002->digitalvalue = 0;
+ uPD7002->conversion_counter = 0;
+}
+
+DEVICE_GET_INFO( uPD7002 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(uPD7002_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(uPD7002); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(uPD7002); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "uPD7002"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "uPD7002"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(UPD7002, uPD7002);