2018-08-01 20:41:36 +02:00
|
|
|
//---
|
|
|
|
// gint:tmu - Timer operation
|
|
|
|
//---
|
|
|
|
|
|
|
|
#include <gint/timer.h>
|
|
|
|
#include <gint/drivers.h>
|
2021-04-23 18:50:20 +02:00
|
|
|
#include <gint/drivers/states.h>
|
2018-08-19 17:11:37 +02:00
|
|
|
#include <gint/clock.h>
|
2020-06-20 17:18:51 +02:00
|
|
|
#include <gint/intc.h>
|
2019-07-16 21:32:20 +02:00
|
|
|
#include <gint/mpu/tmu.h>
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-06-20 22:45:46 +02:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#undef timer_setup
|
2018-08-01 20:41:36 +02:00
|
|
|
|
|
|
|
//---
|
2020-05-10 14:03:41 +02:00
|
|
|
// Driver storage
|
2018-08-01 20:41:36 +02:00
|
|
|
//---
|
|
|
|
|
|
|
|
/* inth_data_t - data storage inside interrupt handlers */
|
|
|
|
typedef struct
|
|
|
|
{
|
2020-06-20 22:45:46 +02:00
|
|
|
void *function; /* User-provided callback */
|
|
|
|
uint32_t arg; /* Argument for function */
|
|
|
|
volatile void *TCR; /* TCR address for TMU */
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2019-02-21 20:58:38 +01:00
|
|
|
} GPACKED(4) inth_data_t;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
/* This array references the storage areas of all timer handlers */
|
2020-07-10 16:36:05 +02:00
|
|
|
static inth_data_t *timers[9] = { NULL };
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
/* Arrays of standard and extra timers */
|
2020-07-10 16:36:05 +02:00
|
|
|
static tmu_t *TMU = SH7305_TMU.TMU;
|
|
|
|
static etmu_t *ETMU = SH7305_ETMU;
|
2018-08-01 20:41:36 +02:00
|
|
|
/* TSTR register for standard timers */
|
2020-07-10 16:36:05 +02:00
|
|
|
static volatile uint8_t *TSTR = &SH7305_TMU.TSTR;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
|
|
|
//---
|
2020-06-20 22:45:46 +02:00
|
|
|
// Local functions
|
2018-08-01 20:41:36 +02:00
|
|
|
//---
|
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
/* conf(): Configure a fixed timer */
|
|
|
|
static void conf(int id, uint32_t delay, int clock, void *f, uint32_t arg)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2019-07-18 21:18:36 +02:00
|
|
|
if(id < 3)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
|
|
|
/* Refuse to setup timers that are already in use */
|
2020-05-10 14:03:41 +02:00
|
|
|
tmu_t *T = &TMU[id];
|
2020-06-20 22:45:46 +02:00
|
|
|
if(T->TCR.UNIE || *TSTR & (1 << id)) return;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
/* Configure the counter, clear interrupt flag*/
|
|
|
|
T->TCOR = delay;
|
|
|
|
T->TCNT = delay;
|
|
|
|
T->TCR.TPSC = clock;
|
|
|
|
do T->TCR.UNF = 0;
|
|
|
|
while(T->TCR.UNF);
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2019-07-18 21:18:36 +02:00
|
|
|
/* Enable interrupt and count on rising edge (SH7705) */
|
2020-05-10 14:03:41 +02:00
|
|
|
T->TCR.UNIE = 1;
|
|
|
|
T->TCR.CKEG = 0;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-10 14:03:41 +02:00
|
|
|
etmu_t *T = &ETMU[id-3];
|
2020-06-20 22:45:46 +02:00
|
|
|
if(T->TCR.UNIE) return;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-06-20 22:45:46 +02:00
|
|
|
/* No clock input and clock edge here. But TCR and TCNT need
|
|
|
|
some time to execute the write */
|
2020-05-10 14:03:41 +02:00
|
|
|
do T->TCR.UNF = 0;
|
|
|
|
while(T->TCR.UNF);
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
do T->TCOR = delay;
|
|
|
|
while(T->TCOR != delay);
|
2019-02-21 20:58:38 +01:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
do T->TCNT = delay;
|
|
|
|
while(T->TCNT != delay);
|
2019-02-21 20:58:38 +01:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
T->TCR.UNIE = 1;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
2020-06-20 22:45:46 +02:00
|
|
|
timers[id]->function = f;
|
2020-05-10 14:03:41 +02:00
|
|
|
timers[id]->arg = arg;
|
2020-06-20 22:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* matches(): Check if a timer matches the provided specification and delay */
|
|
|
|
static int matches(int id, int spec, uint32_t delay)
|
|
|
|
{
|
|
|
|
/* A specific idea only matches the exact timer */
|
|
|
|
if(spec >= 0) return id == (spec & 0xf);
|
|
|
|
/* TIMER_ANY always matches ETMU only for delays at least 100 µs */
|
|
|
|
if(spec == TIMER_ANY) return (id < 3 || delay >= 100);
|
|
|
|
/* TIMER_TMU and TIMER_ETMU match as you'd expect */
|
|
|
|
if(spec == TIMER_TMU) return (id < 3);
|
|
|
|
if(spec == TIMER_ETMU) return (id >= 3);
|
|
|
|
/* Default is not matching */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* available(): Check if a timer is available (UNIE cleared, not running) */
|
|
|
|
static int available(int id)
|
|
|
|
{
|
|
|
|
/* The timer should also be installed... */
|
|
|
|
if(!timers[id]) return 0;
|
|
|
|
|
|
|
|
if(id < 3)
|
|
|
|
{
|
|
|
|
tmu_t *T = &TMU[id];
|
|
|
|
return !T->TCR.UNIE && !(*TSTR & (1 << id));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
etmu_t *T = &ETMU[id-3];
|
|
|
|
return !T->TCR.UNIE && !T->TSTR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stop_callback(): Empty callback that stops the timer */
|
|
|
|
static int stop_callback(void)
|
|
|
|
{
|
|
|
|
return TIMER_STOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Timer API
|
|
|
|
//---
|
|
|
|
|
|
|
|
/* timer_setup(): Reserve and configure a timer */
|
|
|
|
int timer_setup(int spec, uint64_t delay, timer_callback_t function, ...)
|
|
|
|
{
|
|
|
|
int clock = 0;
|
|
|
|
|
|
|
|
/* Get the optional argument */
|
|
|
|
va_list va;
|
|
|
|
va_start(va, function);
|
|
|
|
uint32_t arg = va_arg(va, uint32_t);
|
|
|
|
va_end(va);
|
|
|
|
|
|
|
|
/* Default value for the callback */
|
|
|
|
if(!function.v) function.v = stop_callback;
|
|
|
|
|
|
|
|
/* Find a matching timer, starting from the slowest timers with the
|
|
|
|
smallest interrupt priorities all the way up to TMU0 */
|
|
|
|
for(int id = timer_count() - 1; id >= 0; id--)
|
|
|
|
{
|
|
|
|
if(!matches(id, spec, delay) || !available(id)) continue;
|
|
|
|
|
|
|
|
/* If ID is a TMU, choose a timer prescaler. Assuming the worst
|
|
|
|
running Pphi of ~48 MHz, select the finest resolution that
|
|
|
|
allows the requested delay to be represented. */
|
|
|
|
if(id < 3 && spec >= 0)
|
|
|
|
{
|
|
|
|
/* Explicit timers with clock in the specification */
|
|
|
|
clock = (spec >> 4) & 0xf;
|
|
|
|
}
|
|
|
|
else if(id < 3)
|
|
|
|
{
|
|
|
|
uint64_t sec = 1000000;
|
|
|
|
|
|
|
|
/* Pphi/4 until 350 seconds */
|
|
|
|
if(delay <= 350 * sec) clock = TIMER_Pphi_4;
|
|
|
|
/* Pphi/16 until 1430 seconds */
|
|
|
|
else if(delay <= 1430 * sec) clock = TIMER_Pphi_16;
|
|
|
|
/* Pphi/64 until 5720 seconds */
|
|
|
|
else if(delay <= 5720 * sec) clock = TIMER_Pphi_64;
|
|
|
|
/* Pphi/256 otherwise */
|
|
|
|
else clock = TIMER_Pphi_256;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the delay constant for that timer and clock */
|
|
|
|
if(spec < 0) delay = timer_delay(id, delay, clock);
|
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
conf(id, delay, clock, function.v, arg);
|
2020-06-20 22:45:46 +02:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* timer_delay() - compute a delay constant from a duration in seconds */
|
2020-06-20 22:45:46 +02:00
|
|
|
uint32_t timer_delay(int id, uint64_t delay_us, int clock)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2020-06-20 22:45:46 +02:00
|
|
|
uint64_t freq;
|
|
|
|
|
|
|
|
if(id < 3)
|
|
|
|
{
|
|
|
|
const clock_frequency_t *cpg = clock_freq();
|
|
|
|
freq = cpg->Pphi_f;
|
|
|
|
if(clock == TIMER_Pphi_4) freq >>= 2;
|
|
|
|
if(clock == TIMER_Pphi_16) freq >>= 4;
|
|
|
|
if(clock == TIMER_Pphi_64) freq >>= 6;
|
|
|
|
if(clock == TIMER_Pphi_256) freq >>= 8;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* ETMU all run on TCLK at 32768 Hz */
|
|
|
|
freq = 32768;
|
|
|
|
}
|
2018-08-19 17:11:37 +02:00
|
|
|
|
|
|
|
/* fxcg50: Calculated = 29491200 but it's too low */
|
2019-07-04 18:11:43 +02:00
|
|
|
/* TODO: Account for down spread spectrum in the CPG */
|
2018-08-19 17:11:37 +02:00
|
|
|
// uint64_t freq = 29020000 >> 2;
|
|
|
|
|
2019-02-21 20:58:38 +01:00
|
|
|
uint64_t product = freq * delay_us;
|
2018-08-01 20:41:36 +02:00
|
|
|
return product / 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* timer_control() - start or stop a timer
|
2019-07-18 21:18:36 +02:00
|
|
|
@id Timer ID to configure
|
2018-08-01 20:41:36 +02:00
|
|
|
@state 0 to start the timer, 1 to stop it (nothing else!) */
|
2019-07-18 21:18:36 +02:00
|
|
|
static void timer_control(int id, int state)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2019-07-18 21:18:36 +02:00
|
|
|
if(id < 3) *TSTR = (*TSTR | (1 << id)) ^ (state << id);
|
2020-05-10 14:03:41 +02:00
|
|
|
else ETMU[id-3].TSTR = state ^ 1;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* timer_start() - start a configured timer */
|
2019-07-18 21:18:36 +02:00
|
|
|
void timer_start(int id)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2019-07-18 21:18:36 +02:00
|
|
|
timer_control(id, 0);
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
2018-08-19 17:11:37 +02:00
|
|
|
/* timer_reload() - change a timer's delay constant for next interrupts */
|
2019-07-18 21:18:36 +02:00
|
|
|
void timer_reload(int id, uint32_t delay)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2020-05-10 14:03:41 +02:00
|
|
|
if(id < 3) TMU[id].TCOR = delay;
|
|
|
|
else ETMU[id-3].TCOR = delay;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* timer_pause() - stop a running timer */
|
2019-07-18 21:18:36 +02:00
|
|
|
void timer_pause(int id)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2019-07-18 21:18:36 +02:00
|
|
|
timer_control(id, 1);
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
/* timer_stop() - stop and free a timer */
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
void timer_stop(int id)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
|
|
|
/* Stop the timer and disable UNIE to indicate that it's free */
|
2019-07-18 21:18:36 +02:00
|
|
|
timer_pause(id);
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2019-07-18 21:18:36 +02:00
|
|
|
if(id < 3)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2020-05-10 14:03:41 +02:00
|
|
|
TMU[id].TCR.UNIE = 0;
|
|
|
|
TMU[id].TCOR = 0xffffffff;
|
|
|
|
TMU[id].TCNT = 0xffffffff;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-10 14:03:41 +02:00
|
|
|
etmu_t *T = &ETMU[id-3];
|
|
|
|
T->TCR.UNIE = 0;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
|
|
|
/* Also clear TCOR and TCNT to avoid spurious interrupts */
|
2020-05-10 14:03:41 +02:00
|
|
|
do T->TCOR = 0xffffffff;
|
|
|
|
while(T->TCOR + 1);
|
2019-02-21 20:58:38 +01:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
do T->TCNT = 0xffffffff;
|
|
|
|
while(T->TCNT + 1);
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
do T->TCR.UNF = 0;
|
|
|
|
while(T->TCR.UNF);
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 14:49:34 +02:00
|
|
|
/* timer_wait(): Wait for a timer to stop */
|
2020-06-17 11:36:05 +02:00
|
|
|
void timer_wait(int id)
|
|
|
|
{
|
|
|
|
if(id < 3)
|
|
|
|
{
|
|
|
|
tmu_t *T = &TMU[id];
|
2020-10-21 14:49:34 +02:00
|
|
|
/* Sleep only if an interrupt will be there to wake us up */
|
2020-06-17 11:36:05 +02:00
|
|
|
while(*TSTR & (1 << id)) if(T->TCR.UNIE) sleep();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-18 20:20:55 +02:00
|
|
|
etmu_t *T = &ETMU[id-3];
|
2020-06-17 11:36:05 +02:00
|
|
|
while(T->TSTR) if(T->TCR.UNIE) sleep();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 14:49:34 +02:00
|
|
|
/* timer_spinwait(): Actively wait for a timer to raise UNF */
|
|
|
|
void timer_spinwait(int id)
|
|
|
|
{
|
|
|
|
if(id < 3)
|
|
|
|
{
|
|
|
|
tmu_t *T = &TMU[id];
|
|
|
|
while(!T->TCR.UNF) {}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
etmu_t *T = &ETMU[id-3];
|
|
|
|
while(!T->TCR.UNF) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-21 20:58:38 +01:00
|
|
|
//---
|
|
|
|
// Predefined timer callbacks
|
|
|
|
//---
|
|
|
|
|
|
|
|
/* timer_timeout() - callback that sets a flag and halts the timer */
|
2020-06-20 22:45:46 +02:00
|
|
|
int timer_timeout(void volatile *arg)
|
2019-02-21 20:58:38 +01:00
|
|
|
{
|
2020-06-20 22:45:46 +02:00
|
|
|
int volatile *x = arg;
|
|
|
|
if(x) (*x)++;
|
|
|
|
return TIMER_STOP;
|
2019-07-16 21:32:20 +02:00
|
|
|
}
|
|
|
|
|
2018-08-01 20:41:36 +02:00
|
|
|
//---
|
|
|
|
// Driver initialization
|
|
|
|
//---
|
|
|
|
|
2019-07-18 21:18:36 +02:00
|
|
|
/* Interrupt handlers for standard timers (4 gates) */
|
|
|
|
extern void inth_tmu(void);
|
|
|
|
/* Interrupt handlers for extra timers */
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
extern void inth_etmu4(void);
|
2019-07-16 21:32:20 +02:00
|
|
|
extern void inth_etmux(void);
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
static void constructor(void)
|
2018-08-19 17:11:37 +02:00
|
|
|
{
|
2021-04-23 18:50:20 +02:00
|
|
|
if(isSH3())
|
|
|
|
{
|
|
|
|
TMU = SH7705_TMU.TMU;
|
|
|
|
ETMU = SH7705_ETMU;
|
|
|
|
TSTR = &SH7705_TMU.TSTR;
|
|
|
|
}
|
2018-08-19 17:11:37 +02:00
|
|
|
}
|
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
static void configure(void)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2020-05-10 14:03:41 +02:00
|
|
|
uint16_t etmu_event[6] = { 0x9e0, 0xc20, 0xc40, 0x900, 0xd00, 0xfa0 };
|
|
|
|
*TSTR = 0;
|
|
|
|
|
2020-02-23 15:49:55 +01:00
|
|
|
/* Install the standard TMU's interrupt handlers */
|
2021-04-23 18:50:20 +02:00
|
|
|
void *h = intc_handler(0x400, inth_tmu, 128);
|
2020-05-10 14:03:41 +02:00
|
|
|
timers[0] = h + 84;
|
|
|
|
timers[1] = h + 104;
|
|
|
|
timers[2] = h + 116;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-05-10 14:03:41 +02:00
|
|
|
/* Clear every timer to avoid surprises */
|
|
|
|
for(int id = 0; id < 3; id++)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2020-05-10 14:03:41 +02:00
|
|
|
do TMU[id].TCR.word = 0;
|
|
|
|
while(TMU[id].TCR.word);
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2020-07-08 19:49:09 +02:00
|
|
|
TMU[id].TCOR = 0xffffffff;
|
|
|
|
TMU[id].TCNT = 0xffffffff;
|
|
|
|
|
2018-08-01 20:41:36 +02:00
|
|
|
/* Standard timers: TCR is provided to the interrupt handler */
|
2020-05-10 14:03:41 +02:00
|
|
|
timers[id]->TCR = &TMU[id].TCR;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
2020-05-10 14:03:41 +02:00
|
|
|
for(int id = 0; id < timer_count()-3; id++)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2020-05-10 14:03:41 +02:00
|
|
|
etmu_t *T = &ETMU[id];
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2019-02-21 20:58:38 +01:00
|
|
|
/* Extra timers seem to generate interrupts as long as TCNT=0,
|
|
|
|
regardless of TSTR. I'm not entirely sure about this weird
|
2020-05-10 14:03:41 +02:00
|
|
|
behaviour, but for safety I'll set TCOR/TCNT to non-zero. */
|
|
|
|
T->TSTR = 0;
|
|
|
|
do T->TCOR = 0xffffffff;
|
|
|
|
while(T->TCOR + 1);
|
|
|
|
|
|
|
|
/* Also TCNT and TCR take some time to record changes */
|
|
|
|
do T->TCNT = 0xffffffff;
|
|
|
|
while(T->TCNT + 1);
|
|
|
|
do T->TCR.byte = 0;
|
|
|
|
while(T->TCR.byte);
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
/* Install the extra timers. On SH3, only ETMU0 is available */
|
|
|
|
for(int i = 3; i < timer_count(); i++) if(i != 7)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2021-04-23 18:50:20 +02:00
|
|
|
void *h = intc_handler(etmu_event[i-3], inth_etmux, 32);
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
timers[i] = h + 20;
|
2019-07-16 21:32:20 +02:00
|
|
|
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
/* On SH3, the ETMU handler is not at an offset of 0x900 (event
|
|
|
|
code 0xd00) but at an offset of 0xa0 */
|
2020-07-09 10:32:53 +02:00
|
|
|
uint32_t *etmu_offset = h + 16;
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
if(isSH3()) *etmu_offset = *etmu_offset - 0xf40 + 0x2a0;
|
2020-07-09 10:32:53 +02:00
|
|
|
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
uint16_t *data_id = h + 14;
|
2019-07-16 21:32:20 +02:00
|
|
|
*data_id = i;
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
|
|
|
|
uint32_t *TCR = h + 28;
|
|
|
|
*TCR = (uint32_t)&ETMU[i-3].TCR;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
/* Also install ETMU4, even on SH3, because it contains common code */
|
2021-04-23 18:50:20 +02:00
|
|
|
h = intc_handler(etmu_event[4], inth_etmu4, 96);
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
timers[7] = h + 84;
|
|
|
|
*(uint32_t *)(h + 92) = (uint32_t)&ETMU[4].TCR;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
|
|
|
/* Enable TMU0 at level 13, TMU1 at level 11, TMU2 at level 9 */
|
2020-06-20 17:18:51 +02:00
|
|
|
intc_priority(INTC_TMU_TUNI0, 13);
|
|
|
|
intc_priority(INTC_TMU_TUNI1, 11);
|
|
|
|
intc_priority(INTC_TMU_TUNI2, 9);
|
2018-08-01 20:41:36 +02:00
|
|
|
|
|
|
|
/* Enable the extra TMUs at level 7 */
|
2020-06-20 17:18:51 +02:00
|
|
|
intc_priority(INTC_ETMU_TUNI0, 7);
|
|
|
|
if(isSH4())
|
2018-08-19 17:11:37 +02:00
|
|
|
{
|
2020-06-20 17:18:51 +02:00
|
|
|
intc_priority(INTC_ETMU_TUNI1, 7);
|
|
|
|
intc_priority(INTC_ETMU_TUNI2, 7);
|
|
|
|
intc_priority(INTC_ETMU_TUNI3, 7);
|
|
|
|
intc_priority(INTC_ETMU_TUNI4, 7);
|
|
|
|
intc_priority(INTC_ETMU_TUNI5, 7);
|
2018-08-19 17:11:37 +02:00
|
|
|
}
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---
|
2021-04-23 18:50:20 +02:00
|
|
|
// State and driver metadata
|
2018-08-01 20:41:36 +02:00
|
|
|
//---
|
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
static void hsave(tmu_state_t *s)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2021-04-23 18:50:20 +02:00
|
|
|
s->TSTR = *TSTR;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
|
|
|
for(int i = 0; i < 3; i++)
|
|
|
|
{
|
2021-04-23 18:50:20 +02:00
|
|
|
s->t[i].TCOR = TMU[i].TCOR;
|
|
|
|
s->t[i].TCNT = TMU[i].TCNT;
|
|
|
|
s->t[i].TCR = TMU[i].TCR.word;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
2020-07-10 16:05:11 +02:00
|
|
|
for(int i = 3; i < timer_count(); i++)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2021-04-23 18:50:20 +02:00
|
|
|
struct tmu_state_stored_timer *c = &s->t[i];
|
2020-07-10 16:05:11 +02:00
|
|
|
etmu_t *T = &ETMU[i-3];
|
2020-05-10 14:03:41 +02:00
|
|
|
|
|
|
|
/* Don't snapshot an interrupt state, because the timer state
|
|
|
|
is sometimes garbage protected by a masked interrupt. */
|
|
|
|
c->TCOR = T->TCOR ? T->TCOR : 0xffffffff;
|
|
|
|
c->TCNT = T->TCNT ? T->TCNT : c->TCOR;
|
2020-07-10 16:05:11 +02:00
|
|
|
c->TCR = T->TCR.byte & 0xd;
|
2020-05-10 14:03:41 +02:00
|
|
|
c->TSTR = T->TSTR;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
static void hrestore(tmu_state_t const *s)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2020-07-08 19:49:09 +02:00
|
|
|
*TSTR = 0;
|
2018-08-01 20:41:36 +02:00
|
|
|
|
|
|
|
for(int i = 0; i < 3; i++)
|
|
|
|
{
|
2021-04-23 18:50:20 +02:00
|
|
|
TMU[i].TCOR = s->t[i].TCOR;
|
|
|
|
TMU[i].TCNT = s->t[i].TCNT;
|
|
|
|
TMU[i].TCR.word = s->t[i].TCR;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
2020-07-10 16:05:11 +02:00
|
|
|
for(int i = 3; i < timer_count(); i++)
|
2018-08-01 20:41:36 +02:00
|
|
|
{
|
2021-04-23 18:50:20 +02:00
|
|
|
struct tmu_state_stored_timer const *c = &s->t[i];
|
2020-07-10 16:05:11 +02:00
|
|
|
etmu_t *T = &ETMU[i-3];
|
2020-05-10 14:03:41 +02:00
|
|
|
|
|
|
|
do T->TCOR = c->TCOR;
|
|
|
|
while(T->TCOR != c->TCOR);
|
|
|
|
|
|
|
|
T->TSTR = c->TSTR;
|
|
|
|
|
|
|
|
do T->TCNT = c->TCNT;
|
|
|
|
while(T->TCNT != c->TCNT);
|
|
|
|
|
2020-07-10 16:05:11 +02:00
|
|
|
do T->TCR.byte = c->TCR;
|
|
|
|
while(T->TCR.byte != c->TCR);
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
2020-07-08 19:49:09 +02:00
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
*TSTR = s->TSTR;
|
2018-08-01 20:41:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gint_driver_t drv_tmu = {
|
2020-05-10 16:36:21 +02:00
|
|
|
.name = "TMU",
|
2021-04-23 18:50:20 +02:00
|
|
|
.constructor = constructor,
|
|
|
|
.configure = configure,
|
|
|
|
.hsave = (void *)hsave,
|
|
|
|
.hrestore = (void *)hrestore,
|
|
|
|
.state_size = sizeof(tmu_state_t),
|
2018-08-01 20:41:36 +02:00
|
|
|
};
|
2021-04-23 18:50:20 +02:00
|
|
|
GINT_DECLARE_DRIVER(13, drv_tmu);
|