diff options
Diffstat (limited to 'trunk/src/emu/machine/adc083x.c')
-rw-r--r-- | trunk/src/emu/machine/adc083x.c | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/adc083x.c b/trunk/src/emu/machine/adc083x.c new file mode 100644 index 00000000000..aab3d868600 --- /dev/null +++ b/trunk/src/emu/machine/adc083x.c @@ -0,0 +1,539 @@ +/*************************************************************************** + + National Semiconductor ADC0831 / ADC0832 / ADC0834 / ADC0838 + + 8-Bit serial I/O A/D Converters with Muliplexer Options + +***************************************************************************/ + +#include "emu.h" +#include "adc083x.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF( 3, 4 ) verboselog( int n_level, running_machine &machine, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context( ), buf ); + } +} + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +enum +{ + STATE_IDLE, + STATE_WAIT_FOR_START, + STATE_SHIFT_MUX, + STATE_MUX_SETTLE, + STATE_OUTPUT_MSB_FIRST, + STATE_WAIT_FOR_SE, + STATE_OUTPUT_LSB_FIRST, + STATE_FINISHED +}; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _adc0831_state adc0831_state; +struct _adc0831_state +{ + adc083x_input_convert_func input_callback_r; + + INT32 cs; + INT32 clk; + INT32 di; + INT32 se; + INT32 sars; + INT32 _do; + INT32 sgl; + INT32 odd; + INT32 sel1; + INT32 sel0; + INT32 state; + INT32 bit; + INT32 output; + INT32 mux_bits; +}; + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +INLINE adc0831_state *get_safe_token( device_t *device ) +{ + assert( device != NULL ); + assert( ( device->type() == ADC0831 ) || ( device->type() == ADC0832 ) || ( device->type() == ADC0834 ) || ( device->type() == ADC0838 ) ); + return (adc0831_state *) downcast<legacy_device_base *>(device)->token(); +} + +INLINE const adc083x_interface *get_interface( device_t *device ) +{ + assert( device != NULL ); + assert( ( device->type() == ADC0831 ) || ( device->type() == ADC0832 ) || ( device->type() == ADC0834 ) || ( device->type() == ADC0838 ) ); + return (const adc083x_interface *) device->static_config(); +} + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +/*------------------------------------------------- + adc083x_clear_sars +-------------------------------------------------*/ + +static void adc083x_clear_sars( device_t *device, adc0831_state *adc083x ) +{ + if( device->type() == ADC0834 ||device->type() == ADC0838 ) + { + adc083x->sars = 1; + } + else + { + adc083x->sars = 0; + } +} + +/*------------------------------------------------- + adc083x_cs_write +-------------------------------------------------*/ + +WRITE_LINE_DEVICE_HANDLER( adc083x_cs_write ) +{ + adc0831_state *adc083x = get_safe_token( device ); + + if( adc083x->cs != state ) + { + verboselog( 2, device->machine(), "adc083x_cs_write( %s, %d )\n", device->tag(), state ); + } + + if( adc083x->cs == 0 && state != 0 ) + { + adc083x->state = STATE_IDLE; + adc083x_clear_sars( device, adc083x ); + adc083x->_do = 1; + } + + if( adc083x->cs != 0 && state == 0 ) + { + if( device->type() == ADC0831 ) + { + adc083x->state = STATE_MUX_SETTLE; + } + else + { + adc083x->state = STATE_WAIT_FOR_START; + } + + adc083x_clear_sars( device, adc083x ); + adc083x->_do = 1; + } + + adc083x->cs = state; +} + +/*------------------------------------------------- + adc083x_conversion +-------------------------------------------------*/ + +static UINT8 adc083x_conversion( device_t *device ) +{ + adc0831_state *adc083x = get_safe_token( device ); + int result; + int positive_channel = ADC083X_AGND; + int negative_channel = ADC083X_AGND; + double positive = 0; + double negative = 0; + double gnd = adc083x->input_callback_r( device, ADC083X_AGND ); + double vref = adc083x->input_callback_r( device, ADC083X_VREF ); + + if( device->type() == ADC0831 ) + { + positive_channel = ADC083X_CH0; + negative_channel = ADC083X_CH1; + } + else if( device->type() == ADC0832 ) + { + positive_channel = ADC083X_CH0 + adc083x->odd; + if( adc083x->sgl == 0 ) + { + negative_channel = positive_channel ^ 1; + } + else + { + negative_channel = ADC083X_AGND; + } + } + else if( device->type() == ADC0834 ) + { + positive_channel = ADC083X_CH0 + adc083x->odd + ( adc083x->sel1 * 2 ); + if( adc083x->sgl == 0 ) + { + negative_channel = positive_channel ^ 1; + } + else + { + negative_channel = ADC083X_AGND; + } + } + else if( device->type() == ADC0838 ) + { + positive_channel = ADC083X_CH0 + adc083x->odd + ( adc083x->sel0 * 2 ) + ( adc083x->sel1 * 4 ); + if( adc083x->sgl == 0 ) + { + negative_channel = positive_channel ^ 1; + } + else + { + negative_channel = ADC083X_COM; + } + } + + if( positive_channel != ADC083X_AGND ) + { + positive = adc083x->input_callback_r( device, positive_channel ) - gnd; + } + + if( negative_channel != ADC083X_AGND ) + { + negative = adc083x->input_callback_r( device, negative_channel ) - gnd; + } + + result = (int) ( ( ( positive - negative ) * 255 ) / vref ); + if( result < 0 ) + { + result = 0; + } + else if( result > 255 ) + { + result = 255; + } + + return result; +} + +/*------------------------------------------------- + adc083x_clk_write +-------------------------------------------------*/ + +WRITE_LINE_DEVICE_HANDLER( adc083x_clk_write ) +{ + adc0831_state *adc083x = get_safe_token( device ); + + if( adc083x->clk != state ) + { + verboselog( 2, device->machine(), "adc083x_clk_write( %s, %d )\n", device->tag(), state ); + } + + if( adc083x->cs == 0 ) + { + if( adc083x->clk == 0 && state != 0 ) + { + switch( adc083x->state ) + { + case STATE_WAIT_FOR_START: + if( adc083x->di != 0 ) + { + verboselog( 1, device->machine(), "adc083x %s got start bit\n", device->tag() ); + adc083x->state = STATE_SHIFT_MUX; + adc083x->sars = 0; + adc083x->sgl = 0; + adc083x->odd = 0; + adc083x->sel1 = 0; + adc083x->sel0 = 0; + adc083x->bit = 0; + } + else + { + verboselog( 1, device->machine(), "adc083x %s not start bit\n", device->tag() ); + } + break; + + case STATE_SHIFT_MUX: + switch( adc083x->bit ) + { + case 0: + if( adc083x->di != 0 ) + { + adc083x->sgl = 1; + } + verboselog( 1, device->machine(), "adc083x %s sgl <- %d\n", device->tag(), adc083x->sgl ); + break; + + case 1: + if( adc083x->di != 0 ) + { + adc083x->odd = 1; + } + verboselog( 1, device->machine(), "adc083x %s odd <- %d\n", device->tag(), adc083x->odd ); + break; + + case 2: + if( adc083x->di != 0 ) + { + adc083x->sel1 = 1; + } + verboselog( 1, device->machine(), "adc083x %s sel1 <- %d\n", device->tag(), adc083x->sel1 ); + break; + + case 3: + if( adc083x->di != 0 ) + { + adc083x->sel0 = 1; + } + verboselog( 1, device->machine(), "adc083x %s sel0 <- %d\n", device->tag(), adc083x->sel0 ); + break; + } + + adc083x->bit++; + if( adc083x->bit == adc083x->mux_bits ) + { + adc083x->state = STATE_MUX_SETTLE; + } + + break; + + case STATE_WAIT_FOR_SE: + adc083x->sars = 0; + if( device->type() == ADC0838 && adc083x->se != 0 ) + { + verboselog( 1, device->machine(), "adc083x %s not se\n", device->tag() ); + } + else + { + verboselog( 1, device->machine(), "adc083x %s got se\n", device->tag() ); + adc083x->state = STATE_OUTPUT_LSB_FIRST; + adc083x->bit = 1; + } + break; + } + } + + if( adc083x->clk != 0 && state == 0 ) + { + switch( adc083x->state ) + { + case STATE_MUX_SETTLE: + verboselog( 1, device->machine(), "adc083x %s mux settle\n", device->tag() ); + adc083x->output = adc083x_conversion( device ); + adc083x->state = STATE_OUTPUT_MSB_FIRST; + adc083x->bit = 7; + adc083x_clear_sars( device, adc083x ); + adc083x->_do = 0; + break; + + case STATE_OUTPUT_MSB_FIRST: + adc083x->_do = ( adc083x->output >> adc083x->bit ) & 1; + verboselog( 1, device->machine(), "adc083x %s msb %d -> %d\n", device->tag(), adc083x->bit, adc083x->_do ); + + adc083x->bit--; + if( adc083x->bit < 0 ) + { + if( device->type() == ADC0831 ) + { + adc083x->state = STATE_FINISHED; + } + else + { + adc083x->state = STATE_WAIT_FOR_SE; + } + } + break; + + case STATE_OUTPUT_LSB_FIRST: + adc083x->_do = ( adc083x->output >> adc083x->bit ) & 1; + verboselog( 1, device->machine(), "adc083x %s lsb %d -> %d\n", device->tag(), adc083x->bit, adc083x->_do ); + + adc083x->bit++; + if( adc083x->bit == 8 ) + { + adc083x->state = STATE_FINISHED; + } + break; + + case STATE_FINISHED: + adc083x->state = STATE_IDLE; + adc083x->_do = 0; + break; + } + } + } + + adc083x->clk = state; +} + +/*------------------------------------------------- + adc083x_di_write +-------------------------------------------------*/ + +WRITE_LINE_DEVICE_HANDLER( adc083x_di_write ) +{ + adc0831_state *adc083x = get_safe_token( device ); + + if( adc083x->di != state ) + { + verboselog( 2, device->machine(), "adc083x_di_write( %s, %d )\n", device->tag(), state ); + } + + adc083x->di = state; +} + +/*------------------------------------------------- + adc083x_se_write +-------------------------------------------------*/ + +WRITE_LINE_DEVICE_HANDLER( adc083x_se_write ) +{ + adc0831_state *adc083x = get_safe_token( device ); + + if( adc083x->se != state ) + { + verboselog( 2, device->machine(), "adc083x_se_write( %s, %d )\n", device->tag(), state ); + } + + adc083x->se = state; +} + +/*------------------------------------------------- + adc083x_sars_read +-------------------------------------------------*/ + +READ_LINE_DEVICE_HANDLER( adc083x_sars_read ) +{ + adc0831_state *adc083x = get_safe_token( device ); + + verboselog( 1, device->machine(), "adc083x_sars_read( %s ) %d\n", device->tag(), adc083x->sars ); + return adc083x->sars; +} + +/*------------------------------------------------- + adc083x_do_read +-------------------------------------------------*/ + +READ_LINE_DEVICE_HANDLER( adc083x_do_read ) +{ + adc0831_state *adc083x = get_safe_token( device ); + + verboselog( 1, device->machine(), "adc083x_do_read( %s ) %d\n", device->tag(), adc083x->_do ); + return adc083x->_do; +} + + +/*------------------------------------------------- + DEVICE_START( adc083x ) +-------------------------------------------------*/ + +static DEVICE_START( adc0831 ) +{ + adc0831_state *adc083x = get_safe_token( device ); + const adc083x_interface *intf = get_interface( device ); + + adc083x->cs = 0; + adc083x->clk = 0; + adc083x->di = 0; + adc083x->se = 0; + adc083x_clear_sars( device, adc083x ); + adc083x->_do = 1; + adc083x->sgl = 0; + adc083x->odd = 0; + adc083x->sel1 = 0; + adc083x->sel0 = 0; + adc083x->state = STATE_IDLE; + adc083x->bit = 0; + adc083x->output = 0; + + if( device->type() == ADC0831 ) + { + adc083x->mux_bits = 0; + } + else if( device->type() == ADC0832 ) + { + adc083x->mux_bits = 2; + } + else if( device->type() == ADC0834 ) + { + adc083x->mux_bits = 3; + } + else if( device->type() == ADC0838 ) + { + adc083x->mux_bits = 4; + } + + /* resolve callbacks */ + adc083x->input_callback_r = intf->input_callback_r; + + /* register for state saving */ + device->save_item( NAME(adc083x->cs) ); + device->save_item( NAME(adc083x->clk) ); + device->save_item( NAME(adc083x->di) ); + device->save_item( NAME(adc083x->se) ); + device->save_item( NAME(adc083x->sars) ); + device->save_item( NAME(adc083x->_do) ); + device->save_item( NAME(adc083x->sgl) ); + device->save_item( NAME(adc083x->odd) ); + device->save_item( NAME(adc083x->sel1) ); + device->save_item( NAME(adc083x->sel0) ); + device->save_item( NAME(adc083x->state) ); + device->save_item( NAME(adc083x->bit) ); + device->save_item( NAME(adc083x->output) ); + device->save_item( NAME(adc083x->mux_bits) ); +} + + +/*------------------------------------------------- + DEVICE_RESET( adc083x ) +-------------------------------------------------*/ + +static DEVICE_RESET( adc0831 ) +{ + adc0831_state *adc083x = get_safe_token( device ); + + adc083x_clear_sars( device, adc083x ); + adc083x->_do = 1; + adc083x->state = STATE_IDLE; +} + +/*------------------------------------------------- + device definition +-------------------------------------------------*/ + +static const char DEVTEMPLATE_SOURCE[] = __FILE__; + +#define DEVTEMPLATE_ID( p, s ) p##adc0831##s +#define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET +#define DEVTEMPLATE_NAME "A/D Converters 0831" +#define DEVTEMPLATE_FAMILY "National Semiconductor A/D Converters 083x" +#include "devtempl.h" + +#define DEVTEMPLATE_DERIVED_ID( p, s ) p##adc0832##s +#define DEVTEMPLATE_DERIVED_FEATURES 0 +#define DEVTEMPLATE_DERIVED_NAME "A/D Converters 0832" +#include "devtempl.h" + +#define DEVTEMPLATE_DERIVED_ID( p, s ) p##adc0834##s +#define DEVTEMPLATE_DERIVED_FEATURES 0 +#define DEVTEMPLATE_DERIVED_NAME "A/D Converters 0834" +#include "devtempl.h" + +#define DEVTEMPLATE_DERIVED_ID( p, s ) p##adc0838##s +#define DEVTEMPLATE_DERIVED_FEATURES 0 +#define DEVTEMPLATE_DERIVED_NAME "A/D Converters 0838" +#include "devtempl.h" + + +DEFINE_LEGACY_DEVICE(ADC0831, adc0831); +DEFINE_LEGACY_DEVICE(ADC0832, adc0832); +DEFINE_LEGACY_DEVICE(ADC0834, adc0834); +DEFINE_LEGACY_DEVICE(ADC0838, adc0838); |