summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine/adc083x.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/machine/adc083x.c')
-rw-r--r--src/emu/machine/adc083x.c465
1 files changed, 465 insertions, 0 deletions
diff --git a/src/emu/machine/adc083x.c b/src/emu/machine/adc083x.c
new file mode 100644
index 00000000000..edb9ea9bdea
--- /dev/null
+++ b/src/emu/machine/adc083x.c
@@ -0,0 +1,465 @@
+/*
+ * ADC0831/ADC0832/ADC0834/ADC0838
+ *
+ * 8-Bit Serial I/O A/D Converters with Muliplexer Options
+ *
+ */
+
+#include <stdarg.h>
+#include "driver.h"
+#include "machine/adc083x.h"
+
+#define VERBOSE_LEVEL ( 0 )
+
+INLINE void verboselog( int n_level, 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 );
+ if( cpu_getactivecpu() != -1 )
+ {
+ logerror( "%08x: %s", activecpu_get_pc(), buf );
+ }
+ else
+ {
+ logerror( "(timer) : %s", buf );
+ }
+ }
+}
+
+struct adc083x_chip
+{
+ int type;
+ double (*input_callback)(int input);
+ 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;
+};
+
+#define STATE_IDLE ( 0 )
+#define STATE_WAIT_FOR_START ( 1 )
+#define STATE_SHIFT_MUX ( 2 )
+#define STATE_MUX_SETTLE ( 3 )
+#define STATE_OUTPUT_MSB_FIRST ( 4 )
+#define STATE_WAIT_FOR_SE ( 5 )
+#define STATE_OUTPUT_LSB_FIRST ( 6 )
+#define STATE_FINISHED ( 7 )
+
+static struct adc083x_chip adc083x[ MAX_ADC083X_CHIPS ];
+
+void adc083x_init( int chip, int type, double (*input_callback)(int input) )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_init( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ c->type = type;
+ c->input_callback = input_callback;
+ c->CS = 0;
+ c->CLK = 0;
+ c->DI = 0;
+ c->SE = 0;
+ if( c->type == ADC0834 || c->type == ADC0838 )
+ {
+ c->SARS = 1;
+ }
+ else
+ {
+ c->SARS = 0;
+ }
+ c->DO = 1;
+ c->SGL = 0;
+ c->ODD = 0;
+ c->SEL1 = 0;
+ c->SEL0 = 0;
+ c->state = STATE_IDLE;
+ c->bit = 0;
+ c->output = 0;
+
+ switch( c->type )
+ {
+ case ADC0831:
+ c->mux_bits = 0;
+ break;
+ case ADC0832:
+ c->mux_bits = 2;
+ break;
+ case ADC0834:
+ c->mux_bits = 3;
+ break;
+ case ADC0838:
+ c->mux_bits = 4;
+ break;
+ }
+
+ state_save_register_item( "adc083x", chip, c->CS );
+ state_save_register_item( "adc083x", chip, c->CLK );
+ state_save_register_item( "adc083x", chip, c->DI );
+ state_save_register_item( "adc083x", chip, c->SE );
+ state_save_register_item( "adc083x", chip, c->SARS );
+ state_save_register_item( "adc083x", chip, c->DO );
+ state_save_register_item( "adc083x", chip, c->SGL );
+ state_save_register_item( "adc083x", chip, c->ODD );
+ state_save_register_item( "adc083x", chip, c->SEL1 );
+ state_save_register_item( "adc083x", chip, c->SEL0 );
+ state_save_register_item( "adc083x", chip, c->state );
+ state_save_register_item( "adc083x", chip, c->bit );
+ state_save_register_item( "adc083x", chip, c->output );
+}
+
+void adc083x_cs_write( int chip, int cs )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_cs_write( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ if( c->CS != cs )
+ {
+ verboselog( 2, "adc083x_cs_write( %d, %d )\n", chip, cs );
+ }
+
+ if( c->CS == 0 && cs != 0 )
+ {
+ c->state = STATE_IDLE;
+ if( c->type == ADC0834 || c->type == ADC0838 )
+ {
+ c->SARS = 1;
+ }
+ c->DO = 1;
+ }
+ if( c->CS != 0 && cs == 0 )
+ {
+ if( c->type == ADC0831 )
+ {
+ c->state = STATE_MUX_SETTLE;
+ }
+ else
+ {
+ c->state = STATE_WAIT_FOR_START;
+ }
+ if( c->type == ADC0834 || c->type == ADC0838 )
+ {
+ c->SARS = 1;
+ }
+ c->DO = 1;
+ }
+
+ c->CS = cs;
+}
+
+static int adc083x_conversion( int chip )
+{
+ struct adc083x_chip *c = &adc083x[ chip ];
+ int result;
+ int positive_channel = ADC083X_AGND;
+ int negative_channel = ADC083X_AGND;
+ double positive = 0;
+ double negative = 0;
+ double gnd = c->input_callback( ADC083X_AGND );
+ double vref = c->input_callback( ADC083X_VREF );
+
+ switch( c->type )
+ {
+ case ADC0831:
+ positive_channel = ADC083X_CH0;
+ negative_channel = ADC083X_CH1;
+ break;
+ case ADC0832:
+ positive_channel = ADC083X_CH0 + c->ODD;
+ if( c->SGL == 0 )
+ {
+ negative_channel = positive_channel ^ 1;
+ }
+ else
+ {
+ negative_channel = ADC083X_AGND;
+ }
+ break;
+ case ADC0834:
+ positive_channel = ADC083X_CH0 + c->ODD + ( c->SEL1 * 2 );
+ if( c->SGL == 0 )
+ {
+ negative_channel = positive_channel ^ 1;
+ }
+ else
+ {
+ negative_channel = ADC083X_AGND;
+ }
+ break;
+ case ADC0838:
+ positive_channel = ADC083X_CH0 + c->ODD + ( c->SEL0 * 2 ) + ( c->SEL1 * 4 );
+ if( c->SGL == 0 )
+ {
+ negative_channel = positive_channel ^ 1;
+ }
+ else
+ {
+ negative_channel = ADC083X_COM;
+ }
+ break;
+ }
+
+ if( positive_channel != ADC083X_AGND )
+ {
+ positive = c->input_callback( positive_channel ) - gnd;
+ }
+ if( negative_channel != ADC083X_AGND )
+ {
+ negative = c->input_callback( negative_channel ) - gnd;
+ }
+
+ result = (int)( ( ( positive - negative ) * 255 ) / vref );
+ if( result < 0 )
+ {
+ result = 0;
+ }
+ else if( result > 255 )
+ {
+ result = 255;
+ }
+
+ return result;
+}
+
+void adc083x_clk_write( int chip, int clk )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_clk_write( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ if( c->CLK != clk )
+ {
+ verboselog( 2, "adc083x_clk_write( %d, %d )\n", chip, clk );
+ }
+
+ if( c->CS == 0 )
+ {
+ if( c->CLK == 0 && clk != 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_WAIT_FOR_START:
+ if( c->DI != 0 )
+ {
+ verboselog( 1, "adc083x %d got start bit\n", chip );
+ c->state = STATE_SHIFT_MUX;
+ c->SARS = 0;
+ c->SGL = 0;
+ c->ODD = 0;
+ c->SEL1 = 0;
+ c->SEL0 = 0;
+ c->bit = 0;
+ }
+ else
+ {
+ verboselog( 1, "adc083x %d not start bit\n", chip );
+ }
+ break;
+ case STATE_SHIFT_MUX:
+ switch( c->bit )
+ {
+ case 0:
+ if( c->DI != 0 )
+ {
+ c->SGL = 1;
+ }
+ verboselog( 1, "adc083x %d SGL <- %d\n", chip, c->SGL );
+ break;
+ case 1:
+ if( c->DI != 0 )
+ {
+ c->ODD = 1;
+ }
+ verboselog( 1, "adc083x %d ODD <- %d\n", chip, c->ODD );
+ break;
+ case 2:
+ if( c->DI != 0 )
+ {
+ c->SEL1 = 1;
+ }
+ verboselog( 1, "adc083x %d SEL1 <- %d\n", chip, c->SEL1 );
+ break;
+ case 3:
+ if( c->DI != 0 )
+ {
+ c->SEL0 = 1;
+ }
+ verboselog( 1, "adc083x %d SEL0 <- %d\n", chip, c->SEL0 );
+ break;
+ }
+ c->bit++;
+ if( c->bit == c->mux_bits )
+ {
+ c->state = STATE_MUX_SETTLE;
+ }
+ break;
+ case STATE_WAIT_FOR_SE:
+ c->SARS = 0;
+ if( c->type == ADC0838 && c->SE != 0 )
+ {
+ verboselog( 1, "adc083x %d not SE\n", chip );
+ }
+ else
+ {
+ verboselog( 1, "adc083x %d got SE\n", chip );
+ c->state = STATE_OUTPUT_LSB_FIRST;
+ c->bit = 1;
+ }
+ break;
+ }
+ }
+ if( c->CLK != 0 && clk == 0 )
+ {
+ switch( c->state )
+ {
+ case STATE_MUX_SETTLE:
+ verboselog( 1, "adc083x %d mux settle\n", chip );
+ c->output = adc083x_conversion( chip );
+ c->state = STATE_OUTPUT_MSB_FIRST;
+ c->bit = 7;
+ if( c->type == ADC0834 || c->type == ADC0838 )
+ {
+ c->SARS = 1;
+ }
+ c->DO = 0;
+ break;
+ case STATE_OUTPUT_MSB_FIRST:
+ c->DO = ( c->output >> c->bit ) & 1;
+ verboselog( 1, "adc083x %d msb %d -> %d\n", chip, c->bit, c->DO );
+ c->bit--;
+ if( c->bit < 0 )
+ {
+ if( c->type == ADC0831 )
+ {
+ c->state = STATE_FINISHED;
+ }
+ else
+ {
+ c->state = STATE_WAIT_FOR_SE;
+ }
+ }
+ break;
+ case STATE_OUTPUT_LSB_FIRST:
+ c->DO = ( c->output >> c->bit ) & 1;
+ verboselog( 1, "adc083x %d lsb %d -> %d\n", chip, c->bit, c->DO );
+ c->bit++;
+ if( c->bit == 8 )
+ {
+ c->state = STATE_FINISHED;
+ }
+ break;
+ case STATE_FINISHED:
+ c->state = STATE_IDLE;
+ c->DO = 0;
+ break;
+ }
+ }
+ }
+
+ c->CLK = clk;
+}
+
+void adc083x_di_write( int chip, int di )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_di_write( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ if( c->DI != di )
+ {
+ verboselog( 2, "adc083x_di_write( %d, %d )\n", chip, di );
+ }
+
+ c->DI = di;
+}
+
+void adc083x_se_write( int chip, int se )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_se_write( %d ) chip %d out of range\n", chip );
+ return;
+ }
+
+ c = &adc083x[ chip ];
+
+ if( c->SE != se )
+ {
+ verboselog( 2, "adc083x_se_write( %d, %d )\n", chip, se );
+ }
+
+ c->SE = se;
+}
+
+int adc083x_sars_read( int chip )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_sars_read( %d ) chip %d out of range\n", chip );
+ return 0;
+ }
+
+ c = &adc083x[ chip ];
+
+ verboselog( 1, "adc083x_sars_read( %d ) %d\n", chip, c->SARS );
+ return c->SARS;
+}
+
+int adc083x_do_read( int chip )
+{
+ struct adc083x_chip *c;
+
+ if( chip >= MAX_ADC083X_CHIPS )
+ {
+ verboselog( 0, "adc083x_do_read( %d ) chip %d out of range\n", chip );
+ return 0;
+ }
+
+ c = &adc083x[ chip ];
+
+ verboselog( 1, "adc083x_do_read( %d ) %d\n", chip, c->DO );
+ return c->DO;
+}