85 lines
2.3 KiB
C
85 lines
2.3 KiB
C
/*
|
|
* Serial encoder/decoder.
|
|
*
|
|
* Copyright (c) 2000 Fabrice Bellard.
|
|
*
|
|
* This code is released under the GNU General Public License version
|
|
* 2. Please read the file COPYING to know the exact terms of the
|
|
* license.
|
|
*
|
|
*/
|
|
|
|
#include "lm.h"
|
|
|
|
/* Init the serial encoder & decoder. 5 <= data_bits <= 8 and parity
|
|
can be 'E', 'O', or 'N' */
|
|
void serial_init(struct sm_state *s, int data_bits, int parity)
|
|
{
|
|
s->serial_data_bits = data_bits;
|
|
s->serial_use_parity = (parity == 'E' || parity == 'O');
|
|
s->serial_parity = (parity == 'O');
|
|
s->serial_wordsize = data_bits + 2 + s->serial_use_parity;
|
|
|
|
/* rx init */
|
|
s->serial_buf = 0;
|
|
s->serial_cnt = 0;
|
|
|
|
/* tx init */
|
|
s->serial_tx_buf = 0;
|
|
s->serial_tx_cnt = 0;
|
|
}
|
|
|
|
/* return a bit from the tx fifo with serial encoding */
|
|
int serial_get_bit(void *opaque)
|
|
{
|
|
struct sm_state *s = opaque;
|
|
int data, j, bit, p;
|
|
|
|
if (s->serial_tx_cnt == 0) {
|
|
data = sm_get_bit(&s->tx_fifo);
|
|
if (data == -1)
|
|
return 1;
|
|
s->serial_tx_cnt = s->serial_wordsize;
|
|
if (s->serial_use_parity) {
|
|
p = s->serial_parity;
|
|
for(j=0;j<s->serial_data_bits;j++) p ^= (data >> j) & 1;
|
|
s->serial_tx_buf = (data << 2) | (p << 1) | 1;
|
|
} else {
|
|
s->serial_tx_buf = (data << 1) | 1;
|
|
}
|
|
}
|
|
s->serial_tx_cnt--;
|
|
bit = (s->serial_tx_buf >> s->serial_tx_cnt) & 1;
|
|
return bit;
|
|
}
|
|
|
|
/* decode a serial stream and put it in rx_fifo. Not optimized */
|
|
void serial_put_bit(void *opaque, int bit)
|
|
{
|
|
struct sm_state *s = opaque;
|
|
int mask, p, j, data;
|
|
|
|
s->serial_buf = (s->serial_buf << 1) | bit;
|
|
if (s->serial_cnt >= (s->serial_wordsize-1)) {
|
|
mask = 1 | (1 << (s->serial_wordsize-1));
|
|
|
|
if ((s->serial_buf & mask) == 0x1) {
|
|
data = (s->serial_buf & ((1 << s->serial_wordsize) - 1)) >> 1;
|
|
|
|
if (s->serial_use_parity) {
|
|
p = s->serial_parity;
|
|
for(j=0;j<=s->serial_data_bits;j++) p ^= (data >> j) & 1;
|
|
if (!p)
|
|
sm_put_bit(&s->rx_fifo, data >> 1);
|
|
} else {
|
|
sm_put_bit(&s->rx_fifo, data);
|
|
}
|
|
|
|
s->serial_cnt = 0;
|
|
}
|
|
} else {
|
|
s->serial_cnt++;
|
|
}
|
|
}
|
|
|