Search
lxdream.org :: lxdream/src/sh4/sh4mmio.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mmio.c
changeset 19:9da7a8e38f9d
prev10:c898b37506e0
next23:1ec3acd0594d
author nkeynes
date Thu Dec 22 07:38:12 2005 +0000 (17 years ago)
permissions -rw-r--r--
last change Implement 95% of the SCIF serial interface
Implement basic load_bin_file function to try to load demos directly
Update TMU to run all 3 timers, start on general timing
file annotate diff log raw
nkeynes@1
     1
#include "dream.h"
nkeynes@1
     2
#include "mem.h"
nkeynes@19
     3
#include "clock.h"
nkeynes@1
     4
#include "sh4core.h"
nkeynes@1
     5
#include "sh4mmio.h"
nkeynes@1
     6
#define MMIO_IMPL
nkeynes@1
     7
#include "sh4mmio.h"
nkeynes@1
     8
nkeynes@1
     9
/********************************* MMU *************************************/
nkeynes@1
    10
nkeynes@1
    11
MMIO_REGION_READ_STUBFN( MMU )
nkeynes@1
    12
nkeynes@10
    13
#define OCRAM_START (0x1C000000>>PAGE_BITS)
nkeynes@10
    14
#define OCRAM_END   (0x20000000>>PAGE_BITS)
nkeynes@10
    15
nkeynes@10
    16
static char *cache = NULL;
nkeynes@10
    17
nkeynes@1
    18
void mmio_region_MMU_write( uint32_t reg, uint32_t val )
nkeynes@1
    19
{
nkeynes@1
    20
    switch(reg) {
nkeynes@1
    21
        case CCR:
nkeynes@10
    22
            mmu_set_cache_mode( val & (CCR_OIX|CCR_ORA) );
nkeynes@1
    23
            INFO( "Cache mode set to %08X", val );
nkeynes@1
    24
            break;
nkeynes@1
    25
        default:
nkeynes@1
    26
            break;
nkeynes@1
    27
    }
nkeynes@1
    28
    MMIO_WRITE( MMU, reg, val );
nkeynes@1
    29
}
nkeynes@1
    30
nkeynes@1
    31
nkeynes@10
    32
void mmu_init() 
nkeynes@10
    33
{
nkeynes@19
    34
    cache = mem_alloc_pages(2);
nkeynes@10
    35
}
nkeynes@10
    36
nkeynes@10
    37
void mmu_set_cache_mode( int mode )
nkeynes@10
    38
{
nkeynes@10
    39
    uint32_t i;
nkeynes@10
    40
    switch( mode ) {
nkeynes@10
    41
        case MEM_OC_INDEX0: /* OIX=0 */
nkeynes@10
    42
            for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@10
    43
                page_map[i] = cache + ((i&0x02)<<(PAGE_BITS-1));
nkeynes@10
    44
            break;
nkeynes@10
    45
        case MEM_OC_INDEX1: /* OIX=1 */
nkeynes@10
    46
            for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@10
    47
                page_map[i] = cache + ((i&0x02000000)>>(25-PAGE_BITS));
nkeynes@10
    48
            break;
nkeynes@10
    49
        default: /* disabled */
nkeynes@10
    50
            for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@10
    51
                page_map[i] = NULL;
nkeynes@10
    52
            break;
nkeynes@10
    53
    }
nkeynes@10
    54
}
nkeynes@10
    55
nkeynes@10
    56
nkeynes@1
    57
/********************************* BSC *************************************/
nkeynes@1
    58
nkeynes@1
    59
uint16_t bsc_output_mask_lo = 0, bsc_output_mask_hi = 0;
nkeynes@1
    60
uint16_t bsc_input_mask_lo = 0, bsc_input_mask_hi = 0;
nkeynes@1
    61
uint32_t bsc_output = 0, bsc_input = 0x0300;
nkeynes@1
    62
nkeynes@1
    63
void bsc_out( int output, int mask )
nkeynes@1
    64
{
nkeynes@1
    65
    /* Go figure... The BIOS won't start without this mess though */
nkeynes@1
    66
    if( ((output | (~mask)) & 0x03) == 3 ) {
nkeynes@1
    67
        bsc_output |= 0x03;
nkeynes@1
    68
    } else {
nkeynes@1
    69
        bsc_output &= ~0x03;
nkeynes@1
    70
    }
nkeynes@1
    71
}
nkeynes@1
    72
nkeynes@1
    73
void mmio_region_BSC_write( uint32_t reg, uint32_t val )
nkeynes@1
    74
{
nkeynes@1
    75
    int i;
nkeynes@1
    76
    switch( reg ) {
nkeynes@1
    77
        case PCTRA:
nkeynes@1
    78
            bsc_input_mask_lo = bsc_output_mask_lo = 0;
nkeynes@1
    79
            for( i=0; i<16; i++ ) {
nkeynes@1
    80
                int bits = (val >> (i<<1)) & 0x03;
nkeynes@1
    81
                if( bits == 2 ) bsc_input_mask_lo |= (1<<i);
nkeynes@1
    82
                else if( bits != 0 ) bsc_output_mask_lo |= (1<<i);
nkeynes@1
    83
            }
nkeynes@1
    84
            bsc_output = (bsc_output&0x000F0000) |
nkeynes@1
    85
                (MMIO_READ( BSC, PDTRA ) & bsc_output_mask_lo);
nkeynes@1
    86
            bsc_out( MMIO_READ( BSC, PDTRA ) | ((MMIO_READ(BSC,PDTRB)<<16)),
nkeynes@1
    87
                     bsc_output_mask_lo | (bsc_output_mask_hi<<16) );
nkeynes@1
    88
            break;
nkeynes@1
    89
        case PCTRB:
nkeynes@1
    90
            bsc_input_mask_hi = bsc_output_mask_hi = 0;
nkeynes@1
    91
            for( i=0; i<4; i++ ) {
nkeynes@1
    92
                int bits = (val >> (i>>1)) & 0x03;
nkeynes@1
    93
                if( bits == 2 ) bsc_input_mask_hi |= (1<<i);
nkeynes@1
    94
                else if( bits != 0 ) bsc_output_mask_hi |= (1<<i);
nkeynes@1
    95
            }
nkeynes@1
    96
            bsc_output = (bsc_output&0xFFFF) |
nkeynes@1
    97
                ((MMIO_READ( BSC, PDTRA ) & bsc_output_mask_hi)<<16);
nkeynes@1
    98
            break;
nkeynes@1
    99
        case PDTRA:
nkeynes@1
   100
            bsc_output = (bsc_output&0x000F0000) |
nkeynes@1
   101
                (val & bsc_output_mask_lo );
nkeynes@1
   102
            bsc_out( val | ((MMIO_READ(BSC,PDTRB)<<16)),
nkeynes@1
   103
                     bsc_output_mask_lo | (bsc_output_mask_hi<<16) );
nkeynes@1
   104
            break;
nkeynes@1
   105
        case PDTRB:
nkeynes@1
   106
            bsc_output = (bsc_output&0xFFFF) |
nkeynes@1
   107
                ( (val & bsc_output_mask_hi)<<16 );
nkeynes@1
   108
            break;
nkeynes@1
   109
    }
nkeynes@1
   110
    WARN( "Write to (mostly) unimplemented BSC (%03X <= %08X) [%s: %s]",
nkeynes@1
   111
          reg, val, MMIO_REGID(BSC,reg), MMIO_REGDESC(BSC,reg) );
nkeynes@1
   112
    MMIO_WRITE( BSC, reg, val );
nkeynes@1
   113
}
nkeynes@1
   114
nkeynes@1
   115
int32_t mmio_region_BSC_read( uint32_t reg )
nkeynes@1
   116
{
nkeynes@1
   117
    int32_t val;
nkeynes@1
   118
    switch( reg ) {
nkeynes@1
   119
        case PDTRA:
nkeynes@1
   120
            val = (bsc_input & bsc_input_mask_lo) | (bsc_output&0xFFFF);
nkeynes@1
   121
            break;
nkeynes@1
   122
        case PDTRB:
nkeynes@1
   123
            val = ((bsc_input>>16) & bsc_input_mask_hi) | (bsc_output>>16);
nkeynes@1
   124
            break;
nkeynes@1
   125
        default:
nkeynes@1
   126
            val = MMIO_READ( BSC, reg );
nkeynes@1
   127
    }
nkeynes@1
   128
    WARN( "Read from (mostly) unimplemented BSC (%03X => %08X) [%s: %s]",
nkeynes@1
   129
          reg, val, MMIO_REGID(BSC,reg), MMIO_REGDESC(BSC,reg) );
nkeynes@1
   130
    return val;
nkeynes@1
   131
}
nkeynes@1
   132
nkeynes@1
   133
/********************************* UBC *************************************/
nkeynes@1
   134
nkeynes@1
   135
MMIO_REGION_STUBFNS( UBC )
nkeynes@1
   136
nkeynes@1
   137
/********************************* CPG *************************************/
nkeynes@1
   138
nkeynes@19
   139
uint32_t sh4_freq = SH4_BASE_RATE;
nkeynes@19
   140
uint32_t sh4_bus_freq = SH4_BASE_RATE;
nkeynes@19
   141
uint32_t sh4_peripheral_freq = SH4_BASE_RATE / 2;
nkeynes@19
   142
nkeynes@19
   143
nkeynes@1
   144
MMIO_REGION_STUBFNS( CPG )
nkeynes@1
   145
nkeynes@1
   146
/********************************* DMAC *************************************/
nkeynes@1
   147
nkeynes@1
   148
MMIO_REGION_STUBFNS( DMAC )
nkeynes@1
   149
nkeynes@1
   150
/********************************** RTC *************************************/
nkeynes@1
   151
nkeynes@1
   152
MMIO_REGION_STUBFNS( RTC )
nkeynes@1
   153
nkeynes@1
   154
/********************************** TMU *************************************/
nkeynes@1
   155
nkeynes@1
   156
int timer_divider[3] = {16,16,16};
nkeynes@1
   157
MMIO_REGION_READ_DEFFN( TMU )
nkeynes@1
   158
nkeynes@1
   159
int get_timer_div( int val )
nkeynes@1
   160
{
nkeynes@1
   161
    switch( val & 0x07 ) {
nkeynes@1
   162
        case 0: return 16; /* assume peripheral clock is IC/4 */
nkeynes@1
   163
        case 1: return 64;
nkeynes@1
   164
        case 2: return 256;
nkeynes@1
   165
        case 3: return 1024;
nkeynes@1
   166
        case 4: return 4096;
nkeynes@1
   167
    }
nkeynes@1
   168
    return 1;
nkeynes@1
   169
}
nkeynes@1
   170
nkeynes@1
   171
void mmio_region_TMU_write( uint32_t reg, uint32_t val )
nkeynes@1
   172
{
nkeynes@1
   173
    switch( reg ) {
nkeynes@1
   174
        case TCR0:
nkeynes@1
   175
            timer_divider[0] = get_timer_div(val);
nkeynes@1
   176
            break;
nkeynes@1
   177
        case TCR1:
nkeynes@1
   178
            timer_divider[1] = get_timer_div(val);
nkeynes@1
   179
            break;
nkeynes@1
   180
        case TCR2:
nkeynes@1
   181
            timer_divider[2] = get_timer_div(val);
nkeynes@1
   182
            break;
nkeynes@1
   183
    }
nkeynes@1
   184
    MMIO_WRITE( TMU, reg, val );
nkeynes@1
   185
}
nkeynes@1
   186
nkeynes@1
   187
void run_timers( int cycles )
nkeynes@1
   188
{
nkeynes@1
   189
    int tcr = MMIO_READ( TMU, TSTR );
nkeynes@1
   190
    cycles *= 16;
nkeynes@19
   191
    if( tcr & 0x01 ) {
nkeynes@1
   192
        int count = cycles / timer_divider[0];
nkeynes@1
   193
        int *val = MMIO_REG( TMU, TCNT0 );
nkeynes@1
   194
        if( *val < count ) {
nkeynes@1
   195
            MMIO_READ( TMU, TCR0 ) |= 0x100;
nkeynes@1
   196
            /* interrupt goes here */
nkeynes@1
   197
            count -= *val;
nkeynes@1
   198
            *val = MMIO_READ( TMU, TCOR0 ) - count;
nkeynes@1
   199
        } else {
nkeynes@1
   200
            *val -= count;
nkeynes@1
   201
        }
nkeynes@1
   202
    }
nkeynes@19
   203
    if( tcr & 0x02 ) {
nkeynes@19
   204
        int count = cycles / timer_divider[1];
nkeynes@19
   205
        int *val = MMIO_REG( TMU, TCNT1 );
nkeynes@19
   206
        if( *val < count ) {
nkeynes@19
   207
            MMIO_READ( TMU, TCR1 ) |= 0x100;
nkeynes@19
   208
            /* interrupt goes here */
nkeynes@19
   209
            count -= *val;
nkeynes@19
   210
            *val = MMIO_READ( TMU, TCOR1 ) - count;
nkeynes@19
   211
        } else {
nkeynes@19
   212
            *val -= count;
nkeynes@19
   213
        }
nkeynes@19
   214
    }
nkeynes@19
   215
    if( tcr & 0x04 ) {
nkeynes@19
   216
        int count = cycles / timer_divider[2];
nkeynes@19
   217
        int *val = MMIO_REG( TMU, TCNT2 );
nkeynes@19
   218
        if( *val < count ) {
nkeynes@19
   219
            MMIO_READ( TMU, TCR2 ) |= 0x100;
nkeynes@19
   220
            /* interrupt goes here */
nkeynes@19
   221
            count -= *val;
nkeynes@19
   222
            *val = MMIO_READ( TMU, TCOR2 ) - count;
nkeynes@19
   223
        } else {
nkeynes@19
   224
            *val -= count;
nkeynes@19
   225
        }
nkeynes@19
   226
    }
nkeynes@1
   227
}
nkeynes@1
   228
nkeynes@1
   229
/********************************** SCI *************************************/
nkeynes@1
   230
nkeynes@1
   231
MMIO_REGION_STUBFNS( SCI )
nkeynes@1
   232
.