diff options
Diffstat (limited to 'trunk/src/emu/imagedev/bitbngr.c')
-rw-r--r-- | trunk/src/emu/imagedev/bitbngr.c | 500 |
1 files changed, 500 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..23ec4779caa --- /dev/null +++ b/trunk/src/emu/imagedev/bitbngr.c @@ -0,0 +1,500 @@ +/********************************************************************* + + bitbngr.c + + TRS style "bitbanger" serial port + +*********************************************************************/ + +#include "emu.h" +#include "bitbngr.h" + + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +const device_type BITBANGER = &device_creator<bitbanger_device>; + +/*------------------------------------------------- + ctor +-------------------------------------------------*/ + +bitbanger_device::bitbanger_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, BITBANGER, "Bitbanger", tag, owner, clock), + device_image_interface(mconfig, *this) +{ + m_output_timer = NULL; + m_input_timer = NULL; + m_output_value = 0; + m_build_count = 0; + m_build_byte = 0; + m_idle_delay = attotime::zero; + m_current_baud = attotime::zero; + m_input_buffer_size = 0; + m_input_buffer_cursor = 0; + m_mode = 0; + m_baud = 0; + m_tune = 0; + m_current_input = 0; + memset(m_input_buffer, 0, sizeof(m_input_buffer)); +} + + + +/*------------------------------------------------- + native_output - outputs data to a file +-------------------------------------------------*/ + +void bitbanger_device::native_output(UINT8 data) +{ + if (exists()) + { + fwrite(&data, 1); + } +} + + +/*------------------------------------------------- + native_input - inputs data from a file +-------------------------------------------------*/ + +UINT32 bitbanger_device::native_input(void *buffer, UINT32 length) +{ + if (exists()) + { + return fread(buffer, length); + } + return 0; +} + + + +/*------------------------------------------------- + mode_string +-------------------------------------------------*/ + +const char *bitbanger_device::mode_string(void) +{ + static const char *const modes[] = {"Printer", "Modem"}; + return modes[m_mode]; +} + + + +/*------------------------------------------------- + inc_mode +-------------------------------------------------*/ + +bool bitbanger_device::inc_mode(bool test) +{ + int adjust_mode = (int)m_mode + 1; + + if( adjust_mode >= BITBANGER_MODE_MAX ) + return FALSE; + + if( !test) + m_mode = adjust_mode; + + return TRUE; +} + + + +/*------------------------------------------------- + dec_mode +-------------------------------------------------*/ + +bool bitbanger_device::dec_mode(bool test) +{ + int adjust_mode = m_mode - 1; + + if( adjust_mode < 0 ) + return FALSE; + + if( !test) + m_mode = adjust_mode; + + return TRUE; +} + + + +/*------------------------------------------------- + tune_string +-------------------------------------------------*/ + +const char *bitbanger_device::tune_string(void) +{ + 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[m_tune]; +} + + + +/*------------------------------------------------- + tune_value +-------------------------------------------------*/ + +float bitbanger_device::tune_value(void) +{ + 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[m_tune]; +} + + + +/*------------------------------------------------- + baud_value +-------------------------------------------------*/ + +UINT32 bitbanger_device::baud_value(void) +{ + static const float bauds[] = { 150.0f, 300.0f, 600.0f, 1200.0f, 2400.0f, 4800.0f, 9600.0f, + 14400.0f, 19200.0f, 28800.0f, 38400.0f, 57600.0f, 115200.0f}; + float result = tune_value() * bauds[m_baud]; + return (UINT32)result; +} + + +/*------------------------------------------------- + baud_string +-------------------------------------------------*/ + +const char *bitbanger_device::baud_string(void) +{ + static const char *const bauds[] = { "150", "300", "600", "1200", "2400", "4800", + "9600", "14400", "19200", "28800", "38400", "57600", "115200"}; + + return(bauds[m_baud]); +} + + + +/*------------------------------------------------- + inc_baud +-------------------------------------------------*/ + +bool bitbanger_device::inc_baud(bool test) +{ + int adjust_baud = (int)m_baud + 1; + + if( adjust_baud >= BITBANGER_BAUD_MAX ) + return FALSE; + + if( !test) + { + m_baud = adjust_baud; + m_current_baud = attotime::from_hz(baud_value()); + } + + return TRUE; +} + + +/*------------------------------------------------- + dec_baud +-------------------------------------------------*/ + +bool bitbanger_device::dec_baud(bool test) +{ + int adjust_baud = m_baud - 1; + + if( adjust_baud < 0 ) + return FALSE; + + if( !test) + { + m_baud = adjust_baud; + m_current_baud = attotime::from_hz(baud_value()); + } + + return TRUE; +} + + +/*------------------------------------------------- + inc_tune +-------------------------------------------------*/ + +bool bitbanger_device::inc_tune(bool test) +{ + int adjust_tune = (int)m_tune + 1; + + if( adjust_tune >= BITBANGER_TUNE_MAX ) + return FALSE; + + if (!test) + { + m_tune = adjust_tune; + m_current_baud = attotime::from_hz(baud_value()); + } + + return TRUE; +} + + + +/*------------------------------------------------- + dec_tune +-------------------------------------------------*/ + +bool bitbanger_device::dec_tune(bool test) +{ + int adjust_tune = m_tune - 1; + + if( adjust_tune < 0 ) + return FALSE; + + if( !test) + { + m_tune = adjust_tune; + m_current_baud = attotime::from_hz(baud_value()); + } + + return TRUE; +} + + + +/*------------------------------------------------- + bytes_to_bits_81N +-------------------------------------------------*/ + +void bitbanger_device::bytes_to_bits_81N(void) +{ + 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(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++ ) + { + m_input_buffer[bit_buffer_size++] = 0; + + for( j=0; j<8; j++ ) + { + if( byte_buffer[i] & bitmask[j] ) + m_input_buffer[bit_buffer_size++] = 1; + else + m_input_buffer[bit_buffer_size++] = 0; + } + + m_input_buffer[bit_buffer_size++] = 1; + } + + m_input_buffer_size = bit_buffer_size; + m_input_buffer_cursor = 0; +} + + + +/*------------------------------------------------- + device_start +-------------------------------------------------*/ + +void bitbanger_device::device_start(void) +{ + /* output config */ + m_build_count = 0; + m_output_timer = timer_alloc(TIMER_OUTPUT); + + /* input config */ + m_input_timer = timer_alloc(TIMER_INPUT); + m_idle_delay = attotime::from_seconds(1); + m_input_buffer_size = 0; + m_input_buffer_cursor = 0; + + /* defaults */ + m_mode = m_default_mode; + m_baud = m_default_baud; + m_tune = m_default_tune; + m_current_baud = attotime::from_hz(baud_value()); + + /* callback */ + m_input_func.resolve(m_input_callback, *this); +} + + + +/*------------------------------------------------- + device_config_complete +-------------------------------------------------*/ + +void bitbanger_device::device_config_complete(void) +{ + const _bitbanger_config *intf = reinterpret_cast<const _bitbanger_config *>(static_config()); + if(intf != NULL) + { + *static_cast<_bitbanger_config *>(this) = *intf; + } + else + { + memset(&m_input_callback, 0, sizeof(m_input_callback)); + m_default_mode = 0; + m_default_baud = 0; + m_default_tune = 0; + } + update_names(); +} + + + +/*------------------------------------------------- + device_timer +-------------------------------------------------*/ + +void bitbanger_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_OUTPUT: + timer_output(); + break; + + case TIMER_INPUT: + timer_input(); + break; + } +} + + + +/*------------------------------------------------- + timer_output +-------------------------------------------------*/ + +void bitbanger_device::timer_output(void) +{ + /* this ia harded coded for 8-1-N */ + if( m_output_value ) + m_build_byte |= 0x200; + + m_build_byte >>= 1; + m_build_count--; + + if(m_build_count == 0) + { + if( m_output_value == 1 ) + native_output(m_build_byte); + else + logerror("Bitbanger: Output framing error.\n" ); + + m_output_timer->reset(); + } +} + + + +/*------------------------------------------------- + timer_input +-------------------------------------------------*/ + +void bitbanger_device::timer_input(void) +{ + if(m_input_buffer_cursor == m_input_buffer_size) + { + /* get more data */ + bytes_to_bits_81N(); + + if(m_input_buffer_size == 0) + { + /* no more data, wait and try again */ + m_idle_delay = min(m_idle_delay + attotime::from_msec(100), attotime::from_seconds(1)); + m_input_timer->adjust(m_idle_delay); + + if( m_mode == BITBANGER_MODEM ) + set_input_line(1); + else + set_input_line(0); + return; + } + else + { + m_idle_delay = m_current_baud; + m_input_timer->adjust(m_idle_delay, 0, m_idle_delay); + } + } + + /* send bit to driver */ + set_input_line(m_input_buffer[(m_input_buffer_cursor)++]); +} + + + +/*------------------------------------------------- + set_input_line +-------------------------------------------------*/ + +void bitbanger_device::set_input_line(UINT8 line) +{ + /* normalize */ + line = line ? ASSERT_LINE : CLEAR_LINE; + + /* only act when the state changes */ + if (m_current_input != line) + { + m_current_input = line; + m_input_func(line ? ASSERT_LINE : CLEAR_LINE); + } +} + + + +/*------------------------------------------------- + output - outputs data to a bitbanger port +-------------------------------------------------*/ + +void bitbanger_device::output(int value) +{ + attotime one_point_five_baud; + + if( m_build_count == 0 && m_output_value == 1 && value == 0 ) + { + /* we found our start bit */ + /* eight bits of data, plus one of stop */ + m_build_count = 9; + m_build_byte = 0; + + one_point_five_baud = m_current_baud + m_current_baud / 2; + m_output_timer->adjust(one_point_five_baud, 0, m_current_baud); + } + + //fprintf(stderr,"%s, %d\n", device->machine().time().as_string(9), value); + m_output_value = value; +} + + + +/*------------------------------------------------- + call_load +-------------------------------------------------*/ + +bool bitbanger_device::call_load(void) +{ + m_input_timer->enable(true); + m_input_timer->adjust(attotime::zero, 0, attotime::from_seconds(1)); + + /* we don't need to do anything special */ + return IMAGE_INIT_PASS; +} + + + +/*------------------------------------------------- + call_unload +-------------------------------------------------*/ + +void bitbanger_device::call_unload(void) +{ + m_input_timer->enable(false); +} + |