Search
lxdream.org :: lxdream/src/sh4/timer.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/timer.c
changeset 30:89b30313d757
prev23:1ec3acd0594d
next53:f2981805b929
author nkeynes
date Mon Dec 26 03:10:23 2005 +0000 (18 years ago)
permissions -rw-r--r--
last change Reset SCIF properly on SH4 reset
file annotate diff log raw
nkeynes@23
     1
/**
nkeynes@30
     2
 * $Id: timer.c,v 1.2 2005-12-25 05:57:00 nkeynes Exp $
nkeynes@23
     3
 * 
nkeynes@23
     4
 * SH4 Timer/Clock peripheral modules (CPG, TMU, RTC), combined together to
nkeynes@23
     5
 * keep things simple (they intertwine a bit).
nkeynes@23
     6
 *
nkeynes@23
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@23
     8
 *
nkeynes@23
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@23
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@23
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@23
    12
 * (at your option) any later version.
nkeynes@23
    13
 *
nkeynes@23
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@23
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@23
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@23
    17
 * GNU General Public License for more details.
nkeynes@23
    18
 */
nkeynes@23
    19
nkeynes@23
    20
#include "dream.h"
nkeynes@23
    21
#include "mem.h"
nkeynes@23
    22
#include "clock.h"
nkeynes@23
    23
#include "sh4core.h"
nkeynes@23
    24
#include "sh4mmio.h"
nkeynes@23
    25
nkeynes@23
    26
/********************************* CPG *************************************/
nkeynes@23
    27
nkeynes@23
    28
int32_t mmio_region_CPG_read( uint32_t reg )
nkeynes@23
    29
{
nkeynes@23
    30
    return MMIO_READ( CPG, reg );
nkeynes@23
    31
}
nkeynes@23
    32
nkeynes@23
    33
void mmio_region_CPG_write( uint32_t reg, uint32_t val )
nkeynes@23
    34
{
nkeynes@23
    35
    MMIO_WRITE( CPG, reg, val );
nkeynes@23
    36
}
nkeynes@23
    37
nkeynes@23
    38
/********************************** RTC *************************************/
nkeynes@23
    39
nkeynes@23
    40
int32_t mmio_region_RTC_read( uint32_t reg )
nkeynes@23
    41
{
nkeynes@23
    42
    return MMIO_READ( RTC, reg );
nkeynes@23
    43
}
nkeynes@23
    44
nkeynes@23
    45
void mmio_region_RTC_write( uint32_t reg, uint32_t val )
nkeynes@23
    46
{
nkeynes@23
    47
    MMIO_WRITE( RTC, reg, val );
nkeynes@23
    48
}
nkeynes@23
    49
nkeynes@23
    50
/********************************** TMU *************************************/
nkeynes@23
    51
nkeynes@23
    52
int timer_divider[3] = {16,16,16};
nkeynes@23
    53
nkeynes@23
    54
int32_t mmio_region_TMU_read( uint32_t reg )
nkeynes@23
    55
{
nkeynes@23
    56
    return MMIO_READ( TMU, reg );
nkeynes@23
    57
}
nkeynes@23
    58
nkeynes@23
    59
nkeynes@23
    60
int get_timer_div( int val )
nkeynes@23
    61
{
nkeynes@23
    62
    switch( val & 0x07 ) {
nkeynes@23
    63
        case 0: return 16; /* assume peripheral clock is IC/4 */
nkeynes@23
    64
        case 1: return 64;
nkeynes@23
    65
        case 2: return 256;
nkeynes@23
    66
        case 3: return 1024;
nkeynes@23
    67
        case 4: return 4096;
nkeynes@23
    68
    }
nkeynes@23
    69
    return 1;
nkeynes@23
    70
}
nkeynes@23
    71
nkeynes@23
    72
void mmio_region_TMU_write( uint32_t reg, uint32_t val )
nkeynes@23
    73
{
nkeynes@23
    74
    switch( reg ) {
nkeynes@23
    75
        case TCR0:
nkeynes@23
    76
            timer_divider[0] = get_timer_div(val);
nkeynes@23
    77
            break;
nkeynes@23
    78
        case TCR1:
nkeynes@23
    79
            timer_divider[1] = get_timer_div(val);
nkeynes@23
    80
            break;
nkeynes@23
    81
        case TCR2:
nkeynes@23
    82
            timer_divider[2] = get_timer_div(val);
nkeynes@23
    83
            break;
nkeynes@23
    84
    }
nkeynes@23
    85
    MMIO_WRITE( TMU, reg, val );
nkeynes@23
    86
}
nkeynes@23
    87
nkeynes@30
    88
void TMU_run_slice( uint32_t nanosecs )
nkeynes@23
    89
{
nkeynes@23
    90
    int tcr = MMIO_READ( TMU, TSTR );
nkeynes@30
    91
    int cycles = nanosecs / sh4_peripheral_period;
nkeynes@23
    92
    if( tcr & 0x01 ) {
nkeynes@23
    93
        int count = cycles / timer_divider[0];
nkeynes@23
    94
        int *val = MMIO_REG( TMU, TCNT0 );
nkeynes@23
    95
        if( *val < count ) {
nkeynes@23
    96
            MMIO_READ( TMU, TCR0 ) |= 0x100;
nkeynes@23
    97
            /* interrupt goes here */
nkeynes@23
    98
            count -= *val;
nkeynes@23
    99
            *val = MMIO_READ( TMU, TCOR0 ) - count;
nkeynes@23
   100
        } else {
nkeynes@23
   101
            *val -= count;
nkeynes@23
   102
        }
nkeynes@23
   103
    }
nkeynes@23
   104
    if( tcr & 0x02 ) {
nkeynes@23
   105
        int count = cycles / timer_divider[1];
nkeynes@23
   106
        int *val = MMIO_REG( TMU, TCNT1 );
nkeynes@23
   107
        if( *val < count ) {
nkeynes@23
   108
            MMIO_READ( TMU, TCR1 ) |= 0x100;
nkeynes@23
   109
            /* interrupt goes here */
nkeynes@23
   110
            count -= *val;
nkeynes@23
   111
            *val = MMIO_READ( TMU, TCOR1 ) - count;
nkeynes@23
   112
        } else {
nkeynes@23
   113
            *val -= count;
nkeynes@23
   114
        }
nkeynes@23
   115
    }
nkeynes@23
   116
    if( tcr & 0x04 ) {
nkeynes@23
   117
        int count = cycles / timer_divider[2];
nkeynes@23
   118
        int *val = MMIO_REG( TMU, TCNT2 );
nkeynes@23
   119
        if( *val < count ) {
nkeynes@23
   120
            MMIO_READ( TMU, TCR2 ) |= 0x100;
nkeynes@23
   121
            /* interrupt goes here */
nkeynes@23
   122
            count -= *val;
nkeynes@23
   123
            *val = MMIO_READ( TMU, TCOR2 ) - count;
nkeynes@23
   124
        } else {
nkeynes@23
   125
            *val -= count;
nkeynes@23
   126
        }
nkeynes@23
   127
    }
nkeynes@23
   128
}
.