summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/imagedev/bitbngr.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/imagedev/bitbngr.c')
-rw-r--r--trunk/src/emu/imagedev/bitbngr.c523
1 files changed, 523 insertions, 0 deletions
diff --git a/trunk/src/emu/imagedev/bitbngr.c b/trunk/src/emu/imagedev/bitbngr.c
new file mode 100644
index 00000000000..9bbef4ecc83
--- /dev/null
+++ b/trunk/src/emu/imagedev/bitbngr.c
@@ -0,0 +1,523 @@
+/*********************************************************************
+
+ bitbngr.c
+
+ TRS style "bitbanger" serial port
+
+*********************************************************************/
+
+#include "emu.h"
+#include "bitbngr.h"
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _bitbanger_token bitbanger_token;
+struct _bitbanger_token
+{
+ emu_timer *bitbanger_output_timer;
+ emu_timer *bitbanger_input_timer;
+ int output_value;
+ int build_count;
+ int build_byte;
+ attotime idle_delay;
+ attotime current_baud;
+ UINT32 input_buffer_size;
+ UINT32 input_buffer_cursor;
+ int mode;
+ int baud;
+ int tune;
+ UINT8 input_buffer[1000];
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static TIMER_CALLBACK(bitbanger_output_timer);
+static TIMER_CALLBACK(bitbanger_input_timer);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+
+/*-------------------------------------------------
+ get_token - safely gets the bitbanger data
+-------------------------------------------------*/
+
+INLINE bitbanger_token *get_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == BITBANGER);
+ return (bitbanger_token *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+/*-------------------------------------------------
+ get_config - safely gets the bitbanger config
+-------------------------------------------------*/
+
+INLINE const bitbanger_config *get_config(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == BITBANGER);
+ return (const bitbanger_config *) device->static_config();
+}
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+
+/*-------------------------------------------------
+ native_output - outputs data to a file
+-------------------------------------------------*/
+
+static void native_output(device_t *bitbanger, UINT8 data)
+{
+ device_image_interface *image = dynamic_cast<device_image_interface *>(bitbanger);
+ if (image->exists())
+ {
+ image->fwrite(&data, 1);
+ }
+}
+
+
+/*-------------------------------------------------
+ native_input - inputs data from a file
+-------------------------------------------------*/
+
+static UINT32 native_input(device_t *bitbanger, void *buffer, UINT32 length)
+{
+ device_image_interface *image = dynamic_cast<device_image_interface *>(bitbanger);
+ if (image->exists())
+ {
+ return image->fread(buffer, length);
+ }
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ bitbanger_mode_string
+-------------------------------------------------*/
+const char *bitbanger_mode_string(device_t *device)
+{
+ bitbanger_token *bi = get_token(device);
+ static const char *const modes[] = {"Printer", "Modem"};
+
+ return(modes[bi->mode]);
+}
+
+
+/*-------------------------------------------------
+ bitbanger_inc_mode
+-------------------------------------------------*/
+bool bitbanger_inc_mode(device_t *device, bool test)
+{
+ bitbanger_token *bi = get_token(device);
+ int adjust_mode = (int)bi->mode + 1;
+
+ if( adjust_mode >= BITBANGER_MODE_MAX )
+ return FALSE;
+
+ if( !test)
+ bi->mode = adjust_mode;
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ bitbanger_dec_mode
+-------------------------------------------------*/
+bool bitbanger_dec_mode(device_t *device, bool test)
+{
+ bitbanger_token *bi = get_token(device);
+ int adjust_mode = bi->mode - 1;
+
+ if( adjust_mode < 0 )
+ return FALSE;
+
+ if( !test)
+ bi->mode = adjust_mode;
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ bitbanger_tune_string
+-------------------------------------------------*/
+const char *bitbanger_tune_string(device_t *device)
+{
+ bitbanger_token *bi = get_token(device);
+ static const char *const tunes[] = {"-2.0%", "-1.75%", "-1.5%", "-1.25%", "-1.0%", "-0.75%", "-0.5", "-0.25%", "\xc2\xb1""0%",
+ "+0.25%", "+0.5%", "+0.75%", "+1.0%", "+1.25%", "+1.5%", "+1.75%", "+2.0%"};
+
+ return(tunes[bi->tune]);
+}
+
+
+/*-------------------------------------------------
+ bitbanger_tune_value
+-------------------------------------------------*/
+static float bitbanger_tune_value(device_t *device)
+{
+ bitbanger_token *bi = get_token(device);
+ static const float tunes[] = {0.97f, 0.9825f, 0.985f, 0.9875f, 0.99f, 0.9925f, 0.995f, 0.9975f, 1.0f,
+ 1.0025f, 1.005f, 1.0075f, 1.01f, 1.0125f, 1.015f, 1.0175f, 1.02f};
+
+ return(tunes[bi->tune]);
+}
+
+
+/*-------------------------------------------------
+ bitbanger_baud_value
+-------------------------------------------------*/
+
+static UINT32 bitbanger_baud_value(device_t *device)
+{
+ bitbanger_token *bi = get_token(device);
+ static const float bauds[] = { 150.0f, 300.0f, 600.0f, 1200.0f, 2400.0f, 4800.0f, 9600.0f,
+ 14400.0f, 28800.0f, 38400.0f, 57600.0f, 115200.0f};
+ float result = bitbanger_tune_value(device) * bauds[bi->baud];
+ return (UINT32)result;
+}
+
+
+/*-------------------------------------------------
+ bitbanger_baud_string
+-------------------------------------------------*/
+
+const char *bitbanger_baud_string(device_t *device)
+{
+ bitbanger_token *bi = get_token(device);
+ static const char *const bauds[] = { "150", "300", "600", "1200", "2400", "4800",
+ "9600", "14400", "28800", "38400", "57600", "115200"};
+
+ return(bauds[bi->baud]);
+}
+
+
+/*-------------------------------------------------
+ bitbanger_inc_baud
+-------------------------------------------------*/
+bool bitbanger_inc_baud(device_t *device, bool test)
+{
+ bitbanger_token *bi = get_token(device);
+ int adjust_baud = (int)bi->baud + 1;
+
+ if( adjust_baud >= BITBANGER_BAUD_MAX )
+ return FALSE;
+
+ if( !test)
+ {
+ bi->baud = adjust_baud;
+ bi->current_baud = attotime::from_hz(bitbanger_baud_value(device));
+ }
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ bitbanger_dec_baud
+-------------------------------------------------*/
+bool bitbanger_dec_baud(device_t *device, bool test)
+{
+ bitbanger_token *bi = get_token(device);
+ int adjust_baud = bi->baud - 1;
+
+ if( adjust_baud < 0 )
+ return FALSE;
+
+ if( !test)
+ {
+ bi->baud = adjust_baud;
+ bi->current_baud = attotime::from_hz(bitbanger_baud_value(device));
+ }
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ bitbanger_inc_tune
+-------------------------------------------------*/
+bool bitbanger_inc_tune(device_t *device, bool test)
+{
+ bitbanger_token *bi = get_token(device);
+ int adjust_tune = (int)bi->tune + 1;
+
+ if( adjust_tune >= BITBANGER_TUNE_MAX )
+ return FALSE;
+
+ if( !test)
+ {
+ bi->tune = adjust_tune;
+ bi->current_baud = attotime::from_hz(bitbanger_baud_value(device));
+ }
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ bitbanger_dec_tune
+-------------------------------------------------*/
+bool bitbanger_dec_tune(device_t *device, bool test)
+{
+ bitbanger_token *bi = get_token(device);
+ int adjust_tune = bi->tune - 1;
+
+ if( adjust_tune < 0 )
+ return FALSE;
+
+ if( !test)
+ {
+ bi->tune = adjust_tune;
+ bi->current_baud = attotime::from_hz(bitbanger_baud_value(device));
+ }
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ bitbanger_bytes_to_bits_81N
+-------------------------------------------------*/
+static void bitbanger_bytes_to_bits_81N(device_t *img)
+{
+ bitbanger_token *bi = get_token(img);
+ UINT8 byte_buffer[100];
+ UINT32 byte_buffer_size, bit_buffer_size;
+ int i, j;
+ static const UINT8 bitmask[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+ bit_buffer_size = 0;
+ byte_buffer_size = native_input(img, byte_buffer, sizeof(byte_buffer));
+
+ /* Translate byte buffer into bit buffer using: 1 start bit, 8 data bits, 1 stop bit, no parity */
+
+ for( i=0; i<byte_buffer_size; i++ )
+ {
+ bi->input_buffer[bit_buffer_size++] = 0;
+
+ for( j=0; j<8; j++ )
+ {
+ if( byte_buffer[i] & bitmask[j] )
+ bi->input_buffer[bit_buffer_size++] = 1;
+ else
+ bi->input_buffer[bit_buffer_size++] = 0;
+ }
+
+ bi->input_buffer[bit_buffer_size++] = 1;
+ }
+
+ bi->input_buffer_size = bit_buffer_size;
+ bi->input_buffer_cursor = 0;
+}
+
+
+/*-------------------------------------------------
+ DEVICE_START(bitbanger)
+-------------------------------------------------*/
+
+static DEVICE_START(bitbanger)
+{
+ bitbanger_token *bi;
+ const bitbanger_config *config = get_config(device);
+
+ bi = get_token(device);
+
+ /* output config */
+ bi->build_count = 0;
+ bi->bitbanger_output_timer = device->machine().scheduler().timer_alloc(FUNC(bitbanger_output_timer), (void *) device);
+
+ /* input config */
+ bi->bitbanger_input_timer = device->machine().scheduler().timer_alloc(FUNC(bitbanger_input_timer), (void *) device );
+ bi->idle_delay = attotime::from_seconds(1);
+ bi->input_buffer_size = 0;
+ bi->input_buffer_cursor = 0;
+
+ bi->mode = config->default_mode;
+ bi->baud = config->default_baud;
+ bi->tune = config->default_tune;
+ bi->current_baud = attotime::from_hz(bitbanger_baud_value(device));
+
+ /* test callback */
+ if(!config->input_callback)
+ fatalerror("Misconfigured bitbanger device: input_callback cannot be NULL\n");
+}
+
+
+/*-------------------------------------------------
+ TIMER_CALLBACK(bitbanger_output_timer)
+-------------------------------------------------*/
+
+static TIMER_CALLBACK(bitbanger_output_timer)
+{
+ device_t *device = (device_t *) ptr;
+ bitbanger_token *bi = get_token(device);
+
+ /* this ia harded coded for 8-1-N */
+ if( bi->output_value )
+ bi->build_byte |= 0x200;
+
+ bi->build_byte >>= 1;
+ bi->build_count--;
+
+ if(bi->build_count == 0)
+ {
+ if( bi->output_value == 1 )
+ native_output( device, bi->build_byte );
+ else
+ logerror("Bitbanger: Output framing error.\n" );
+
+ bi->bitbanger_output_timer->reset();
+ }
+}
+
+
+/*-------------------------------------------------
+ TIMER_CALLBACK(bitbanger_input_timer)
+-------------------------------------------------*/
+
+static TIMER_CALLBACK(bitbanger_input_timer)
+{
+ device_t *device = (device_t *) ptr;
+ bitbanger_token *bi = get_token(device);
+ const bitbanger_config *config = get_config(device);
+
+ if(bi->input_buffer_cursor == bi->input_buffer_size)
+ {
+ /* get more data */
+ bitbanger_bytes_to_bits_81N(device);
+
+ if(bi->input_buffer_size == 0)
+ {
+ /* no more data, wait and try again */
+ bi->idle_delay = min(bi->idle_delay + attotime::from_msec(100), attotime::from_seconds(1));
+ bi->bitbanger_input_timer->adjust(bi->idle_delay);
+
+
+ if( bi->mode == BITBANGER_MODEM )
+ config->input_callback(machine, 1);
+ else
+ config->input_callback(machine, 0);
+
+ return;
+ }
+ else
+ {
+ bi->idle_delay = bi->current_baud;
+ bi->bitbanger_input_timer->adjust(bi->idle_delay, 0, bi->idle_delay);
+ }
+ }
+
+ /* send bit to driver */
+ config->input_callback(machine, bi->input_buffer[(bi->input_buffer_cursor)++]);
+}
+
+
+/*-------------------------------------------------
+ bitbanger_output - outputs data to a bitbanger
+ port
+-------------------------------------------------*/
+
+void bitbanger_output(device_t *device, int value)
+{
+ bitbanger_token *bi = get_token(device);
+ attotime one_point_five_baud;
+
+ if( bi->build_count == 0 && bi->output_value == 1 && value == 0 )
+ {
+ /* we found our start bit */
+ /* eight bits of data, plus one of stop */
+ bi->build_count = 9;
+ bi->build_byte = 0;
+
+ one_point_five_baud = bi->current_baud + bi->current_baud / 2;
+ bi->bitbanger_output_timer->adjust(one_point_five_baud, 0, bi->current_baud);
+ }
+
+ //fprintf(stderr,"%s, %d\n", device->machine().time().as_string(9), value);
+ bi->output_value = value;
+}
+
+
+/*-------------------------------------------------
+ DEVICE_IMAGE_LOAD( bitbanger )
+-------------------------------------------------*/
+
+static DEVICE_IMAGE_LOAD( bitbanger )
+{
+ device_t *device = &image.device();
+ bitbanger_token *bi;
+ bi = get_token(device);
+
+ bi->bitbanger_input_timer->enable(true);
+ bi->bitbanger_input_timer->adjust(attotime::zero, 0, attotime::from_seconds(1));
+
+ /* we don't need to do anything special */
+ return IMAGE_INIT_PASS;
+}
+
+
+/*-------------------------------------------------
+ DEVICE_IMAGE_UNLOAD( bitbanger )
+-------------------------------------------------*/
+
+static DEVICE_IMAGE_UNLOAD( bitbanger )
+{
+ device_t *device = &image.device();
+ bitbanger_token *bi;
+ bi = get_token(device);
+
+ bi->bitbanger_input_timer->enable(false);
+}
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO(bitbanger) - device getinfo
+ function
+-------------------------------------------------*/
+
+DEVICE_GET_INFO(bitbanger)
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(bitbanger_token); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_IMAGE_TYPE: info->i = IO_PRINTER; break;
+ case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
+ case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break;
+ case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(bitbanger); break;
+ case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(bitbanger); break;
+ case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(bitbanger); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Bitbanger"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Bitbanger"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "prn"); break;
+ }
+}
+
+DEFINE_LEGACY_IMAGE_DEVICE(BITBANGER, bitbanger);