Search
lxdream.org :: lxdream/src/sh4/scif.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/scif.c
changeset 929:fd8cb0c82f5f
prev828:b42865f00fb5
next975:007bf7eb944f
author nkeynes
date Sat Dec 27 02:59:35 2008 +0000 (15 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change Replace fpscr_mask/fpscr flags in xlat_cache_block with a single xlat_sh4_mode,
which tracks the field of the same name in sh4r - actually a little faster this way.
Now depends on SR.MD, FPSCR.PR and FPSCR.SZ (although it doesn't benefit from the SR
flag yet).

Also fixed the failure to check the flags in the common case (code address returned
by previous block) which took away the performance benefits, but oh well.
file annotate diff log raw
nkeynes@20
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@20
     3
 * SCIF (Serial Communication Interface with FIFO) implementation - part of the 
nkeynes@20
     4
 * SH4 standard on-chip peripheral set. The SCIF is hooked up to the DCs
nkeynes@20
     5
 * external serial port
nkeynes@20
     6
 *
nkeynes@20
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@20
     8
 *
nkeynes@20
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@20
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@20
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@20
    12
 * (at your option) any later version.
nkeynes@20
    13
 *
nkeynes@20
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@20
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@20
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@20
    17
 * GNU General Public License for more details.
nkeynes@20
    18
 */
nkeynes@20
    19
nkeynes@20
    20
#include <glib.h>
nkeynes@20
    21
#include "dream.h"
nkeynes@20
    22
#include "mem.h"
nkeynes@54
    23
#include "sh4/sh4core.h"
nkeynes@54
    24
#include "sh4/sh4mmio.h"
nkeynes@54
    25
#include "sh4/intc.h"
nkeynes@54
    26
#include "sh4/dmac.h"
nkeynes@20
    27
#include "clock.h"
nkeynes@20
    28
#include "serial.h"
nkeynes@20
    29
nkeynes@20
    30
void SCIF_set_break(void);
nkeynes@20
    31
nkeynes@20
    32
/************************* External serial interface ************************/
nkeynes@20
    33
nkeynes@20
    34
/**
nkeynes@20
    35
 * Note: serial_* operations are called from outside the SH4, and as such are
nkeynes@20
    36
 * named relative to the external serial device. SCIF_* operations are only
nkeynes@20
    37
 * called internally to the SH4 and so are named relative to the CPU.
nkeynes@20
    38
 */
nkeynes@20
    39
nkeynes@20
    40
/**
nkeynes@20
    41
 * Storage space for inbound/outbound data blocks. It's a little more
nkeynes@20
    42
 * convenient for serial consumers to be able to deal with block-sized pieces
nkeynes@20
    43
 * rather than a byte at a time, even if it makes all this look rather
nkeynes@20
    44
 * complicated.
nkeynes@20
    45
 *
nkeynes@20
    46
 * Currently there's no limit on the number of blocks that can be queued up.
nkeynes@20
    47
 */
nkeynes@20
    48
typedef struct serial_data_block {
nkeynes@20
    49
    uint32_t length;
nkeynes@20
    50
    uint32_t offset;
nkeynes@20
    51
    struct serial_data_block *next;
nkeynes@20
    52
    char data[];
nkeynes@20
    53
} *serial_data_block_t;
nkeynes@20
    54
nkeynes@20
    55
serial_data_block_t serial_recvq_head = NULL, serial_recvq_tail = NULL;
nkeynes@20
    56
serial_device_t serial_device = NULL;
nkeynes@20
    57
nkeynes@20
    58
void serial_attach_device( serial_device_t dev ) 
nkeynes@20
    59
{
nkeynes@20
    60
    if( serial_device != NULL )
nkeynes@736
    61
        serial_detach_device();
nkeynes@20
    62
    serial_device = dev;
nkeynes@20
    63
}
nkeynes@20
    64
nkeynes@20
    65
nkeynes@20
    66
void serial_detach_device( void )
nkeynes@20
    67
{
nkeynes@20
    68
    serial_device = NULL;
nkeynes@20
    69
}
nkeynes@20
    70
nkeynes@20
    71
/**
nkeynes@20
    72
 * Add a block of data to the serial receive queue. The data will be received
nkeynes@20
    73
 * by the CPU at the appropriate baud rate.
nkeynes@20
    74
 */
nkeynes@20
    75
void serial_transmit_data( char *data, int length ) {
nkeynes@20
    76
    if( length == 0 )
nkeynes@736
    77
        return;
nkeynes@20
    78
    serial_data_block_t block = 
nkeynes@736
    79
        g_malloc( sizeof( struct serial_data_block ) + length );
nkeynes@20
    80
    block->length = length;
nkeynes@20
    81
    block->offset = 0;
nkeynes@20
    82
    block->next = NULL;
nkeynes@20
    83
    memcpy( block->data, data, length );
nkeynes@736
    84
nkeynes@20
    85
    if( serial_recvq_head == NULL ) {
nkeynes@736
    86
        serial_recvq_head = serial_recvq_tail = block;
nkeynes@20
    87
    } else {
nkeynes@736
    88
        serial_recvq_tail->next = block;
nkeynes@736
    89
        serial_recvq_tail = block;
nkeynes@20
    90
    }
nkeynes@20
    91
}
nkeynes@20
    92
nkeynes@20
    93
/**
nkeynes@20
    94
 * Dequeue a byte from the serial input queue
nkeynes@20
    95
 */
nkeynes@20
    96
static int serial_transmit_dequeue( ) {
nkeynes@20
    97
    if( serial_recvq_head != NULL ) {
nkeynes@736
    98
        uint8_t val = serial_recvq_head->data[serial_recvq_head->offset++];
nkeynes@736
    99
        if( serial_recvq_head->offset >= serial_recvq_head->length ) {
nkeynes@736
   100
            serial_data_block_t next = serial_recvq_head->next;
nkeynes@736
   101
            g_free( serial_recvq_head );
nkeynes@736
   102
            serial_recvq_head = next;
nkeynes@736
   103
            if( next == NULL )
nkeynes@736
   104
                serial_recvq_tail = NULL;
nkeynes@736
   105
        }
nkeynes@736
   106
        return (int)(unsigned int)val;
nkeynes@20
   107
    }
nkeynes@20
   108
    return -1;
nkeynes@20
   109
nkeynes@20
   110
}
nkeynes@20
   111
nkeynes@20
   112
void serial_transmit_break() {
nkeynes@20
   113
    SCIF_set_break();
nkeynes@20
   114
}
nkeynes@20
   115
nkeynes@20
   116
/********************************* SCIF *************************************/
nkeynes@20
   117
nkeynes@20
   118
#define FIFO_LENGTH 16
nkeynes@20
   119
#define FIFO_ARR_LENGTH (FIFO_LENGTH+1)
nkeynes@20
   120
nkeynes@20
   121
/* Serial control register flags */
nkeynes@20
   122
#define SCSCR2_TIE  0x80
nkeynes@20
   123
#define SCSCR2_RIE  0x40
nkeynes@20
   124
#define SCSCR2_TE   0x20
nkeynes@20
   125
#define SCSCR2_RE   0x10
nkeynes@20
   126
#define SCSCR2_REIE 0x08
nkeynes@20
   127
#define SCSCR2_CKE 0x02
nkeynes@20
   128
nkeynes@20
   129
#define IS_TRANSMIT_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TIE)
nkeynes@20
   130
#define IS_RECEIVE_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RIE)
nkeynes@20
   131
#define IS_RECEIVE_ERROR_IRQ_ENABLED() (MMIO_READ(SCIF,SCSCR2) & (SCSCR2_RIE|SCSCR2_REIE))
nkeynes@20
   132
/* Receive is enabled if the RE bit is set in SCSCR2, and the ORER bit is cleared in SCLSR2 */
nkeynes@428
   133
#define IS_RECEIVE_ENABLED() ( (MMIO_READ(SCIF,SCSCR2) & SCSCR2_RE) && ((MMIO_READ(SCIF,SCLSR2) & SCLSR2_ORER) == 0) )
nkeynes@20
   134
/* Transmit is enabled if the TE bit is set in SCSCR2 */
nkeynes@20
   135
#define IS_TRANSMIT_ENABLED() (MMIO_READ(SCIF,SCSCR2) & SCSCR2_TE)
nkeynes@20
   136
#define IS_LOOPBACK_ENABLED() (MMIO_READ(SCIF,SCFCR2) & SCFCR2_LOOP)
nkeynes@20
   137
nkeynes@20
   138
/* Serial status register flags */
nkeynes@20
   139
#define SCFSR2_ER   0x80
nkeynes@20
   140
#define SCFSR2_TEND 0x40
nkeynes@20
   141
#define SCFSR2_TDFE 0x20
nkeynes@20
   142
#define SCFSR2_BRK  0x10
nkeynes@20
   143
#define SCFSR2_RDF  0x02
nkeynes@20
   144
#define SCFSR2_DR   0x01
nkeynes@20
   145
nkeynes@20
   146
/* FIFO control register flags */
nkeynes@20
   147
#define SCFCR2_MCE   0x08
nkeynes@20
   148
#define SCFCR2_TFRST 0x04
nkeynes@20
   149
#define SCFCR2_RFRST 0x02
nkeynes@20
   150
#define SCFCR2_LOOP  0x01
nkeynes@20
   151
nkeynes@20
   152
/* Line Status Register */
nkeynes@20
   153
#define SCLSR2_ORER 0x01
nkeynes@20
   154
nkeynes@20
   155
struct SCIF_fifo {
nkeynes@20
   156
    int head;
nkeynes@20
   157
    int tail;
nkeynes@20
   158
    int trigger;
nkeynes@20
   159
    uint8_t data[FIFO_ARR_LENGTH];
nkeynes@20
   160
};
nkeynes@20
   161
nkeynes@22
   162
int SCIF_recvq_triggers[4] = {1, 4, 8, 14};
nkeynes@22
   163
struct SCIF_fifo SCIF_recvq = {0,0,1};
nkeynes@22
   164
nkeynes@22
   165
int SCIF_sendq_triggers[4] = {8, 4, 2, 1};
nkeynes@22
   166
struct SCIF_fifo SCIF_sendq = {0,0,8};
nkeynes@22
   167
nkeynes@22
   168
/**
nkeynes@22
   169
 * Flag to indicate if data was received (ie added to the receive queue)
nkeynes@22
   170
 * during the last SCIF clock tick. Used to determine when to set the DR
nkeynes@22
   171
 * flag.
nkeynes@22
   172
 */
nkeynes@22
   173
gboolean SCIF_rcvd_last_tick = FALSE;
nkeynes@22
   174
nkeynes@30
   175
uint32_t SCIF_tick_period = 0;
nkeynes@30
   176
uint32_t SCIF_tick_remainder = 0;
nkeynes@30
   177
nkeynes@20
   178
void SCIF_save_state( FILE *f ) 
nkeynes@20
   179
{
nkeynes@22
   180
    fwrite( &SCIF_recvq, sizeof(SCIF_recvq), 1, f );
nkeynes@22
   181
    fwrite( &SCIF_sendq, sizeof(SCIF_sendq), 1, f );
nkeynes@22
   182
    fwrite( &SCIF_rcvd_last_tick, sizeof(gboolean), 1, f );
nkeynes@20
   183
nkeynes@20
   184
}
nkeynes@20
   185
nkeynes@20
   186
int SCIF_load_state( FILE *f ) 
nkeynes@20
   187
{
nkeynes@22
   188
    fread( &SCIF_recvq, sizeof(SCIF_recvq), 1, f );
nkeynes@22
   189
    fread( &SCIF_sendq, sizeof(SCIF_sendq), 1, f );
nkeynes@22
   190
    fread( &SCIF_rcvd_last_tick, sizeof(gboolean), 1, f );
nkeynes@20
   191
    return 0;
nkeynes@20
   192
}
nkeynes@20
   193
nkeynes@20
   194
static inline uint8_t SCIF_recvq_size( ) 
nkeynes@20
   195
{
nkeynes@20
   196
    int val = SCIF_recvq.tail - SCIF_recvq.head;
nkeynes@20
   197
    if( val < 0 ) {
nkeynes@736
   198
        val = FIFO_ARR_LENGTH - SCIF_recvq.head + SCIF_recvq.tail;
nkeynes@20
   199
    }
nkeynes@20
   200
    return val;
nkeynes@20
   201
}
nkeynes@20
   202
nkeynes@20
   203
int SCIF_recvq_dequeue( gboolean clearFlags )
nkeynes@20
   204
{
nkeynes@20
   205
    uint8_t result;
nkeynes@20
   206
    uint32_t tmp, length;
nkeynes@20
   207
    if( SCIF_recvq.head == SCIF_recvq.tail )
nkeynes@736
   208
        return -1; /* No data */
nkeynes@20
   209
    result = SCIF_recvq.data[SCIF_recvq.head++];
nkeynes@20
   210
    if( SCIF_recvq.head > FIFO_LENGTH )
nkeynes@736
   211
        SCIF_recvq.head = 0;
nkeynes@20
   212
nkeynes@20
   213
    /* Update data count register */
nkeynes@20
   214
    tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
nkeynes@20
   215
    length = SCIF_recvq_size();
nkeynes@20
   216
    MMIO_WRITE( SCIF, SCFDR2, tmp | length );
nkeynes@20
   217
nkeynes@20
   218
    /* Clear flags (if requested ) */
nkeynes@20
   219
    if( clearFlags && length < SCIF_recvq.trigger ) {
nkeynes@736
   220
        tmp = SCFSR2_RDF;
nkeynes@736
   221
        if( length == 0 )
nkeynes@736
   222
            tmp |= SCFSR2_DR;
nkeynes@736
   223
        tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
nkeynes@736
   224
        MMIO_WRITE( SCIF, SCFSR2, tmp );
nkeynes@736
   225
        /* If both flags are cleared, clear the interrupt as well */
nkeynes@736
   226
        if( (tmp & (SCFSR2_DR|SCFSR2_RDF)) == 0 && IS_RECEIVE_IRQ_ENABLED() )
nkeynes@736
   227
            intc_clear_interrupt( INT_SCIF_RXI );
nkeynes@20
   228
    }
nkeynes@736
   229
nkeynes@20
   230
    return (int)(unsigned int)result;
nkeynes@20
   231
}
nkeynes@20
   232
nkeynes@20
   233
gboolean SCIF_recvq_enqueue( uint8_t value )
nkeynes@20
   234
{
nkeynes@20
   235
    uint32_t tmp, length;
nkeynes@20
   236
    int newpos = SCIF_recvq.tail + 1;
nkeynes@20
   237
    if( newpos > FIFO_LENGTH )
nkeynes@736
   238
        newpos = 0;
nkeynes@20
   239
    if( newpos == SCIF_recvq.head ) {
nkeynes@736
   240
        /* FIFO full - set ORER and discard the value */
nkeynes@736
   241
        MMIO_WRITE( SCIF, SCLSR2, SCLSR2_ORER );
nkeynes@736
   242
        if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
nkeynes@736
   243
            intc_raise_interrupt( INT_SCIF_ERI );
nkeynes@736
   244
        return FALSE;
nkeynes@20
   245
    }
nkeynes@20
   246
    SCIF_recvq.data[SCIF_recvq.tail] = value;
nkeynes@20
   247
nkeynes@20
   248
    /* Update data count register */
nkeynes@20
   249
    tmp = MMIO_READ( SCIF, SCFDR2 ) & 0xF0;
nkeynes@20
   250
    length = SCIF_recvq_size();
nkeynes@20
   251
    MMIO_WRITE( SCIF, SCFDR2, tmp | length );
nkeynes@20
   252
nkeynes@20
   253
    /* Update status register */
nkeynes@20
   254
    tmp = MMIO_READ( SCIF, SCFSR2 );
nkeynes@20
   255
    if( length >= SCIF_recvq.trigger ) {
nkeynes@736
   256
        tmp |= SCFSR2_RDF;
nkeynes@736
   257
        if( IS_RECEIVE_IRQ_ENABLED() ) 
nkeynes@736
   258
            intc_raise_interrupt( INT_SCIF_RXI );
nkeynes@54
   259
        DMAC_trigger( DMAC_SCIF_RDF );
nkeynes@20
   260
    }
nkeynes@20
   261
    MMIO_WRITE( SCIF, SCFSR2, tmp );
nkeynes@20
   262
    return TRUE;
nkeynes@20
   263
}
nkeynes@20
   264
nkeynes@20
   265
nkeynes@20
   266
/**
nkeynes@20
   267
 * Reset the receive FIFO to its initial state. Manual is unclear as to
nkeynes@20
   268
 * whether this also clears flags/interrupts, but we're assuming here that
nkeynes@20
   269
 * it does until proven otherwise.
nkeynes@20
   270
 */
nkeynes@20
   271
void SCIF_recvq_clear( void ) 
nkeynes@20
   272
{
nkeynes@20
   273
    SCIF_recvq.head = SCIF_recvq.tail = 0;
nkeynes@20
   274
    MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0xF0 );
nkeynes@20
   275
    MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) & ~(SCFSR2_DR|SCFSR2_RDF) );
nkeynes@21
   276
    if( IS_RECEIVE_IRQ_ENABLED() )
nkeynes@736
   277
        intc_clear_interrupt( INT_SCIF_RXI );
nkeynes@20
   278
}
nkeynes@20
   279
nkeynes@20
   280
static inline uint8_t SCIF_sendq_size( ) 
nkeynes@20
   281
{
nkeynes@20
   282
    int val = SCIF_sendq.tail - SCIF_sendq.head;
nkeynes@20
   283
    if( val < 0 ) {
nkeynes@736
   284
        val = FIFO_ARR_LENGTH - SCIF_sendq.head + SCIF_sendq.tail;
nkeynes@20
   285
    }
nkeynes@20
   286
    return val;
nkeynes@20
   287
}
nkeynes@20
   288
nkeynes@20
   289
/**
nkeynes@20
   290
 * Dequeue one byte from the SCIF transmit queue (ie transmit the byte),
nkeynes@20
   291
 * updating all status flags as required.
nkeynes@20
   292
 * @return The byte dequeued, or -1 if the queue is empty.
nkeynes@20
   293
 */
nkeynes@20
   294
int SCIF_sendq_dequeue( )
nkeynes@20
   295
{
nkeynes@20
   296
    uint8_t result;
nkeynes@20
   297
    uint32_t tmp, length;
nkeynes@20
   298
    if( SCIF_sendq.head == SCIF_sendq.tail )
nkeynes@736
   299
        return -1; /* No data */
nkeynes@20
   300
nkeynes@20
   301
    /* Update queue head pointer */
nkeynes@20
   302
    result = SCIF_sendq.data[SCIF_sendq.head++];
nkeynes@20
   303
    if( SCIF_sendq.head > FIFO_LENGTH )
nkeynes@736
   304
        SCIF_sendq.head = 0;
nkeynes@20
   305
nkeynes@20
   306
    /* Update data count register */
nkeynes@20
   307
    tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
nkeynes@20
   308
    length = SCIF_sendq_size();
nkeynes@20
   309
    MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
nkeynes@736
   310
nkeynes@20
   311
    /* Update status register */
nkeynes@20
   312
    if( length <= SCIF_sendq.trigger ) {
nkeynes@736
   313
        tmp = MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TDFE;
nkeynes@736
   314
        if( length == 0 )
nkeynes@736
   315
            tmp |= SCFSR2_TEND; /* Transmission ended - no data waiting */
nkeynes@736
   316
        if( IS_TRANSMIT_IRQ_ENABLED() ) 
nkeynes@736
   317
            intc_raise_interrupt( INT_SCIF_TXI );
nkeynes@54
   318
        DMAC_trigger( DMAC_SCIF_TDE );
nkeynes@736
   319
        MMIO_WRITE( SCIF, SCFSR2, tmp );
nkeynes@20
   320
    }
nkeynes@20
   321
    return (int)(unsigned int)result;
nkeynes@20
   322
}
nkeynes@20
   323
nkeynes@20
   324
/**
nkeynes@20
   325
 * Enqueue a single byte in the SCIF transmit queue. If the queue is full,
nkeynes@20
   326
 * the value will be discarded.
nkeynes@20
   327
 * @param value to be queued.
nkeynes@20
   328
 * @param clearFlags TRUE if the TEND/TDFE flags should be cleared
nkeynes@20
   329
 *   if the queue exceeds the trigger level. (According to the manual,
nkeynes@20
   330
 *   DMAC writes will clear the flag, whereas regular SH4 writes do NOT
nkeynes@20
   331
 *   automatically clear it. Go figure).
nkeynes@20
   332
 * @return gboolean TRUE if the value was queued, FALSE if the queue was
nkeynes@20
   333
 *   full.
nkeynes@20
   334
 */
nkeynes@20
   335
gboolean SCIF_sendq_enqueue( uint8_t value, gboolean clearFlags )
nkeynes@20
   336
{
nkeynes@20
   337
    uint32_t tmp, length;
nkeynes@20
   338
    int newpos = SCIF_sendq.tail + 1;
nkeynes@20
   339
    if( newpos > FIFO_LENGTH )
nkeynes@736
   340
        newpos = 0;
nkeynes@20
   341
    if( newpos == SCIF_sendq.head ) {
nkeynes@736
   342
        /* FIFO full - discard */
nkeynes@736
   343
        return FALSE;
nkeynes@20
   344
    }
nkeynes@20
   345
    SCIF_sendq.data[SCIF_sendq.tail] = value;
nkeynes@20
   346
    SCIF_sendq.tail = newpos;
nkeynes@20
   347
nkeynes@20
   348
    /* Update data count register */
nkeynes@20
   349
    tmp = MMIO_READ( SCIF, SCFDR2 ) & 0x0F;
nkeynes@20
   350
    length = SCIF_sendq_size();
nkeynes@20
   351
    MMIO_WRITE( SCIF, SCFDR2, tmp | (length << 8) );
nkeynes@736
   352
nkeynes@20
   353
    /* Update flags if requested */
nkeynes@20
   354
    if( clearFlags ) {
nkeynes@736
   355
        tmp = SCFSR2_TEND;
nkeynes@736
   356
        if( length > SCIF_sendq.trigger ) {
nkeynes@736
   357
            tmp |= SCFSR2_TDFE;
nkeynes@736
   358
            if( IS_TRANSMIT_IRQ_ENABLED() )
nkeynes@736
   359
                intc_clear_interrupt( INT_SCIF_TXI );
nkeynes@736
   360
        }
nkeynes@736
   361
        tmp = MMIO_READ( SCIF, SCFSR2 ) & (~tmp);
nkeynes@736
   362
        MMIO_WRITE( SCIF, SCFSR2, tmp );
nkeynes@20
   363
    }
nkeynes@20
   364
    return TRUE;
nkeynes@20
   365
}
nkeynes@20
   366
nkeynes@20
   367
void SCIF_sendq_clear( void ) 
nkeynes@20
   368
{
nkeynes@20
   369
    SCIF_sendq.head = SCIF_sendq.tail = 0;
nkeynes@20
   370
    MMIO_WRITE( SCIF, SCFDR2, MMIO_READ( SCIF, SCFDR2 ) & 0x0F );
nkeynes@20
   371
    MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_TEND | SCFSR2_TDFE );
nkeynes@20
   372
    if( IS_TRANSMIT_IRQ_ENABLED() ) {
nkeynes@736
   373
        intc_raise_interrupt( INT_SCIF_TXI );
nkeynes@54
   374
        DMAC_trigger( DMAC_SCIF_TDE );
nkeynes@20
   375
    }
nkeynes@20
   376
}
nkeynes@20
   377
nkeynes@21
   378
/**
nkeynes@21
   379
 * Update the SCFSR2 status register with the given mask (ie clear any values
nkeynes@21
   380
 * that are set to 0 in the mask. According to a strict reading of the doco
nkeynes@21
   381
 * though, the bits will only actually clear if the flag state is no longer
nkeynes@21
   382
 * true, so we need to recheck everything...
nkeynes@21
   383
 */
nkeynes@21
   384
void SCIF_update_status( uint32_t mask )
nkeynes@21
   385
{
nkeynes@21
   386
    uint32_t value = MMIO_READ( SCIF, SCFSR2 );
nkeynes@21
   387
    uint32_t result = value & mask;
nkeynes@21
   388
    uint32_t sendq_size = SCIF_sendq_size();
nkeynes@21
   389
    uint32_t recvq_size = SCIF_recvq_size();
nkeynes@21
   390
nkeynes@21
   391
    if( sendq_size != 0 )
nkeynes@736
   392
        result |= SCFSR2_TEND;
nkeynes@21
   393
nkeynes@21
   394
    if( sendq_size <= SCIF_sendq.trigger )
nkeynes@736
   395
        result |= SCFSR2_TDFE;
nkeynes@428
   396
    else if( (result & SCFSR2_TDFE) == 0 && IS_TRANSMIT_IRQ_ENABLED() )
nkeynes@736
   397
        intc_clear_interrupt( INT_SCIF_TXI );
nkeynes@21
   398
nkeynes@21
   399
    if( recvq_size >= SCIF_recvq.trigger )
nkeynes@736
   400
        result |= SCFSR2_RDF;
nkeynes@21
   401
    if( (value & SCFSR2_DR) != 0 && (result & SCFSR2_DR) == 0 &&
nkeynes@736
   402
            recvq_size != 0 )
nkeynes@736
   403
        result |= SCFSR2_DR;
nkeynes@21
   404
    if( (result & (SCFSR2_DR|SCFSR2_RDF)) == 0 && IS_RECEIVE_IRQ_ENABLED() )
nkeynes@736
   405
        intc_clear_interrupt( INT_SCIF_RXI );
nkeynes@21
   406
nkeynes@21
   407
    if( IS_RECEIVE_ERROR_IRQ_ENABLED() ) {
nkeynes@736
   408
        if( (result & SCFSR2_BRK) == 0 )
nkeynes@736
   409
            intc_clear_interrupt( INT_SCIF_BRI );
nkeynes@736
   410
        if( (result & SCFSR2_ER) == 0 && 
nkeynes@736
   411
                (MMIO_READ( SCIF, SCLSR2 ) & SCLSR2_ORER) == 0 )
nkeynes@736
   412
            intc_clear_interrupt( INT_SCIF_ERI );
nkeynes@21
   413
    }
nkeynes@21
   414
}
nkeynes@20
   415
nkeynes@20
   416
/**
nkeynes@20
   417
 * Set the break detected flag
nkeynes@20
   418
 */
nkeynes@20
   419
void SCIF_set_break( void ) 
nkeynes@20
   420
{
nkeynes@20
   421
    MMIO_WRITE( SCIF, SCFSR2, MMIO_READ( SCIF, SCFSR2 ) | SCFSR2_BRK );
nkeynes@20
   422
    if( IS_RECEIVE_ERROR_IRQ_ENABLED() )
nkeynes@736
   423
        intc_raise_interrupt( INT_SCIF_BRI );
nkeynes@20
   424
}
nkeynes@20
   425
nkeynes@20
   426
const static int SCIF_CLOCK_MULTIPLIER[4] = {1, 4, 16, 64};
nkeynes@20
   427
nkeynes@20
   428
/**
nkeynes@20
   429
 * Calculate the current line speed.
nkeynes@20
   430
 */
nkeynes@20
   431
void SCIF_update_line_speed( void )
nkeynes@20
   432
{
nkeynes@20
   433
    /* If CKE1 is set, use the external clock as a base */
nkeynes@20
   434
    if( MMIO_READ( SCIF, SCSCR2 ) & SCSCR2_CKE ) {
nkeynes@20
   435
nkeynes@20
   436
nkeynes@20
   437
    } else {
nkeynes@20
   438
nkeynes@736
   439
        /* Otherwise, SH4 peripheral clock divided by n */
nkeynes@736
   440
        int mult = SCIF_CLOCK_MULTIPLIER[MMIO_READ( SCIF, SCSMR2 ) & 0x03];
nkeynes@20
   441
nkeynes@736
   442
        /* Then process the bitrate register */
nkeynes@736
   443
        int bbr = MMIO_READ( SCIF, SCBRR2 ) & 0xFF;
nkeynes@30
   444
nkeynes@736
   445
        int baudrate = sh4_peripheral_freq / (32 * mult * (bbr+1) );
nkeynes@30
   446
nkeynes@736
   447
        if( serial_device != NULL && serial_device->set_line_speed != NULL )
nkeynes@736
   448
            serial_device->set_line_speed( baudrate );
nkeynes@736
   449
nkeynes@736
   450
        SCIF_tick_period = sh4_peripheral_period * (32 * mult * (bbr+1));
nkeynes@736
   451
nkeynes@736
   452
        /*
nkeynes@20
   453
	  clock_set_tick_rate( CLOCK_SCIF, baudrate / 10 );
nkeynes@736
   454
         */
nkeynes@20
   455
    }
nkeynes@20
   456
}
nkeynes@20
   457
nkeynes@929
   458
MMIO_REGION_READ_FN( SCIF, reg )
nkeynes@20
   459
{
nkeynes@929
   460
    reg &= 0xFFF;
nkeynes@20
   461
    switch( reg ) {
nkeynes@20
   462
    case SCFRDR2: /* Receive data */
nkeynes@736
   463
        return SCIF_recvq_dequeue(FALSE);
nkeynes@20
   464
    default:
nkeynes@736
   465
        return MMIO_READ( SCIF, reg );
nkeynes@20
   466
    }
nkeynes@20
   467
}
nkeynes@20
   468
nkeynes@929
   469
MMIO_REGION_WRITE_FN( SCIF, reg, val )
nkeynes@20
   470
{
nkeynes@20
   471
    uint32_t tmp;
nkeynes@929
   472
    reg &= 0xFFF;
nkeynes@20
   473
    switch( reg ) {
nkeynes@20
   474
    case SCSMR2: /* Serial mode register */
nkeynes@736
   475
        /* Bit 6 => 0 = 8-bit, 1 = 7-bit
nkeynes@736
   476
         * Bit 5 => 0 = Parity disabled, 1 = parity enabled
nkeynes@736
   477
         * Bit 4 => 0 = Even parity, 1 = Odd parity
nkeynes@736
   478
         * Bit 3 => 0 = 1 stop bit, 1 = 2 stop bits
nkeynes@736
   479
         * Bits 0-1 => Clock select 00 = P, 01 = P/4, 10 = P/16, 11 = P/64
nkeynes@736
   480
         */
nkeynes@736
   481
        val &= 0x007B;
nkeynes@736
   482
        if( serial_device != NULL ) {
nkeynes@736
   483
            serial_device->set_line_params( val );
nkeynes@736
   484
        }
nkeynes@736
   485
        tmp = MMIO_READ( SCIF, SCSMR2 );
nkeynes@736
   486
        if( (tmp & 0x03) != (val & 0x03) ) {
nkeynes@736
   487
            /* Clock change */
nkeynes@736
   488
            SCIF_update_line_speed( );
nkeynes@736
   489
        }
nkeynes@736
   490
        /* Save for later read-back */
nkeynes@736
   491
        MMIO_WRITE( SCIF, SCSMR2, val );
nkeynes@736
   492
        break;
nkeynes@20
   493
    case SCBRR2: /* Bit rate register */
nkeynes@736
   494
        MMIO_WRITE( SCIF, SCBRR2, val );
nkeynes@736
   495
        SCIF_update_line_speed( );
nkeynes@736
   496
        break;
nkeynes@20
   497
    case SCSCR2: /* Serial control register */
nkeynes@736
   498
        /* Bit 7 => Transmit-FIFO-data-empty interrupt enabled 
nkeynes@736
   499
         * Bit 6 => Receive-data-full interrupt enabled 
nkeynes@736
   500
         * Bit 5 => Transmit enable 
nkeynes@736
   501
         * Bit 4 => Receive enable 
nkeynes@736
   502
         * Bit 3 => Receive-error/break interrupt enabled
nkeynes@736
   503
         * Bit 1 => Clock enable
nkeynes@736
   504
         */
nkeynes@736
   505
        val &= 0x00FA;
nkeynes@736
   506
        /* Clear any interrupts that just became disabled */
nkeynes@736
   507
        if( (val & SCSCR2_TIE) == 0 )
nkeynes@736
   508
            intc_clear_interrupt( INT_SCIF_TXI );
nkeynes@736
   509
        if( (val & SCSCR2_RIE) == 0 )
nkeynes@736
   510
            intc_clear_interrupt( INT_SCIF_RXI );
nkeynes@736
   511
        if( (val & (SCSCR2_RIE|SCSCR2_REIE)) == 0 ) {
nkeynes@736
   512
            intc_clear_interrupt( INT_SCIF_ERI );
nkeynes@736
   513
            intc_clear_interrupt( INT_SCIF_BRI );
nkeynes@736
   514
        }
nkeynes@736
   515
nkeynes@736
   516
        MMIO_WRITE( SCIF, reg, val );
nkeynes@736
   517
        break;
nkeynes@20
   518
    case SCFTDR2: /* Transmit FIFO data register */
nkeynes@736
   519
        SCIF_sendq_enqueue( val, FALSE );
nkeynes@736
   520
        break;
nkeynes@20
   521
    case SCFSR2: /* Serial status register */
nkeynes@736
   522
        /* Bits 12-15 Parity error count
nkeynes@736
   523
         * Bits 8-11 Framing erro count 
nkeynes@736
   524
         * Bit 7 - Receive error
nkeynes@736
   525
         * Bit 6 - Transmit end
nkeynes@736
   526
         * Bit 5 - Transmit FIFO data empty
nkeynes@736
   527
         * Bit 4 - Break detect
nkeynes@736
   528
         * Bit 3 - Framing error
nkeynes@736
   529
         * Bit 2 - Parity error
nkeynes@736
   530
         * Bit 1 - Receive FIFO data full
nkeynes@736
   531
         * Bit 0 - Receive data ready
nkeynes@736
   532
         */
nkeynes@736
   533
        /* Clear off any flags/interrupts that are being set to 0 */
nkeynes@736
   534
        SCIF_update_status( val );
nkeynes@736
   535
        break;
nkeynes@20
   536
    case SCFCR2: /* FIFO control register */
nkeynes@736
   537
        val &= 0x0F;
nkeynes@736
   538
        SCIF_recvq.trigger = SCIF_recvq_triggers[val >> 6];
nkeynes@736
   539
        SCIF_sendq.trigger = SCIF_sendq_triggers[(val >> 4) & 0x03];
nkeynes@736
   540
        if( val & SCFCR2_TFRST ) {
nkeynes@736
   541
            SCIF_sendq_clear();
nkeynes@736
   542
        }
nkeynes@736
   543
        if( val & SCFCR2_RFRST ) {
nkeynes@736
   544
            SCIF_recvq_clear();
nkeynes@736
   545
        }
nkeynes@20
   546
nkeynes@736
   547
        MMIO_WRITE( SCIF, reg, val );
nkeynes@736
   548
        break;
nkeynes@20
   549
    case SCSPTR2: /* Serial Port Register */
nkeynes@736
   550
        MMIO_WRITE( SCIF, reg, val );
nkeynes@828
   551
        /* NOT IMPLEMENTED - 'direct' serial I/O */
nkeynes@828
   552
        if( val != 0 ) {
nkeynes@828
   553
            WARN( "SCSPTR2 not implemented: Write %08X", val );
nkeynes@828
   554
        }
nkeynes@736
   555
        break;
nkeynes@20
   556
    case SCLSR2:
nkeynes@736
   557
        val = val & SCLSR2_ORER;
nkeynes@736
   558
        if( val == 0 ) {
nkeynes@736
   559
            MMIO_WRITE( SCIF, SCLSR2, val );
nkeynes@736
   560
            if( (MMIO_READ( SCIF, SCFSR2 ) & SCFSR2_ER) == 0 &&
nkeynes@736
   561
                    IS_RECEIVE_ERROR_IRQ_ENABLED() ) 
nkeynes@736
   562
                intc_clear_interrupt( INT_SCIF_ERI );
nkeynes@736
   563
        }
nkeynes@736
   564
nkeynes@736
   565
        break;
nkeynes@20
   566
    }
nkeynes@20
   567
}
nkeynes@20
   568
nkeynes@20
   569
/**
nkeynes@20
   570
 * Actions for a single tick of the serial clock, defined as the transmission
nkeynes@20
   571
 * time of a single frame.
nkeynes@20
   572
 *
nkeynes@20
   573
 * If transmit queue is non-empty:
nkeynes@20
   574
 *    Transmit one byte and remove from queue
nkeynes@20
   575
 * If input receive source is non-empty:
nkeynes@20
   576
 *    Transfer one byte to the receive queue (if queue is full, byte is lost)
nkeynes@20
   577
 * If recvq is non-empty, less than the trigger level, and no data has been
nkeynes@20
   578
 *    received in the last 2 ticks (including this one), set the DR flag and
nkeynes@20
   579
 *    IRQ if appropriate.
nkeynes@20
   580
 */
nkeynes@20
   581
void SCIF_clock_tick( void ) 
nkeynes@20
   582
{
nkeynes@20
   583
    gboolean rcvd = FALSE;
nkeynes@20
   584
nkeynes@20
   585
    if( IS_LOOPBACK_ENABLED() ) {
nkeynes@736
   586
        if( IS_TRANSMIT_ENABLED() ) {
nkeynes@736
   587
            int val = SCIF_sendq_dequeue();
nkeynes@736
   588
            if( val != -1 && IS_RECEIVE_ENABLED() ) {
nkeynes@736
   589
                SCIF_recvq_enqueue( val );
nkeynes@736
   590
                rcvd = TRUE;
nkeynes@736
   591
            }
nkeynes@736
   592
        }
nkeynes@20
   593
    } else {
nkeynes@736
   594
        if( IS_TRANSMIT_ENABLED() ) {
nkeynes@736
   595
            int val = SCIF_sendq_dequeue();
nkeynes@736
   596
            if( val != -1 && serial_device != NULL && 
nkeynes@736
   597
                    serial_device->receive_data != NULL ) {
nkeynes@736
   598
                serial_device->receive_data( val );
nkeynes@736
   599
            }
nkeynes@736
   600
        }
nkeynes@736
   601
nkeynes@736
   602
        if( IS_RECEIVE_ENABLED() ) {
nkeynes@736
   603
            int val = serial_transmit_dequeue();
nkeynes@736
   604
            if( val != -1 ) {
nkeynes@736
   605
                SCIF_recvq_enqueue( val );
nkeynes@736
   606
                rcvd = TRUE;
nkeynes@736
   607
            }
nkeynes@736
   608
        }
nkeynes@20
   609
    }
nkeynes@20
   610
nkeynes@20
   611
    /* Check if we need to set the DR flag */
nkeynes@20
   612
    if( !rcvd && !SCIF_rcvd_last_tick &&
nkeynes@736
   613
            SCIF_recvq.head != SCIF_recvq.tail &&
nkeynes@736
   614
            SCIF_recvq_size() < SCIF_recvq.trigger ) {
nkeynes@736
   615
        uint32_t tmp = MMIO_READ( SCIF, SCFSR2 );
nkeynes@736
   616
        if( (tmp & SCFSR2_DR) == 0 ) {
nkeynes@736
   617
            MMIO_WRITE( SCIF, SCFSR2, tmp | SCFSR2_DR );
nkeynes@736
   618
            if( IS_RECEIVE_IRQ_ENABLED() )
nkeynes@736
   619
                intc_raise_interrupt( INT_SCIF_RXI );
nkeynes@736
   620
            DMAC_trigger( DMAC_SCIF_RDF );
nkeynes@736
   621
        }
nkeynes@20
   622
    }
nkeynes@20
   623
    SCIF_rcvd_last_tick = rcvd;
nkeynes@20
   624
}
nkeynes@23
   625
nkeynes@30
   626
void SCIF_reset( void )
nkeynes@23
   627
{
nkeynes@32
   628
    SCIF_recvq_clear();
nkeynes@32
   629
    SCIF_sendq_clear();
nkeynes@32
   630
    SCIF_update_line_speed();
nkeynes@23
   631
}
nkeynes@30
   632
nkeynes@30
   633
void SCIF_run_slice( uint32_t nanosecs ) 
nkeynes@30
   634
{
nkeynes@30
   635
    SCIF_tick_remainder += nanosecs;
nkeynes@30
   636
    while( SCIF_tick_remainder >= SCIF_tick_period ) {
nkeynes@736
   637
        SCIF_tick_remainder -= SCIF_tick_period;
nkeynes@736
   638
        SCIF_clock_tick();
nkeynes@30
   639
    }
nkeynes@30
   640
}
.