diff options
Diffstat (limited to 'gdb/rdi-share/rx.c')
-rw-r--r-- | gdb/rdi-share/rx.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/gdb/rdi-share/rx.c b/gdb/rdi-share/rx.c new file mode 100644 index 0000000..4f434f0 --- /dev/null +++ b/gdb/rdi-share/rx.c @@ -0,0 +1,361 @@ +/* + * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. + * + * This software may be freely used, copied, modified, and distributed + * provided that the above copyright notice is preserved in all copies of the + * software. + */ + +/*-*-C-*- + * + * $Revision$ + * $Date$ + * + * + * Project: ANGEL + * + * Title: Character reception engine + */ + +#include <stdarg.h> /* ANSI varargs support */ +#include "angel.h" /* Angel system definitions */ +#include "endian.h" /* Endian independant memory access macros */ +#include "crc.h" /* crc generation definitions and headers */ +#include "rxtx.h" +#include "channels.h" +#include "buffers.h" +#ifdef TARGET +# include "devdriv.h" +#endif +#include "logging.h" + +static re_status unexp_stx(struct re_state *rxstate); +static re_status unexp_etx(struct re_state *rxstate); + +/* bitfield for the rx_engine state */ +typedef enum rx_state_flag{ + RST_STX, + RST_TYP, + RST_LEN, + RST_DAT, + RST_CRC, + RST_ETX, + RST_ESC = (0x1 << 0x3) +} rx_state_flag; + +void Angel_RxEngineInit(const struct re_config *rxconfig, + struct re_state *rxstate) +{ + rxstate->rx_state = RST_STX; + rxstate->field_c = 0; + rxstate->index = 0; + rxstate->crc = 0; + rxstate->error = RE_OKAY; + rxstate->config = rxconfig; +} + +re_status Angel_RxEngine(unsigned char new_ch, struct data_packet *packet, + struct re_state *rxstate) +{ + /* + * TODO: add the flow control bits in + * Note: We test for the data field in a seperate case so we can + * completely avoid entering the switch for most chars + */ + + /* see if we're expecting a escaped char */ + if ((rxstate->rx_state & RST_ESC) == RST_ESC) + { + /* unescape the char and unset the flag*/ + new_ch &= ~serial_ESCAPE; +#ifdef DO_TRACE + __rt_trace("rxe-echar-%2x ", new_ch); +#endif + rxstate->rx_state &= ~RST_ESC; + } + else if ( (1 << new_ch) & rxstate->config->esc_set ) + { + /* see if the incoming char is a special one */ + if (new_ch == rxstate->config->esc) + { +#ifdef DO_TRACE + __rt_trace("rxe-esc "); +#endif + rxstate->rx_state |= RST_ESC; + return RS_IN_PKT; + } + else + { + /* + * must be a normal packet so do some unexpected etx/stx checking + * we haven't been told to escape or received an escape so unless + * we are expecting an stx or etx then we can take the unexpected + * stx/etx trap + */ + if ((new_ch == (rxstate->config->stx)) && (rxstate->rx_state != RST_STX)) + return unexp_stx(rxstate); + if ((new_ch == (rxstate->config->etx)) && (rxstate->rx_state != RST_ETX)) + return unexp_etx(rxstate); + } + } + + if (rxstate->rx_state == RST_DAT) + { + /* + * do this to speed up the common case, no real penalty for + * other cases + */ +#ifdef DO_TRACE + __rt_trace("rxe-dat "); +#endif + + rxstate->crc = crc32(&new_ch, 1, rxstate->crc); + (packet->data)[rxstate->index++] = (unsigned int)new_ch & 0xff; + + if (rxstate->index == packet->len) + rxstate->rx_state = RST_CRC; + + return RS_IN_PKT; + } + + /* + * Now that the common case is out of the way we can test for everything + * else without worrying quite so much about the speed, changing the + * order to len,crc,stx,etx,typ might gain a tiny bit of speed but lets + * leave that for the moment + */ + switch (rxstate->rx_state) + { + case RST_STX: + if (new_ch == rxstate->config->stx) + { + rxstate->rx_state = RST_TYP; + rxstate->error = RE_OKAY; + rxstate->crc = startCRC32; + rxstate->index = 0; + return RS_IN_PKT; + } + else + { + rxstate->error = RE_OKAY; + return RS_WAIT_PKT; + } + + case RST_TYP: + packet->type = (DevChanID)new_ch; + rxstate->rx_state = RST_LEN; + rxstate->error = RE_OKAY; + rxstate->field_c = 0; /* set up here for the length that follows */ +#ifdef DO_TRACE + __rt_trace("rxe-type-%2x ", packet->type); +#endif + rxstate->crc = crc32(&new_ch, 1, rxstate->crc); + + return RS_IN_PKT; + + case RST_LEN: + rxstate->crc = crc32(&new_ch, 1, rxstate->crc); + + if (rxstate->field_c++ == 0) + { + /* first length byte */ + packet->len = ((unsigned int)new_ch) << 8; + return RS_IN_PKT; + } + else + { + /* got the whole legth */ + packet->len |= new_ch; +#ifdef DO_TRACE + __rt_trace("rxe-len-%4x\n", packet->len); +#endif + + /* check that the length is ok */ + if (packet->len == 0) + { + /* empty pkt */ + rxstate->field_c = 0; + rxstate->rx_state = RST_CRC; + return RS_IN_PKT; + } + else + { + if (packet->data == NULL) + { + /* need to alloc the data buffer */ + if (!rxstate->config->ba_callback( + packet, rxstate->config->ba_data)) { + rxstate->rx_state = RST_STX; + rxstate->error = RE_INTERNAL; + return RS_BAD_PKT; + } + } + + if (packet->len > packet->buf_len) + { + /* pkt bigger than buffer */ + rxstate->field_c = 0; + rxstate->rx_state = RST_STX; + rxstate->error = RE_LEN; + return RS_BAD_PKT; + } + else + { + /* packet ok */ + rxstate->field_c = 0; + rxstate->rx_state = RST_DAT; + return RS_IN_PKT; + } + } + } + + case RST_DAT: + /* dummy case (dealt with earlier) */ +#ifdef ASSERTIONS_ENABLED + __rt_warning("ERROR: hit RST_dat in switch\n"); +#endif + rxstate->rx_state = RST_STX; + rxstate->error = RE_INTERNAL; + return RS_BAD_PKT; + + case RST_CRC: + if (rxstate->field_c == 0) + packet->crc = 0; + + packet->crc |= (new_ch & 0xFF) << ((3 - rxstate->field_c) * 8); + rxstate->field_c++; + + if (rxstate->field_c == 4) + { + /* last crc field */ + rxstate->field_c = 0; + rxstate->rx_state = RST_ETX; +#ifdef DO_TRACE + __rt_trace("rxe-rcrc-%8x ", packet->crc); +#endif + } + + return RS_IN_PKT; + + case RST_ETX: + if (new_ch == rxstate->config->etx) + { +#if defined(DEBUG) && !defined(NO_PKT_DATA) + { + int c; +# ifdef DO_TRACE + __rt_trace("\n"); +# endif + __rt_info("RXE Data ="); + for (c=0; c < packet->len; c++) + __rt_info("%02x", packet->data[c]); + __rt_info("\n"); + } +#endif + + /* check crc */ + if (rxstate->crc == packet->crc) + { + /* crc ok */ + rxstate->rx_state = RST_STX; + rxstate->field_c = 0; + return RS_GOOD_PKT; + } + else + { +#ifdef ASSERTIONS_ENABLED + __rt_warning("Bad crc, rx calculates it should be 0x%x\n", rxstate->crc); +#endif + rxstate->rx_state = RST_STX; + rxstate->error = RE_CRC; + return RS_BAD_PKT; + } + } + else if (new_ch == rxstate->config->stx) + return unexp_stx(rxstate); + else + { + rxstate->rx_state = RST_STX; + rxstate->error = RE_NETX; + return RS_BAD_PKT; + } + + default: +#ifdef ASSERTIONS_ENABLED + __rt_warning("ERROR fell through rxengine\n"); +#endif + rxstate->rx_state = RST_STX; + rxstate->error = RE_INTERNAL; + return RS_BAD_PKT; + } +} + +static re_status unexp_stx(struct re_state *rxstate) +{ +#ifdef ASSERTIONS_ENABLED + __rt_warning("Unexpected stx\n"); +#endif + rxstate->crc = startCRC32; + rxstate->index = 0; + rxstate->rx_state = RST_TYP; + rxstate->error = RE_U_STX; + rxstate->field_c = 0; + return RS_BAD_PKT; +} + +static re_status unexp_etx(struct re_state *rxstate) +{ +#ifdef ASSERTIONS_ENABLED + __rt_warning("Unexpected etx, rxstate: index= 0x%2x, field_c=0x%2x, state=0x%2x\n", rxstate->index, rxstate->field_c, rxstate->rx_state); +#endif + rxstate->crc = 0; + rxstate->index = 0; + rxstate->rx_state = RST_STX; + rxstate->error = RE_U_ETX; + rxstate->field_c = 0; + return RS_BAD_PKT; +} + +/* + * This can be used as the buffer allocation callback for the rx engine, + * and makes use of angel_DD_GetBuffer() [in devdrv.h]. + * + * Saves duplicating this callback function in every device driver that + * uses the rx engine. + * + * Note that this REQUIRES that the device id is installed as ba_data + * in the rx engine config structure for the driver. + */ +bool angel_DD_RxEng_BufferAlloc( struct data_packet *packet, void *cb_data ) +{ +#ifdef TARGET + DeviceID devid = (DeviceID)cb_data; +#else + IGNORE(cb_data); +#endif + + if ( packet->type < DC_NUM_CHANNELS ) + { + /* request a buffer down from the channels layer */ +#ifdef TARGET + packet->data = angel_DD_GetBuffer( devid, packet->type, + packet->len ); +#else + packet->data = malloc(packet->len); +#endif + if ( packet->data == NULL ) + return FALSE; + else + { + packet->buf_len = packet->len; + return TRUE; + } + } + else + { + /* bad type field */ + return FALSE; + } +} + +/* EOF rx.c */ |