nkeynes@23: /** nkeynes@30: * $Id: timer.c,v 1.2 2005-12-25 05:57:00 nkeynes Exp $ nkeynes@23: * nkeynes@23: * SH4 Timer/Clock peripheral modules (CPG, TMU, RTC), combined together to nkeynes@23: * keep things simple (they intertwine a bit). nkeynes@23: * nkeynes@23: * Copyright (c) 2005 Nathan Keynes. nkeynes@23: * nkeynes@23: * This program is free software; you can redistribute it and/or modify nkeynes@23: * it under the terms of the GNU General Public License as published by nkeynes@23: * the Free Software Foundation; either version 2 of the License, or nkeynes@23: * (at your option) any later version. nkeynes@23: * nkeynes@23: * This program is distributed in the hope that it will be useful, nkeynes@23: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@23: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@23: * GNU General Public License for more details. nkeynes@23: */ nkeynes@23: nkeynes@23: #include "dream.h" nkeynes@23: #include "mem.h" nkeynes@23: #include "clock.h" nkeynes@23: #include "sh4core.h" nkeynes@23: #include "sh4mmio.h" nkeynes@23: nkeynes@23: /********************************* CPG *************************************/ nkeynes@23: nkeynes@23: int32_t mmio_region_CPG_read( uint32_t reg ) nkeynes@23: { nkeynes@23: return MMIO_READ( CPG, reg ); nkeynes@23: } nkeynes@23: nkeynes@23: void mmio_region_CPG_write( uint32_t reg, uint32_t val ) nkeynes@23: { nkeynes@23: MMIO_WRITE( CPG, reg, val ); nkeynes@23: } nkeynes@23: nkeynes@23: /********************************** RTC *************************************/ nkeynes@23: nkeynes@23: int32_t mmio_region_RTC_read( uint32_t reg ) nkeynes@23: { nkeynes@23: return MMIO_READ( RTC, reg ); nkeynes@23: } nkeynes@23: nkeynes@23: void mmio_region_RTC_write( uint32_t reg, uint32_t val ) nkeynes@23: { nkeynes@23: MMIO_WRITE( RTC, reg, val ); nkeynes@23: } nkeynes@23: nkeynes@23: /********************************** TMU *************************************/ nkeynes@23: nkeynes@23: int timer_divider[3] = {16,16,16}; nkeynes@23: nkeynes@23: int32_t mmio_region_TMU_read( uint32_t reg ) nkeynes@23: { nkeynes@23: return MMIO_READ( TMU, reg ); nkeynes@23: } nkeynes@23: nkeynes@23: nkeynes@23: int get_timer_div( int val ) nkeynes@23: { nkeynes@23: switch( val & 0x07 ) { nkeynes@23: case 0: return 16; /* assume peripheral clock is IC/4 */ nkeynes@23: case 1: return 64; nkeynes@23: case 2: return 256; nkeynes@23: case 3: return 1024; nkeynes@23: case 4: return 4096; nkeynes@23: } nkeynes@23: return 1; nkeynes@23: } nkeynes@23: nkeynes@23: void mmio_region_TMU_write( uint32_t reg, uint32_t val ) nkeynes@23: { nkeynes@23: switch( reg ) { nkeynes@23: case TCR0: nkeynes@23: timer_divider[0] = get_timer_div(val); nkeynes@23: break; nkeynes@23: case TCR1: nkeynes@23: timer_divider[1] = get_timer_div(val); nkeynes@23: break; nkeynes@23: case TCR2: nkeynes@23: timer_divider[2] = get_timer_div(val); nkeynes@23: break; nkeynes@23: } nkeynes@23: MMIO_WRITE( TMU, reg, val ); nkeynes@23: } nkeynes@23: nkeynes@30: void TMU_run_slice( uint32_t nanosecs ) nkeynes@23: { nkeynes@23: int tcr = MMIO_READ( TMU, TSTR ); nkeynes@30: int cycles = nanosecs / sh4_peripheral_period; nkeynes@23: if( tcr & 0x01 ) { nkeynes@23: int count = cycles / timer_divider[0]; nkeynes@23: int *val = MMIO_REG( TMU, TCNT0 ); nkeynes@23: if( *val < count ) { nkeynes@23: MMIO_READ( TMU, TCR0 ) |= 0x100; nkeynes@23: /* interrupt goes here */ nkeynes@23: count -= *val; nkeynes@23: *val = MMIO_READ( TMU, TCOR0 ) - count; nkeynes@23: } else { nkeynes@23: *val -= count; nkeynes@23: } nkeynes@23: } nkeynes@23: if( tcr & 0x02 ) { nkeynes@23: int count = cycles / timer_divider[1]; nkeynes@23: int *val = MMIO_REG( TMU, TCNT1 ); nkeynes@23: if( *val < count ) { nkeynes@23: MMIO_READ( TMU, TCR1 ) |= 0x100; nkeynes@23: /* interrupt goes here */ nkeynes@23: count -= *val; nkeynes@23: *val = MMIO_READ( TMU, TCOR1 ) - count; nkeynes@23: } else { nkeynes@23: *val -= count; nkeynes@23: } nkeynes@23: } nkeynes@23: if( tcr & 0x04 ) { nkeynes@23: int count = cycles / timer_divider[2]; nkeynes@23: int *val = MMIO_REG( TMU, TCNT2 ); nkeynes@23: if( *val < count ) { nkeynes@23: MMIO_READ( TMU, TCR2 ) |= 0x100; nkeynes@23: /* interrupt goes here */ nkeynes@23: count -= *val; nkeynes@23: *val = MMIO_READ( TMU, TCOR2 ) - count; nkeynes@23: } else { nkeynes@23: *val -= count; nkeynes@23: } nkeynes@23: } nkeynes@23: }