#ifndef SIO_H
#define SIO_H

/* FIFO size in SIO */
#define MAXIOBUF                8

/* Status Reg bits */
#define TX_RDY                  0x0001
#define RX_RDY                  0x0002
#define TX_EMPTY                0x0004
#define PE                      0x0008
#define RX_OVERRUN              0x0010
#define FE                      0x0020
#define SYNCDET                 0x0040
#define DSR                     0x0080
#define CTS                     0x0100
#define SIO_IRQ                 0x0200

/* Mode Reg bits */
#define PRESCALER1              0x0001
#define PRESCALER16             0x0002
#define PRESCALER64             0x0003
#define BYTE5BIT                0x0000
#define BYTE6BIT                0x0004
#define BYTE7BIT                0x0008
#define BYTE8BIT                0x000C
#define PARITY                  0x0010
#define PARITY_ODDEVEN          0x0020
#define STOP1BIT                0x0040
#define STOP15BIT               0x0080
#define STOP2BIT                0x00C0

/* Control Reg bits */
#define TxENABLE                0x01
#define DTR                     0x02
#define RxENABLE                0x04
#define CHNBREAK                0x08
#define ERROR_RESET             0x10
#define RTS                     0x20
#define INTERNAL_RESET          0x40
#define HUNT_MODE               0x80
 
/* Interrupt Reg bits */
#define BUFFERSIZE              0x03
#define TxIRQ                   0x04
#define RxIRQ                   0x08
#define DSRIRQ                  0x10
#define CTSIRQ                  0x20 // Not sure about this

/* SIO clock speed */
#define SIOBAUDCLOCK            0x001FA400

// SIO IRQ handling
#define SIO_IRQ_NONE    0
#define SIO_IRQ_IMM     1
#define SIO_IRQ_ASYNC   2
#define SIO_IRQ_VSYNC   3

/* SIO emulation struct */
typedef struct {
    UINT8  RxBuf[MAXIOBUF];
    UINT8  TxBuf[MAXIOBUF];
    int    RxNum,TxNum;
    int    RxStart,RxEnd;
    UINT32 Status;
    UINT16 Mode;
    union {
        struct {
#ifdef MSB_FIRST
            UINT8  Irq, Line;
#else
            UINT8  Line, Irq;
#endif
        } Control8;
        UINT16 Control16;
    } Ctrl;
    UINT32 Baud;
    int    FifoSize;
    int    IrqLevel;
    int    IrqSrc;
    int    IrqFlags;
    int    Delta;
    void (*UpdateStatus)();
    void (*WriteData)();
} SIO_Type;

/* Exported Vars */
extern SIO_Type Sio0;
extern SIO_Type Sio1;

/* Exported functions */
int sio_init();

int sio_readdata8 (SIO_Type *sio);
int sio_readdata16(SIO_Type *sio);
int sio_readdata32(SIO_Type *sio);

void sio_writedata8 (SIO_Type *sio, int data);
void sio_writedata16(SIO_Type *sio, int data);
void sio_writedata32(SIO_Type *sio, int data);

int sio_async(SIO_Type *sio, char *buf, int len);

void sio_control_write(SIO_Type *sio, int data);
void sio_baud_write(SIO_Type *sio, int data);
void sio_mode_write(SIO_Type *sio, int data);

#endif