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