📄 timerdrv.c
字号:
/* while(remainder<0) do { remainder += divider; quotient += 1 } */
asm(Circle: );
asm( cmp A, B ); /* no more than 4 times */
asm( bge GetK );
asm( add Y, B ); /* Y = divider */
asm( inc.w X0 );
asm( bra Circle );
asm(GetK: );
asm( sub A, B ); /* the same: remainder += divider * k, k = {0, 1, 2, 3, 4} */
asm( move.w B0, B1 ); /* calling convention */
asm( move.w Y0, B0 );
asm( move.w X0, Y0 );
asm( bfclr #$0001, SR );
asm( sbc Y, A );
asm( move.w B0, Y0 );
asm(Endofdiv: ); /* end of division */
asm( move.l A10, X:(R2) ); /* save results of division */
asm( move.w B1, Y0 );
asm( rts );
}
/*****************************************************************************
*
* Module: U64divU16
*
* Description: division unsigned 64 bits value by unsigned 16 bits value divider
*
* Returns: remainder
*
* Arguments: puDividend - not null pointer to 64 bits dividend
* uDivider - 16 bits unsigned divider
* puQuotient - not null pointer to 64 bits quotient
*
* Range Issues:
*
* Special Issues: For executive loop only. Module doesn't save registers: A, B, Y, X0, C1, D1
* Use SP
* Test Method:
*
*****************************************************************************/
static unsigned short U64divU16(const U64 * puDividend, const unsigned short uDivider, U64 * puQuotient)
{
asm(adda #1, SP );
asm(move.w Y1, X:(SP)+ );
asm(move.w B0, X:(SP)+ );
asm(move.w B1, X:(SP)+ );
asm(move.w A0, X:(SP)+ );
asm(move.w A1, X:(SP)+ );
asm(move.w D1, X:(SP)+ );
asm(move.w C1, X:(SP)+ );
asm(move.l X:(R2), B ); /* save X:(R2), X:(R2+1) to X:(SP) */
asm(move.w B0, X:(SP)+ );
asm(move.w B1, X:(SP) );
asm(move.w Y0, C1 ); /* save divider (Y0) to C1 */
asm(move.l X:(R2+2), A ); /* move 2 high number positions in register A */
asm(jsr U32divU16s ); /* divide high positions */
asm(move.l A10, x:(R3+2) ); /* save high number positions of results */
asm(move.w Y0, A1 ); /* move reminder of first division */
asm(move.w X:(SP), A0 ); /* prepare next 16 bit for division */
asm(move.w C1, Y0 ); /* restore divider */
asm(jsr U32divU16s ); /* divide middle number position */
asm(move.w A0, D1 ); /* save middle number position of result */
/* not at once to R3 because if user write U64divU16(&a, b, &a) */
/* next division destroy this result */
asm(move.w Y0, A1 ); /* move reminder of second division */
asm(move.w X:(SP-1), A0 ); /* prepare next 16 bit for division */
asm(move.w C1, Y0 ); /* restore divider */
asm(jsr U32divU16s ); /* divide low number position */
asm(move.w X:(SP)-, B1 ); /* restore X:(R2), X:(R2+1) */
asm(move.w X:(SP)-, B0 );
asm(move.l B10, X:(R2) );
asm(move.w D1, A1 ); /* save results of low bits D1A0 -> X:(R3) */
asm(move.l A10, x:(R3) );
asm(move.w X:(SP)-, C1 );
asm(move.w X:(SP)-, D1 );
asm(move.w X:(SP)-, A1 );
asm(move.w X:(SP)-, A0 );
asm(move.w X:(SP)-, B1 );
asm(move.w X:(SP)-, B0 );
asm(move.w X:(SP)-, Y1 );
asm(rts );
}
#if 0
/*****************************************************************************
*
* Module: TimerCallback
*
* Description: program counter routine for POSIX timer
*
* Returns: none
*
* Arguments: QT callback type, Timer device
*
* Range Issues:
*
* Special Issues: to be optimized in asm
*
* Test Method:
*
*****************************************************************************/
void TimerCallback( posix_tContext* ptr )
{
extern const union sigval sig; /* non OS version */
// periphBitClear( QTB_TCF, &((arch_sTimerChannel*)ptr->bspDevice)->StatusControlReg );
if( --ptr->SoftCounter == 0 )
{
ptr->SoftCounter = ptr->reloadSoftCounter;
if(ptr->pUserFunc != 0 )
ptr->pUserFunc( sig );
}
}
#endif
/*****************************************************************************
*
* Module: timerRealTimeClockISR
*
* Description: Update CLOCK_REALTIME system timer counter
*
* Returns: None
*
* Range Issues: None
* Special Issues: None
* Test Method: timers.mcp
*
*****************************************************************************/
#pragma interrupt called
static void timerRealTimeClockISR(union sigval Params)
{ /* update system counter */
timerTick(); /* increments TimerISRCount */
}
/* No operating system (nos) version */
/* Include OS hooks for Timer ticks */
void timerSleep(long Ticks)
{
unsigned long TargetISRCount = TimerISRCount + Ticks;
while(TimerISRCount < TargetISRCount)
{
continue;
}
}
void timerTick(void)
{
TimerISRCount++;
}
/*****************************************************************************
*
* Module: timer_create
*
* Description (POSIX) :
* The timer_create() function creates a per-process timer using the specified
* clock, ClockID, as the timing base. The EventParams argument, if non-NULL,
* points to a sigevent structure. This structure, allocated by the application,
* defines the asynchronous notification that will occur when the timer expires.
*
* Returns:
* If the call succeeds, timer_create() returns zero and in the
* location referenced by TimerID, stores a timer ID of type timer_t used to
* identify the timer in subsequent timer requests. This timer ID will be
* unique within the calling process until the timer is deleted.
*
* Range Issues: None
* Special Issues: None
* Test Method: timers.mcp
*
*****************************************************************************/
int timer_create ( const clockid_t ClockID,
const struct sigevent * EventParams,
timer_t * TimerID)
{
extern const posix_tConfig posixDeviceMap[];
posix_tContext* ptr = NULL;
const posix_tConfig * cfg = &posixDeviceMap[0];
while(1)
{
if(cfg->ctx == 0 )
return -1; /* last timer */
if( (unsigned short)cfg->base == ClockID )
break;
cfg++;
}
*TimerID = ClockID;
ptr = cfg->ctx;
ptr->pUserFunc = EventParams->sigev_notify_function; /* save user function here */
timer_qt_writeCompareReg1( (arch_sTimerChannel*)ClockID, (unsigned short)ptr);
return 0;
}
/*****************************************************************************
*
* Module: timer_delete
*
* Description (POSIX) :
* The timer_delete() function deletes the specified timer, timerid, previously
* created by the timer_create() function. If the timer is armed when
* timer_delete() is called, the behaviour will be as if the timer is
* automatically disarmed before removal. The disposition of pending
* signals for the deleted timer is unspecified.
*
* Returns: If successful, the function returns a value of zero. Otherwise,
* the function returns a value of -1.
*
* Range Issues: None
* Special Issues: None
* Test Method: timers.mcp
*
*****************************************************************************/
int timer_delete(timer_t TimerID)
{
timer_qt_disable( (arch_sTimerChannel*)TimerID );
}
/*****************************************************************************
*
* Module: time2Ticks
*
* Description :
* Translate time (ns) to ticks
*
* Range Issues: None
* Special Issues: None
* Test Method: timers.mcp
*
*****************************************************************************/
static void time2Ticks(const struct timespec * pTimeValue, U64 * pTicks)
{
U64 nsTime;
/*translate into nanoseconds*/
nsTime.w[0] = pTimeValue->tv_sec;
nsTime.w[1] = 0;
U64mulU32(&nsTime, 1000000000UL, &nsTime); /* nSec=Sec*10^9 */
U64addU32(&nsTime, pTimeValue->tv_nsec, &nsTime);
/* translate software counter into ticks */
/* tick = nanoSec * qtINPUT_FREQUENCY / 10^9 */
U64mulU32(&nsTime, IP_BUS_FREQUENCY, &nsTime);
U64divU16(&nsTime, 1000, &nsTime);
U64divU16(&nsTime, 1000, &nsTime);
U64divU16(&nsTime, 1000, &nsTime);
pTicks->w[0] = nsTime.w[0];
pTicks->w[1] = nsTime.w[1];
}
/*****************************************************************************
*
* Module: ticks2ns
*
* Description :
* Translate ticks to ns
*
* Range Issues: None
* Special Issues: None
* Test Method: timers.mcp
*
*****************************************************************************/
static void ticks2ns(U64* tickPeriod, U64* timePeriod)
{
/* translate ticks to ns: ns=10^9 * ticks / FREQ */
U64mulU32(tickPeriod, 1000000000, timePeriod);
U64divU16(timePeriod, IP_BUS_FREQUENCY_1, timePeriod);
U64divU16(timePeriod, IP_BUS_FREQUENCY_2, timePeriod);
}
/*****************************************************************************
*
* Module: ns2Time
*
* Description :
* It represents time, which is specified in ns, as <sec, ns>
*
* Range Issues: None
* Special Issues: None
* Test Method: timers.mcp
*
*****************************************************************************/
static void ns2Time(U64* timePeriod, struct timespec * tp)
{
U64 secCount;
unsigned long nsCount;
U64 tmp;
/* timePeriod = 10^9 * secCount + nsCount */
/* 1:timePeriod = 10^3 * secCount1 + nsCount1 */
/* 2:secCount1 = 10^3 * secCount2 + nsCount2 */
/* 3:secCount = 10^3 * secCount2 + nsCount3 */
/* 4:nsCount = 10^6 * nsCount3 + nsCount2 * 10^3 + nsCount1 */
nsCount = U64divU16(timePeriod, 1000, &secCount);
tmp.w[0] = U64divU16(&secCount, 1000, &secCount);
tmp.w[1] = 0;
U64mulU32(&tmp,1000,&tmp);
nsCount +=tmp.w[0];
tmp.w[0]= U64divU16(&secCount, 1000, &secCount);
U64mulU32(&tmp,1000000,&tmp);
nsCount +=tmp.w[0];
tp->tv_nsec = nsCount;
tp->tv_sec = secCount.w[0];
}
static unsigned short factorization(U64* tickPeriod, unsigned long* SWCounter)
{
struct /* representation nuber A as: A = divider * quot + rem, 0 < rem < divider */
{
unsigned long quot;
unsigned short rem;
} div1, div2;
U64 SW;
const unsigned short SearchCount = 32; /* max number of divider to try */
unsigned short rem0, rem1, minRem,
HWCounter,
foundDivider;
for( HWCounter = 0xFFFF-SearchCount, minRem = 0xFFFF;
HWCounter < 0xFFFF && minRem > 500;
++HWCounter)
{
div1.rem = rem0 = U64divU16(tickPeriod, HWCounter, &SW);
div2.rem = rem1 = HWCounter - rem0;
/* Predcondition: SWCounter.w[1] == 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -