Category : Files from Magazines
Archive   : DDJ8612.ZIP
Filename : BERRY.DEC

 
Output of file : BERRY.DEC contained in archive : DDJ8612.ZIP
/*
Listing 1 Scheduling Algorithm
(C) Copyright 1986 Ken Berry.
All rights reserved.
Copies may be made for non-commercial, private use only.
*/

#define _F 0 /* false */
#define _T 1 /* true */
#define _E -1 /* error */

#define _NULL 0 /* null pointer */

typedef char pointer; /* pointer type */
typedef char logical; /* logical type */
typedef unsigned selector; /* 8086 selector type */

struct sys_parm /* register storage block for 8086 interface */
{
union {unsigned sys_rax; struct {char sys_ral, sys_rah;} sys_byt;} sys_ra;
union {unsigned sys_rbx; struct {char sys_rbl, sys_rbh;} sys_byt;} sys_rb;
union {unsigned sys_rcx; struct {char sys_rcl, sys_rch;} sys_byt;} sys_rc;
union {unsigned sys_rdx; struct {char sys_rdl, sys_rdh;} sys_byt;} sys_rd;
#define sys_ax sys_ra.sys_rax
#define sys_al sys_ra.sys_byt.sys_ral
#define sys_ah sys_ra.sys_byt.sys_rah
#define sys_bx sys_rb.sys_rbx
#define sys_bl sys_rb.sys_byt.sys_rbl
#define sys_bh sys_rb.sys_byt.sys_rbh
#define sys_cx sys_rc.sys_rcx
#define sys_cl sys_rc.sys_byt.sys_rcl
#define sys_ch sys_rc.sys_byt.sys_rch
#define sys_dx sys_rd.sys_rdx
#define sys_dl sys_rd.sys_byt.sys_rdl
#define sys_dh sys_rd.sys_byt.sys_rdh
unsigned sys_bp; /* base pointer */
unsigned sys_si; /* source index */
unsigned sys_di; /* destination index */
unsigned sys_sp; /* stack pointer */
unsigned sys_cs; /* code segment */
unsigned sys_ds; /* data segment */
unsigned sys_ss; /* stack segment */
unsigned sys_es; /* extra segment */
unsigned sys_pf; /* 80286 processor flags */
#define SYS_OF 0x0800 /* overflow flag- 1: lost significance */
#define SYS_DF 0x0400 /* direction flag- 1: strings auto-decrement */
#define SYS_IF 0x0200 /* interrupt flag- 1: enable interrupts */
#define SYS_TF 0x0100 /* trap flag- 1: interrupt every instruction */
#define SYS_SF 0x0080 /* sign flag- 1: result negative */
#define SYS_ZF 0x0040 /* zero flag- 1: result 0 */
#define SYS_AF 0x0010 /* auxiliary carry flag- 1: carry from bit 3 */
#define SYS_PF 0x0004 /* parity flag- 1: even number of 1's */
#define SYS_CF 0x0001 /* carry flag- 1: carry from bit 8 or 16 */
unsigned sys_sw; /* status word */
#define SYS_TS 0x0008 /* task switch */
#define SYS_EM 0x0004 /* processor extension emulation */
#define SYS_MP 0x0002 /* monitor processor extension */
#define SYS_PE 0x0001 /* protection enable */
unsigned sys_ip; /* instruction pointer */
unsigned sys_res; /* unused */
};

struct t_xstck
{
unsigned t_xbase; /* application stack base (overflow detection) */
unsigned t_xes; /* es */
unsigned t_xbp; /* bp */
unsigned t_xdi; /* di */
unsigned t_xsi; /* si */
unsigned t_xdx; /* dx */
unsigned t_xcx; /* cx */
unsigned t_xbx; /* bx */
unsigned t_xax; /* ax */
unsigned t_xds; /* ds */
unsigned t_xip; /* ip */
unsigned t_xcs; /* cs */
unsigned t_xpf; /* pf */
unsigned t_retip; /* return address */
};

struct t_task
{
char t_type; /* task type */
#define T_X 0x80 /* execute queue */
#define T_W 0x40 /* wait queue */
#define T_P 0x20 /* priority queue */
#define T_SW 0x10 /* secondary wait queue */
#define T_ATASK 0x01 /* abreviated task */
unsigned t_wttk; /* wait tick count */
unsigned t_cls; /* priority queue index */
struct t_task *t_pqtsk,*t_nqtsk; /* queue linkage */
struct t_task *t_ratsk,*t_pstsk,*t_nstsk,*t_fdtsk,*t_ldtsk; /* family */
struct sys_parm t_ps; /* processor status */
unsigned t_xtm0; /* execution time accumulator */
unsigned t_xtm1;
unsigned t_xtm2;
pointer *t_axstk; /* execution stack pointer */
};

extern pointer *sys_task; /* current task control table pointer */
#define _tsk ( ( struct t_task * ) sys_task ) /* task control table ref */

#define T_SCLS 4 /* number of scheduling classes */

struct t_scls /* scheduling class queue */
{
unsigned t_sfrq; /* scheduling frequency */
int t_sct; /* queue length */
struct t_task *t_fqtsk,*t_lqtsk; /* queue header */
};

struct t_schd /* scheduling control table */
{
int t_xct; /* execution queue length */
struct t_task *t_fxtsk, *t_lxtsk; /* execution queue header */
int t_wct; /* wait queue length */
struct t_task *t_fwtsk, *t_lwtsk; /* wait queue header */
int t_swct; /* secondary wait queue length */
struct t_task *t_fswtsk, *t_lswtsk; /* secondary wait queue header */
int t_sclsl; /* scheduling class index limit */
struct t_scls **t_sclsp; /* scheduling class array pointer */
};

extern pointer *sys_tsch; /* task scheduling control table pointer */
#define _tschd ( ( struct t_schd * ) sys_tsch ) /* quick pointer */

/*
t__krnl /* security kernel */
*/
t__krnl()
/*
This is the security kernel. It never returns, being the most trusted
software in the system. The current contents in t__crtss and t__crtsp
are used to set the stack for when the current task is resumed. */
{
extern logical t_astrm; /* tick termination flag */
extern selector t__crtss; /* current task ss storage */
extern pointer *t__crtsp; /* current task sp storage */
extern unsigned tmr_tkct; /* tick clock */
int xtskct; /* task queue count (at entry) */
int ttc; /* task termination code */
_tsk -> t_ps.sys_ss = t__crtss; /* set current task stack */
_tsk -> t_ps.sys_sp = t__crtsp;
while(_T) /* find executable task */
{
xtskct = _tschd -> t_xct; /* save task count */
if ( t_astrm ) t__wtst( tmr_tkct ); /* process wait tasks */
if ( xtskct == 0 ) t__sch(); /* schedule application tasks if necessary */
sys_task = _tschd -> t_fxtsk; /* set next task address */
if ( sys_task != _NULL ) /* test for executable task available */
{
_tschd -> t_xct--; /* decrement executing task count */
_tschd -> t_fxtsk = _tsk -> t_nqtsk; /* delink task */
if ( _tschd -> t_fxtsk == _NULL )
_tschd -> t_lxtsk = _NULL;
else _tschd -> t_fxtsk -> t_pqtsk = _NULL;
_tsk -> t_type &= ~T_X; /* indicate task not in execution queue */
ttc = t__xtsk( sys_task ); /* execute application task */
if ( !sys_task ) continue; /* test for task terminated */
if ( ttc < 0 ) t__inxq(); /* insert task into execution queue */
else if ( ttc == 0 ) t__inpq(); /* insert task into priority queue */
else t__inwq( ttc ); /* insert into wait queue */
}
}
}

/*
t__wtst test waiting tasks
*/
t__wtst( tc)
unsigned tc;
/*
The wait queue is traversed. All tasks with a wait value of tc are executed.
_F is always returned. */
{
while(_T) /* traverse wait queue */
{
sys_task = _tschd -> t_fwtsk; /* set current task pointer */
if ( !sys_task ) break; /* test for no waiting tasks */
_tsk -> t_type &= ~T_W; /* remove task from wait queue */
_tsk -> t_type |= T_X; /* indicate task in execution queue */
if ( _tsk -> t_wttk > tc ) break; /* test for effective end of list */
--_tschd -> t_wct; /* decrement waiting task count */
_tschd -> t_fwtsk = _tsk -> t_nqtsk; /* delink from wait queue */
if ( _tsk -> t_nqtsk == _NULL )
_tschd -> t_lwtsk = _NULL;
else _tsk -> t_nqtsk -> t_pqtsk = _NULL;
_tsk -> t_pqtsk = _NULL; /* insert at top of execution queue */
_tsk -> t_nqtsk = _tschd -> t_fxtsk;
_tschd -> t_fxtsk = sys_task;
++_tschd -> t_xct; /* increment executable task count */
if ( _tschd -> t_lxtsk == _NULL )
_tschd -> t_lxtsk = sys_task;
else _tsk -> t_nqtsk -> t_pqtsk = sys_task;
}
return _F; /* return */
}


/*
t__sch schedule task
*/
t__sch()
/*
This function searches the priority queues and links tasks ready for execution
into the execution queue. The return is always _F. */
{
struct t_scls **a; /* priority queue pointer array pointer */
struct t_scls *q; /* priority queue pointer */
int i,j; /* iteration variables */
a = _tschd -> t_sclsp; /* set pointer array address */
/* while(_T) /* nonterminating task */
{ */
for ( i = 0; i < _tschd -> t_sclsl; ++i ) /* traverse queues */
{
q = a[i]; /* set priority queue pointer */
for ( j = 0; j++ t_sfrq; ) /* schedule tasks from priority queue */
{
if ( q -> t_fqtsk == _NULL ) break; /* test for queue empty */
if ( _tschd -> t_lxtsk ) /* link to end of execution queue */
_tschd -> t_lxtsk -> t_nqtsk = q -> t_fqtsk;
else _tschd -> t_fxtsk = q -> t_fqtsk;
q -> t_fqtsk -> t_type &= ~T_P; /* indicate not in priority queue */
q -> t_fqtsk -> t_pqtsk = _tschd -> t_lxtsk;
_tschd -> t_lxtsk = q -> t_fqtsk;
q -> t_fqtsk = q -> t_fqtsk -> t_nqtsk; /* update queue header */
_tschd -> t_lxtsk -> t_nqtsk = _NULL;
if ( q -> t_fqtsk == _NULL )
q -> t_lqtsk = _NULL;
else q -> t_fqtsk -> t_pqtsk = _NULL;
q -> t_sct --; /* decrement queue count */
++ _tschd -> t_xct; /* increment execution queue length */
_tschd -> t_lxtsk -> t_type |= T_X; /* ind. task in execution queue */
}
}
/* t_rels(); /* return to bottom of execution queue */
}*/
return _F; /* return */
}

/*
t__inxq insert task into execution queue
*/
t__inxq()
/*
The current task is inserted into the execution queue. _F is always returned.
*/
{
_tsk -> t_wttk = 0; /* indicate not waiting for system tick */
if ( _tschd -> t_lxtsk == _NULL ) /* test for execution queue empty */
{
_tschd -> t_fxtsk = sys_task; /* insert in empty queue */
_tsk -> t_pqtsk = _NULL;
}
else /* execution queue not empty */
{
_tschd -> t_lxtsk -> t_nqtsk = sys_task; /* insert at end of queue */
_tsk -> t_pqtsk = _tschd -> t_lxtsk;
}
_tsk -> t_nqtsk = _NULL; /* new task at end of list */
_tschd -> t_lxtsk = sys_task;
_tschd -> t_xct++; /* increment executable task count */
_tschd -> t_lxtsk -> t_type |= T_X; /* indicate task in execution queue */
return _F; /* return */
}

/*
t__secw process secondary wait queue
*/
t__secw()
/*
This program executes every 64K system ticks. It moves the secondary
wait queue to the primary wait queue and changes the type of the waiting
tasks. */
{
struct t_task *tsk; /* task control table pointer */
char swtflg; /* system state flag */
while(_T) /* nonterminating task */
{
t__syntr( &swtflg ); /* enter system state */
for ( tsk = _tschd -> t_fwtsk; tsk; tsk = tsk -> t_nqtsk ) /* traverse */
{
tsk -> t_type &= ~T_SW;
tsk -> t_type |= T_W; /* change task type */
}
_tschd -> t_wct = _tschd -> t_swct; /* append secondary wait queue */
_tschd -> t_fwtsk = _tschd -> t_fswtsk;
_tschd -> t_lwtsk = _tschd -> t_lswtsk;
_tschd -> t_fswtsk = _tschd -> t_lswtsk = _NULL; /* empty sec. queue */
_tschd -> t_swct = 0;
t__inwq( 0xFFFF - tmr_tkct ); /* insert self into wait queue at end */
sys_task = _NULL; /* remove task from kernel control */
t_term(); /* suspend execution */
}
}

/*
t__inwq insert task into wait queue
*/
t__inwq(tc)
unsigned tc;
/*
The current task is inserted into the wait queue. tc is the number of system
ticks that the task is to wait. _F is always returned. */
{
extern unsigned tmr_tkct; /* tick clock */
unsigned crtk; /* current tick */
crtk = tmr_tkct; /* set current system tick */
_tsk -> t_wttk = tc + crtk; /* compute reactivation time */
if ( _tsk -> t_wttk >= crtk ) /* test for task in wait queue */
{ t__inwt( &_tschd -> t_wct ); /* insert in wait queue */
_tsk -> t_type |= T_W;
}else /* task in secondary wait queue */
{ t__inwt( &_tschd -> t_swct ); /* insert in secondary wait queue */
_tsk -> t_type |= T_SW;
}return _F; /* indicate task inserted */
}

/*
t__inwt insert into wait or secondary wait queue
*/
struct t_wtq
{
int wct; /* wait queue length */
struct t_task *frs,*lst; /* queue header */
};
t__inwt( w )
struct t_wtq *w;
/*
The t_wtq structure is implicitly contained in the scheduling control table
(t_schd structure). The current task is inserted into the queue. _F is always
returned. */
{
struct t_task *p; /* task pointer */
unsigned tc; /* reactivation time */
tc = _tsk -> t_wttk; /* set reactivation time */
++w -> wct; /* increment queue length */
for ( p = w -> frs; p; p = p -> t_nqtsk ) /* traverse queue */
{
if ( tc < p -> t_wttk ) /* test for task earlier */
{
_tsk -> t_nqtsk = p; /* insert within queue */
_tsk -> t_pqtsk = p -> t_pqtsk;
p -> t_pqtsk = sys_task;
if ( ( p = _tsk -> t_pqtsk ) ) p -> t_nqtsk = sys_task;
else w -> frs = sys_task;
return _F; /* indicate task inserted */
}
}
if ( ( p = w -> lst ) ) /* test for wait queue not empty */
{
p -> t_nqtsk = w -> lst = sys_task; /* insert at end of queue */
_tsk -> t_pqtsk = p;
_tsk -> t_nqtsk = _NULL;
}
else /* wait queue empty */
{
w -> frs = w -> lst = sys_task; /* initialize wait queue */
_tsk -> t_nqtsk = _tsk -> t_pqtsk = _NULL;
}
return _F; /* indicate task inserted */
}

/*
t__inpq insert into priority queue
*/
t__inpq()
/*
The current task is inserted into its priority queue. _F is always returned.
*/
{
struct t_scls *q; /* priority queue pointer */
_tsk -> t_wttk = 0; /* indicate not waiting for tick */
q = _tschd -> t_sclsp[ _tsk -> t_cls ]; /* set priority queue address */
_tsk -> t_pqtsk = q -> t_lqtsk; /* link task into priority queue */
_tsk -> t_nqtsk = _NULL;
if ( q -> t_lqtsk == _NULL ) q -> t_fqtsk = sys_task;
else q -> t_lqtsk -> t_nqtsk = sys_task;
q -> t_lqtsk = sys_task;
++q -> t_sct; /* increment queue length */
_tsk -> t_type |= T_P; /* indicate task in priority queue */
return _F; /* return */
}

/*
t__xtsk execute task
*/
t__xtsk( t )
struct t_task *t;
/*
Task t is executed. The returned value is the termination code.
*/
{
extern unsigned t_mnxtm; /* minimum execution time */
extern unsigned t_syxtm[]; /* system pseudo time accumulator */
extern logical t_astrm; /* application termination flag */
int ttc; /* return value storage */
unsigned atm; /* accumulated time */
unsigned rtm; /* reference time */
int xtm; /* execution time */
atm = 0; /* initialize accumulated execution time */
while(_T) /* execute task */
{
rtm = t -> t_xtm0; /* set reference time */
t_rtmark( &t -> t_xtm0 ); /* accumulate pseudo time */
ttc = t__dspap( t -> t_ps.sys_ss, t -> t_ps.sys_sp ); /* execute task */
t -> t_ps.sys_ss = t__crtss; /* store ss */
t -> t_ps.sys_sp = t__crtsp; /* store sp */
t_rtmark( &t_syxtm ); /* accumulate pseudo time */
if ( ( ttc != 0 ) || !t_astrm ) break; /* test for not tick termination */
xtm = t -> t_xtm0 - rtm; /* compute execution time */
if ( xtm < rtm ) xtm = -xtm;
atm += xtm; /* accumulate execution time */
if ( atm >= t_mnxtm ) break; /* test for minimum time satisfied */
}
return ttc; /* return */
}
/*
t__init initialize task system
*/
t__init()
/*
This function initializes the task system. _F is the normal return. _E is
returned if the system cannot be initialized. */
{
#define WSTK 252 /* t_wqupd stack size */
extern struct sys_parm sys_stat; /* initial processor status */
extern struct t_task *t_wqupd; /* secondary wait queue update task */
extern selector sys_dgrp; /* data segment selector storage */
extern char *sys_ssbs; /* system stack pointer */
extern unsigned sys_sssz; /* system stack length */
extern char tmr_ilck; /* tick service interlock */
int t__secw(); /* wait queue update function */
struct t_scls *cls; /* priority queue pointer */
struct t_scls **ary; /* priority queue pointer array pointer */
int i; /* iteration variable */
char *s; /* pointer */
tmr__int(); /* initialize system tick clock */
sys_task = sys_ssbs + sys_sssz; /* set main task control table pointer */
_tsk -> t_xtm0 = /* initialize execution time */
_tsk -> t_xtm1 =
_tsk -> t_xtm2 = 0;
if( ( sys_tsch = mm_aloc( sizeof( struct t_schd ) ) ) == _NULL )goto err1;
if( ( ary = mm_aloc( T_SCLS*( sizeof( struct t_scls )+2 ) ) )
== _NULL )goto err2;
_tsk -> t_pqtsk = /* NULL linkage */
_tsk -> t_nqtsk =
_tsk -> t_ratsk =
_tsk -> t_pstsk =
_tsk -> t_nstsk =
_tsk -> t_fdtsk =
_tsk -> t_ldtsk = _NULL;
_tsk -> t_cls = 0; /* set priority class 0 */
_tsk -> t_wttk = 0; /* indicate not waiting */
for( i = 0, s = &_tsk -> t_ps;
i++ _tsk -> t_ps.sys_cs = sys_stat.sys_cs; /* set selectors */
_tsk -> t_ps.sys_ds =
_tsk -> t_ps.sys_es =
_tsk -> t_ps.sys_ss = sys_dgrp;
_tsk -> t_axstk = _NULL; /* NULL execution stack pointer */
_tschd -> t_xct = 1; /* set execution task count */
_tschd -> t_fxtsk = /* set execution queue */
_tschd -> t_lxtsk = sys_task;
_tschd -> t_wct = 0; /* indicate idle wait queue */
_tschd -> t_fwtsk = /* set wait queue */
_tschd -> t_lwtsk = _NULL;
_tschd -> t_swct = 0; /* indicate empty secondary wait queue */
_tschd -> t_fswtsk = /* NULL secondary wait queue */
_tschd -> t_lswtsk = _NULL;
_tschd -> t_sclsl = T_SCLS; /* set priority queue count */
_tschd -> t_sclsp = ary; /* set priority queue pointer array address */
cls = &ary[ T_SCLS ]; /* set first t_scls pointer */
for( i = 0; i {
ary[i] = cls; /* set priority queue pointer */
cls -> t_sfrq = 1; /* set default frequency */
cls -> t_sct = 0; /* indicate empty queue */
cls -> t_fqtsk = /* NULL queue linkage */
cls -> t_lqtsk = _NULL;
}
t_wqupd = /* create task to update wait queue */
t_crt( t__secw, 0, 0, WSTK, 0, 0, 0 );
if( t_wqupd == _NULL )goto err3;
t_wqupd -> t_wttk = 0xFFFF; /* update wait queue at wraparound time */
t__dspsy(); /* dispatch system */
tmr_ilck = 0x00; /* enable tick service */
return _F; /* indicate task system initialized */
err3: mm_free( ary ); /* error nest */
err2: mm_free( sys_tsch );
err1: return _E;
}

/*
t__term
*/
t__term()
/*
The task system is terminated. All tasks and storage allocated by t__init are
released. The return is always _F. */
{
extern char *sys_ssbs; /* system stack base */
extern unsigned sys_sssz; /* system stack size */
struct t_task *t; /* t_task pointer */
char trmflg; /* system state flag storage */
tmr__rst(); /* reset system tick clock */
t__syntr( &trmflg ); /* enter system state */
sys_task = sys_ssbs + sys_sssz; /* set original task address */
while( ( t = _tsk -> t_fdtsk ) ) /* delete all created tasks */
t_del( t, _F );
mm_free( _tschd -> t_sclsp );
mm_free( sys_tsch );
return _F; /* normal return */
}

/*
t_crt create task
*/
t_crt( xadr, pcnt, padr, ssiz, dsiz, sadr, prty )
pointer *xadr;
unsigned pcnt;
unsigned *padr;

unsigned ssiz, dsiz;
pointer *sadr;
unsigned prty;
/*
A new task is created with execution priority prty. Execution will begin at
xadr. pcnt parameters will be passed (on the new task stack). The parameters
are in an array addressed by padr. The new task will have a stack of ssiz
bytes and a dynamic memory area of dsiz bytes. dsiz may be zero to indicate
that no dynamic memory is required. sadr will recieve a termination code when
the task terminates. If sadr is _NULL, an abreviated task is created. _F is
returned if insufficient memory is available. Otherwise the address of the
t_ftask table is returned. */
{
extern int t__halt(); /* return address */
struct t_task *tsk; /* task control table pointer (t_task) */
struct t_scls *pq; /* priority queue pointer */
struct t_xstck *sp; /* execution stack pointer */
pointer *ss; /* stack start */
unsigned *pr; /* parameter pointer */
unsigned ln; /* task control table length */
int i; /* iteration variable */
char *s; /* pointer */
char *sptr; /* execution stack pointer */
logical crtflg; /* system state flag storage */
t__syntr( &crtflg ); /* enter system state */
ln = sizeof( struct t_task ); /* allocate task control table */
if( ( tsk = mm_aloc( ln ) ) == _NULL ) goto err1;
ssiz += sizeof( struct t_xstck ); /* allocate stack */
if( ( ss = tsk -> t_axstk = mm_aloc( ssiz ) ) == _NULL )goto err2;
tsk -> t_type = T_ATASK; /* indicate abreviated task control table */
tsk -> t_wttk = 0; /* indicate not waiting */
tsk -> t_ratsk = sys_task; /* task family linkage */
tsk -> t_pstsk = _tsk -> t_ldtsk;
tsk -> t_nstsk =
tsk -> t_fdtsk =
tsk -> t_ldtsk = _NULL;
_tsk -> t_ldtsk = tsk;
if( tsk -> t_pstsk == _NULL )_tsk -> t_fdtsk = tsk;
else tsk -> t_pstsk -> t_nstsk = tsk;
if( prty > _tschd -> t_sclsl ) /* adjust priority */
prty = _tschd -> t_sclsl-1;
tsk -> t_cls = prty; /* set priority */
pq = _tschd -> t_sclsp[ prty ]; /* set scheduling array pointer */
++pq -> t_sct; /* scheduling linkage */
tsk -> t_pqtsk = pq -> t_lqtsk;
tsk -> t_nqtsk = _NULL;
if( tsk -> t_pqtsk == _NULL )pq -> t_fqtsk = tsk;
else tsk -> t_pqtsk -> t_nqtsk = tsk;
pq -> t_lqtsk = tsk;
tsk -> t_xtm0 = /* no execution time yet */
tsk -> t_xtm1 =
tsk -> t_xtm2 = 0;
pr = sptr = ss+ssiz-2*pcnt; /* initialize execution stack & t_ps */
tsk -> t_ps.sys_sp =
sp = sptr - sizeof( struct t_xstck );
sp -> t_xbp = ss + ssiz;
sp -> t_xbase = ss;
while( pcnt-- )*pr++ = *padr++;
for( i = 0, s = &tsk -> t_ps; i++ < sizeof( struct sys_parm ); )*s = 0;
tsk -> t_ps.sys_ds =
tsk -> t_ps.sys_es =
tsk -> t_ps.sys_ss =
sp -> t_xds =
sp -> t_xes = _tsk -> t_ps.sys_ds;
sp -> t_xdi =
sp -> t_xsi =
sp -> t_xdx =
sp -> t_xcx =
sp -> t_xbx =
sp -> t_xax = _NULL;
sp -> t_xip = xadr;
tsk -> t_ps.sys_cs =
sp -> t_xcs =
_tsk -> t_ps.sys_cs;
tsk -> t_ps.sys_pf =
sp -> t_xpf = SYS_IF;
tsk -> t_ps.sys_ip =
sp -> t_retip = &t__halt;
t__syxit( &crtflg ); /* exit system state */
return tsk; /* return */
err3: mm_free( tsk -> t_ps.sys_ss );
err2: mm_free( tsk );
err1: t__syxit( &crtflg );
return _NULL;
}

/*
t__halt terminate task
*/
t__halt()
/*
If a subtask returns into its orginal stack, control will pass to t__halt.
This function deletes the subtask and then clears the sys_task pointer just
before returning on the system stack (to reenter the security kernel). */
{
logical haltflg; /* system state flag storage */
t__syntr( &haltflg ); /* enter system state */
t_rtmark( &_tsk -> t_ratsk -> t_xtm0 ); /* accumulate pseudo time */
t_del( sys_task, _F ); /* delete current task */
sys_task = _NULL; /* indicate task terminated */
while(_T)t_term(); /* return to security kernel */
}

/*
t_del delete task
*/
t_del( tsk, st )
struct t_task *tsk;
int st;
/*
Task tsk is killed. st is the status returned to the calling program.
*/
{
#define tskf ( ( struct t_ftask * )tsk ) /** (t_ftask) */
struct t_task *t; /* task control table pointer */
logical delflg; /* system state flag storage */
t__syntr( &delflg ); /* enter system state */
while( ( t = tsk -> t_fdtsk ) )t_del( t, st ); /* delete subtasks first */
if( tsk -> t_pstsk ) /* family linkage */
tsk -> t_pstsk -> t_nstsk = tsk -> t_nstsk;
else tsk -> t_ratsk -> t_ldtsk = tsk -> t_nstsk;
if( tsk -> t_nstsk )
tsk -> t_nstsk -> t_pstsk = tsk -> t_pstsk;
else tsk -> t_ratsk -> t_fdtsk = tsk -> t_pstsk;
if( tsk -> t_pqtsk ) /* queue linkage */
tsk -> t_pqtsk -> t_nqtsk = tsk -> t_nqtsk;
else if( ( tsk -> t_type&T_P )
&& ( _tschd -> t_sclsp[ tsk -> t_cls ] -> t_fqtsk == tsk ) )
_tschd -> t_sclsp[ tsk -> t_cls ] -> t_fqtsk = tsk -> t_nqtsk;
else if( ( tsk -> t_type&T_W ) && ( _tschd -> t_fwtsk == tsk ) )
_tschd -> t_fwtsk = tsk -> t_nqtsk;
else if( ( tsk -> t_type&T_SW ) && ( _tschd -> t_fswtsk == tsk ) )
_tschd -> t_fswtsk = tsk -> t_nqtsk;
else if( ( tsk -> t_type&T_X ) && ( _tschd -> t_fxtsk == tsk ) )
_tschd -> t_fxtsk = tsk -> t_nqtsk;
if( tsk -> t_nqtsk )tsk -> t_nqtsk -> t_pqtsk = tsk -> t_pqtsk;
else if( ( tsk -> t_type&T_P )
&& ( _tschd -> t_sclsp[ tsk -> t_cls ] -> t_lqtsk == tsk ) )
_tschd -> t_sclsp[tsk -> t_cls] -> t_lqtsk = tsk -> t_pqtsk;
else if( ( tsk -> t_type&T_W ) && ( _tschd -> t_fwtsk == tsk ) )
_tschd -> t_lwtsk = tsk -> t_pqtsk;
else if( ( tsk -> t_type&T_SW ) && ( _tschd -> t_fswtsk == tsk ) )
_tschd -> t_lswtsk = tsk -> t_pqtsk;
else if( ( tsk -> t_type&T_X ) && ( _tschd -> t_fxtsk == tsk ) )
_tschd -> t_lxtsk = tsk -> t_pqtsk;
t = sys_task; /* save current t_task pointer */
sys_task = tsk -> t_ratsk; /* set ancestor task */
mm_free( tsk -> t_ps.sys_ss ); /* free stack */
mm_free( tsk ); /* free t_task table */
sys_task = t; /* restore current task pointer */
t__syxit( &delflg ); /* exit system state */
return _F; /* return */
}

/*
mm_aloc memory allocation
*/
mm_aloc(ln)
unsigned ln;
/*
ln bytes are allocated from the heap. The address of the first byte is
returned. If there is not enough available memory to satisfy the request,
_NULL is returned. */
{
return malloc(ln); /* allocate storage */
}

/*
mm_free memory deallocation
*/
mm_free(st)
char *st;
/*
st is the address returned by a previous call to function mm_free. The storage
previously allocated is made available for future use. The normal return is
_F. _E is returned if st does not point to an area previously allocated by
mm_aloc. */
{
return free(st); /* deallocate storage */
}

/*
main test program
*/
main()
/*
This function serves to test the task scheduler. Two tasks are created, each
of which increments a variable. The original task continually displays the
counts, as well as its own iteration number. Depressing any key will cause a
return to MS-DOS. */
{
int ctr1, ctr2, ctr3; /* counters */
int count(); /* counting subroutine */
int param[ 2 ]; /* parameter array */
printf("tasktest (C) 1986 Ken Berry- All Rights Reserved\n");
printf("Tele task scheduler: 1986 September 2 version (DDJ mod)\n\n");
t__init(); /* initialize task scheduler */
ctr1 = ctr2 = ctr3 = 0; /* initialize counters */
param[ 0 ] = &ctr1; /* create first task */
param[ 1 ] = 1;
t_crt( count, 2, ¶m, 256, 0, 0, 0);
param[ 0 ] = &ctr2; /* create second task */
param[ 1 ] = 2;
t_crt( count, 2, ¶m, 256, 0, 0, 0);
while( !kbhit() ) /* loop until key depressed */
{
++ctr3; /* increment main loop count */
printf("main = %d, task 1 = %d, task 2 = %d\n", ctr3, ctr1, ctr2 );
}
getch(); /* discard termination character */
t__term(); /* terminate task scheduler */
return _F; /* return to MSöDOS */
}

count(ctr,inc)
int *ctr,inc;
{
while(_T) /* infinite loop */
{
*ctr += inc; /* update counter */
}
}



Listing 2- System Definitions
(C) Copyright 1986 Ken Berry.
All rights reserved.
Copies may be made for non-commercial, private use only.


sys_parm struc ;; register storage block
rax dw ? ;; ax (general register A)
rbx dw ? ;; bx (general register B)
rcx dw ? ;; cx (general register C)
rdx dw ? ;; dx (general register D)
rbp dw ? ;; bp (base pointer)
rsi dw ? ;; si (source index)
rdi dw ? ;; di (destination index)
rsp dw ? ;; sp (stack pointer)
rcs dw ? ;; cs (code segment)
rds dw ? ;; ds (data segment)
rss dw ? ;; ss (stack segment)
res dw ? ;; es (extra segment)
rpf dw ? ;; pf (processor flags)
rsw dw ? ;; sw (status word)
rip dw ? ;; ip (instruction pointer)
rres dw ? ;; unused
sys_parm ends

t_task struc ;; task control table
t_type db ? ;; task type
t_wttk dw ? ;; wait tick count
t_cls dw ? ;; priority queue index
t_pqtsk dw ? ;; prior t_task pointer
t_nqtsk dw ? ;; next t_task pointer
t_ratsk dw ? ;; ancestor t_task pointer
t_pstsk dw ? ;; prior sibling t_task pointer
t_nstsk dw ? ;; next sibling t_task pointer
t_fdtsk dw ? ;; first desendant t_task pointer
t_ldtsk dw ? ;; last desendant t_task pointer
t_ps db type sys_parm dup (?) ;; processor status
t_xtm0 dw ? ;; * execution time accumulator
t_xtm1 dw ? ;; *
t_xtm2 dw ? ;; *
t_axstk dw ? ;; application stack pointer
t_task ends

T_ATSK equ 01h ;; abreviated task
T_X equ 80h ;; execute wueue
T_W equ 40h ;; wait queue
T_P equ 20h ;; priority queue
t_SW equ 10h ;; secondary wait queue

t_scls struc ;; scheduling class queue
t_sfrq dw ? ;; scheduling frequency
t_sct dw ? ;; queue length
t_fqtsk dw ? ;; first task in queue
t_lqtsk dw ? ;; last task in queue
t_scls ends

t_schd struc ;; scheduling control table
t_xct dw ? ;; execution queue length
t_fxtsk dw ? ;; first task in execution queue
t_lxtsk dw ? ;; last task in execution queue
t_wct dw ? ;; wait queue length
t_fwtsk dw ? ;; first task in wait queue
t_lwtsk dw ? ;; last task in wait queue
t_swct dw ? ;; secondary wait queue length
t_fswtsk dw ? ;; first task in secondary wait queue
t_lswtsk dw ? ;; last task in secondary wait queue
t_sclsl dw ? ;; scheduling class index limit
t_sclsp dw ? ;; scheduling class array pointer
t_schd ends

t_calln struc ;; near function call
t_nbp dw ? ;; base pointer storage
t_nret dw ? ;; return address
t_np0 dw ? ;; parameter 0
t_np1 dw ? ;; parameter 1
t_np2 dw ? ;; parameter 2
t_np3 dw ? ;; parameter 3
t_np4 dw ? ;; parameter 4
t_np5 dw ? ;; parameter 5
t_np6 dw ? ;; parameter 6
t_np7 dw ? ;; parameter 7
t_calln ends

t_xtsk struc ;; execution stack
t_xbase dw ? ;; _base (for stack overflow detection)
t_xes dw ? ;; es
t_xbp dw ? ;; bp
t_xdi dw ? ;; di
t_xsi dw ? ;; si
t_xdx dw ? ;; dx
t_xcx dw ? ;; cx
t_xbx dw ? ;; bx
t_xax dw ? ;; ax
t_xds dw ? ;; ds
t_xip dw ? ;; ip
t_xcs dw ? ;; cs
t_xpf dw ? ;; pf
t_retip dw ? ;; return ip
t_xtsk ends

retn macro s ;; near return
ifnb
db 0C2h ;; pop ip & adjust sp
db high s ;; * adjustment value
db low s ;; *
else
db 0C3h ;; pop ip only
endif
endm

retf macro s ;; far return
ifnb
db 0CCh ;; pop ip, cs & adjust sp
db high s ;; * adjustment value
db low s ;; *
else
db 0CBh ;; pop ip, cs only
endif
endm

ilck macro reg,flag
xchg reg,flag ;; capture token
endm

iowait macro
nop ;; I/O delay
endm

sys_entr macro flag ;; enter system function
ifndef sys_ilck
extrn sys_ilck:byte
endif
mov al,0FFh ;; ** system task interlock
ilck al,sys_ilck ;; **
mov flag,al ;; save asynchronous status
endm

sys_exit macro flag ;; exit from system function
local exit1,exit2
ifndef sys_ilck
extrn sys_ilck:byte
endif
ifndef t_astrm
extrn t_astrm:byte
endif
ifndef t_term
extrn t_term:near
endif
test byte ptr t_astrm,0FFh ;; * test for application terminated
jnz exit1 ;; *
mov byte ptr sys_ilck,0 ;; exit system state
jmp short exit2 ;; continue application task
exit1: test flag,0FFH ;; ** test for more stacked system tasks
jnz exit2 ;; **
call t_term ;; terminate application task
exit2: ;; macro exit
endm

sys_sync macro flag ;; synchronize system resource
ifndef t_sync
extrn t_sync:near
endif
lea bx,flag ;; set flag offset
call t_sync ;; suspend task until token obtained
endm

sys_sstk macro ;; conditionally establish system stack
local sstk1
ifndef t__sstk
extrn t__sstk:near
endif
or al,al ;; * test for system task interrupted
jnz sstk1 ;; *
call t__sstk ;; establish system stack
sstk1: push ds ;; ** set es = ds
pop es ;; **
endm

sys_sctx macro ;; save processor context
push bx ;; protect bx
push cx ;; protect cx
push dx ;; protect dx
push si ;; protect si
push di ;; protect di
push bp ;; protect bp
push es ;; protect es
cld ;; clear direction flag
sys_sstk ;; conditionally establish system stack
endm

sys__rctx macro ;; restore processor context (except ds)
pop es ;; restore es
pop bp ;; restore bp
pop di ;; restore di
pop si ;; restore si
pop dx ;; restore dx
pop cx ;; restore cx
pop bx ;; restore bx
pop ax ;; restore ax
endm

sys_rctx macro ;; restore processor context
sys__rctx ;; restore context (except ds)
pop ds ;; restore ds
endm

sys_ient macro flag
push ds ;; protect ds
push ax ;; protect ax
mov ax,dgroup ;; * establish data addressability
mov ds,ax ;; *
sys_entr flag ;; enter system state
sti ;; interrupts on
sys_sctx ;; save processor context
endm

sys_iret macro flag
local iret1
ifndef t_astrm
extrn t_astrm:byte
endif
cli ;; interrupts off
test byte ptr t_astrm,0FFh ;; * test for application not terminated
jz iret1 ;; *
test flag,0FFh ;; ** test for system state interrupted
jnz iret1 ;; **
sti ;; interrupts on
retn ;; return to task management
iret1: sys_rctx ;; restore processor context
iret ;; resume interrupted task
endm

dseg macro
dgroup group data
data segment word public 'data'
assume ds:dgroup,es:dgroup,ss:dgroup
endm

endds macro
data ends
endm

pseg macro
pgroup group prog
prog segment byte public 'prog'
assume cs:pgroup
endm

endps macro
prog ends
endm



Listing 3 Scheduling Algorithm (Assembly Subroutines)
(C) Copyright 1986 Ken Berry.
All rights reserved.
Copies may be made for non-commercial, private use only.


include tele.mac ; system definitions (listing 2)

extrn t_astrm:byte ; application task termination flag
extrn t_rtmark:near ; update pseudo time accumulator
extrn t__krnl:near ; security kernel

public sys_task ; current task pointer
public sys_tsch ; task scheduling table pointer
public sys_ilck ; system task interlock
public sys_asbs ; application stack base
public sys_dgrp ; data segment storage
public sys_ssbs ; system stack base
public sys_sssz ; system stack size
public sys_sstp ; system stack top
public sys_stat ; original register block
public t_mnxtm ; minimum execution time
public t_rels ; release
public t_spnd ; suspend
public t_syxtm ; system pseudo time accumulator
public t_term ; reschedule
public t_wait ; wait
public t_wqupd ; wait queue update task pointer
public t__crtss ; current task ss storage
public t__crtsp ; current task sp storage
public t__dspap ; dispatch application
public t__dspsy ; dispatch system
public t__sstk ; establish system stack
public t__syntr ; enter system state
public t__syxit ; exit system state

MINXTM equ 500 ; minimum execution time
STKLN equ 1024 ; system stack size

dseg

tmrdx dw 0 ; dx storage
spdss dw 0 ; ss storage
spdsp dw 0 ; sp storage

t__crtss dw 0 ; current task ss storage
t__crtsp dw 0 ; current task sp storage

sys_stat db type sys_parm dup (0) ; original register block
sys_dgrp dw 0 ; data segment storage
sys_task dw 0 ; current task pointer
sys_tsch dw 0 ; task scheduling table pointer
sys_asbs dw 0 ; application stack base
sys_ssbs dw stkbs ; system stack base
sys_sssz dw STKLN ; system stack length
sys_sstp dw STKLN ; system stack top
sys_ilck db 0FFh ; system task interlock

t_wqupd dw 0 ; wait queue update task pointer

t_syxtm dw 3 dup (0) ; system pseudo time accumulator

t_mnxtm dw MINXTM ; minimum execution time

stkbs db STKLN dup (0) ; system stack
db type t_task dup (0) ; main task control table

endds

pseg

comment ~

t__dspap(ss,sp)
selector ss;
unsigned sp;

ss and sp are placed in the stack registers. Then the other registers are
restored from the new stack. Control passes to the restored task. The return
address is left at the top of the system stack. Therefore the restored task
may use the system stack to return to the caller of t__dspap. ax may contain a
return code in this case.
~

t__dspap proc near
push bp ; protect bp
mov bp,sp ; establish parameter addressability
mov ax,[bp].t_np0 ; set application stack
mov bx,[bp].t_np1
mov sys_sstp,sp ; store current top of system stack
cli
mov ss,ax
mov sp,bx
mov bp,sp ; enable interrupts
or [bp].t_xpf,0200h
pop sys_asbs
sti
sys__rctx ; restore context
cli ; interrupts off
mov byte ptr sys_ilck,0 ; exit system state
mov byte ptr t_astrm,0 ; initialize application interval
pop ds ; restore ds
iret ; execute task
t__dspap endp

comment ~

t_term() _F
t_spnd(tp) tp
t_wait(tp) tp
unsigned tp;
t_rels() _E

All of these functions are similar. The processor registers are stored on
the stack, which is then adjusted to match the pattern for interrupt
returns. Finally the system stack is established. The functions differ in
the code returned to the caller of function t__dspap. t__dspap restores
the registers and returns control to the caller of these functions. The
returned value is shown with the appropriate call above. tp is only used
with t_spnd and t_wait. It is the number of system ticks to wait before
executing the task again. t_wait functions like t_spnd, except that t_rels
is invoked immediately. ~

t_term proc near
call t__trmap ; protect registers
xor ax,ax ; return _F
ret
t_term endp

t_spnd proc near
mov spdss,ss ; store stack pointers
mov spdsp,sp
call t__trmap ; protect registers
mov es,spdss ; return tick count
mov si,spdsp
mov ax,word ptr es:[si+2]
push ds ; set es = ds
pop es
ret ; return
t_spnd endp

t_wait proc near
push bp ; protect bp
mov bp,sp ; establish stack addressability
mov ax,[bp].t_np0 ; suspend task
push ax
call t_spnd
mov sp,bp ; unload stack
pop bp ; restore bp
t_rels proc near

call t__trmap ; protect registers
xor ax,ax ; return _E
dec ax
ret
t_rels endp
t_wait endp

comment ~

t__dspsy()

A call to function t__trmap is made so that after the registers are stored in
the application stack (and the system stack is made current), control passes
to function t__krnl, the system security kernel. Control will return from
t__dspsy when the calling task is resumed. Nothing is returned.
~

t__dspsy proc near
mov ax,offset pgroup:t__krnl ; branch to system
push ax
sub sys_sstp,2 ; adjust system stack (for "pop bp" in t__sstk)

comment ~

t__trmap()

The machine registers are stored on the application stack. Then the system
stack is made current. The return address from the call to t__trmap is put on
the system stack before returning to it. Nothing is returned.
~

t__trmap proc near
mov byte ptr sys_ilck,0FFh ; force system state
mov tmrdx,dx ; save dx
pop dx ; set return address (from t__trmap)
push cs ; protect cs
pushf ; protect flags
push ds ; protect ds
push ax ; protect ax
push bx ; protect bx
push cx ; protect cx
push tmrdx ; protect dx
push si ; protect si
push di ; protect di
push bp ; protect bp
push es ; protect es
push dx ; restore return address to stack
mov bp,sp ; establish stack addressability
mov ax,[bp].t_xip ; adjust stack for interrupt return
xchg ax,[bp].t_xpf
mov [bp].t_xip,ax

comment ~

t__sstk()

The current application stack pointers are stored. Then the system stack is
established as the current stack. The return address from the call is placed
on the system stack before returning into it. Nothing is returned.
~

t__sstk proc near
pop dx ; unload return address
push sys_asbs ; protect stack protection reference
mov bx,ss ; set application stack registers
mov cx,sp
mov ax,sys_ssbs ; set system stack
cli
mov sys_asbs,ax
push ds
pop ss
mov sp,sys_sstp
sti
pop bp ; restore bp
mov t__crtss,bx ; store current ss
mov t__crtsp,cx ; store current bp
push dx ; return to caller
ret
t__sstk endp
t__trmap endp
t__dspsy endp

comment ~

t_sync(flg)
char *flg;

A wait loop will be entered until the required resource is available. This is
indicated by flg containing 0x00. 0xFF is stored to prevent any other tasks
from acquiring the resource. The resource is released by resetting flg to
0x00.
~

t_sync proc near
push bp ; protect bp
mov bp,sp ; establish stack addressability
mov bx,[bp].t_np0 ; set pointer to resource flag

sync1: mov al,0FFh ; interlock token
ilck al,
or al,al ; test for token acquired
jz sync2
xor ax,ax ; wait for 1 system tick
inc ax
push ax
call t_spnd
mov sp,bp
jmp sync1 ; continue

sync2: pop bp ; restore bp
call t_rels ; release task
ret ; return
t_sync endp

comment ~

t__syntr(flg)
char *flg;

This function expands the sys_entr macro for use by c functions.
~

t__syntr proc near
push bp ; protect bp
mov bp,sp ; establish stack addressability
mov bx,[bp].t_np0 ; set flag address
sys_entr ; enter system state
pop bp ; restore bp
ret ; return
t__syntr endp


comment ~

t__syxit(flg)
char *flg;

This function expands the sys_exit macro for use by c functions.
~

t__syxit proc near
push bp ; protect bp
mov bp,sp ; establish stack addressability
mov bx,[bp].t_np0 ; set flag address
sys_exit ; exit system state
pop bp ; restore bp
ret ; return
t__syxit endp

endps

end



Listing 4 High Resolution Clock
(C) Copyright 1986 Ken Berry.
All rights reserved.
Copies may be made for non-commercial, private use only.
~

include tele.mac ; system defintions (listing 2)

extrn t_syxtm:word ; system execution time accumulator
extrn sys_dgrp:word ; data segment storage
extrn sys_stat:word ; original register block

public t__tick ; system tick interrupt service
public t_astrm ; application task termination flag
public tmr_dspl ; physical display pointer
public tmr_dvsr ; timer period
public tmr_ilck ; tick service reentrant interlock
public tmr_sync ; synchronization function address
public tmr_tkct ; tick clock
public tmr_xtm ; tick service execution time
public tmr__clr ; reset time base generation
public tmr__int ; timer initialization function
public tmr__rst ; timer termination function
public tmr__sts ; read timer status
public tmr__tmr ; restart hardware timer
public t_rdclk ; read high resolution clock
public t_rtactg ; psuedo time accumulator pointer
public t_rtmark ; mark execution interval
public t__rdclk ; read real time clock
public td_ref ; clock update tick reference count
public td_tct ; clock tick timer
public td__set ; set time of day clock
public td__upd ; update time of day clock
public w__cdspl ; physical display update function
public w__sync ; physical display synchronization

RLCINT equ 80h ; relocated alternate time base interrupt
TMRINT equ 8 ; hardware timer interrupt
TMRPRT equ 40h ; timer (8253) port
TMRPRD equ 19912 ; timer period (60 Hz rate)
;TMRPRD equ 9956 ; timer period (120 Hz rate)
INTPRT equ 20h ; interrupt controller (8259) port
TMRMSK equ 01h ; hardware timer interrupt mask
INTEOI equ 20h ; interrupt termination value
DSPCT equ 1 ; 60 Hz interrupt rate
;DSPCT equ 2 ; 120 Hz interrupt rate
IDV0 equ 3 ; tmr_idv0 divisor
ISKP0 equ 776 ; tmr_ict correction value
ISKP1 equ 11 ; tmr_idv1 correction value
ISKP2 equ 38 ; tmr_idv2 correction value

dseg

tmr_tkct dw 0 ; interrupt counter
tmr_dct db 0 ; display counter
tmr_ict dw 0 ; tick clock (for time base generation)
tmr_dvsr dw TMRPRD ; 1/2 timer period
t_astrm db 0FFh ; application task termination flag
tmrflg db 0FFh ; system state flag (t__tick)
tmr_ilck db 0 ; tick service reentrant interlock
tmr_idv0 db 0 ; clock time base generator
tmr_idv1 db 0 ; primary alternate time base generator
tmr_idv2 db 0 ; secondary alternate time base generator
tmr_dspl dw 0 ; console display w_pwdw pointer
t_rtactg dw 0 ; psuedo time accumulator pointer
t_rtrfct dw 0 ; real time reference count
t_rttick dw 0 ; tick clock phase
tmr_xtm dw 3 dup (0) ; tick service psuedo time accumulator
tmrpxtm dw 0 ; prior psuedo time accumulator pointer
tmr_sync dw offset pgroup:w__sync ; synchronization function pointer
td_ref dw 0 ; clock update tick reference count
td_tct dw 0 ; clock tick timer

endds

pseg

comment ~
t__tick system tick service

t__tick\\

Control only comes here in response to an interrupt from the system clock.
This function serves three purposes. It maintains the system clock, which
provides the current date and time for both system and application uses. It
also performs an update of the first physical display. And finally it
terminates the execution interval for the current application task.
~

t__tick proc far

; reentrant lockout

assume ss:nothing,ds:nothing,es:nothing
sti ; interrupts on
push ds ; protect ds
push ax ; protect ax
mov ax,dgroup ; establish data addressability
mov ds,ax
assume ds:dgroup
mov al,INTEOI ; terminate interrupt
out INTPRT,al
ilck al,tmr_ilck ; test for not reentrant call
or al,al
jz tick
pop ax ; restore ax
pop ds ; restore ds
iret ; return from interrupt

; system interlock

tick: mov t_astrm,0FFh ; terminate application task
sys_entr tmrflg ; enter system state

; set machine environment

sys_sctx ; save processor context
push bp ; protect bp
mov bp,sp ; mark stack location
lea ax,tmr_xtm ; accumulate psuedo time
push ax
call t_rtmark
mov sp,bp
mov tmrpxtm,ax ; store prior pointer

; real time system processing

inc tmr_dct ; remove display harmonics
mov al,DSPCT
xor al,tmr_dct
jnz tick4
mov tmr_dct,al
push tmr_dspl ; display physical window
call w__cdspl
mov sp,bp ; restore stack pointer
inc tmr_ict ; increment interrupt counter
inc tmr_tkct ; increment tick clock

; time base generation

mov ax,ISKP0 ; long term time base correction
xor ax,tmr_ict
jnz tick1
mov tmr_ict,ax
call tick5 ; update system tick clock
tick1: inc tmr_idv0 ; generate clock time base
mov al,IDV0
xor al,tmr_idv0
jnz tick3
mov tmr_idv0,al
call tick5 ; update system tick clock
inc tmr_idv1 ; primary alternate time base correction
mov al,ISKP1
xor al,tmr_idv1
jnz tick2
mov tmr_idv1,al
int RLCINT ; update alternate time base
inc tmr_idv2 ; secondary alternate time base correction
mov al,ISKP2
xor al,tmr_idv2
jnz tick2
mov tmr_idv2,al
int RLCINT ; update alternate time base
tick2: int RLCINT ; update alternate time base

; terminate interrupt service

tick3: push tmrpxtm ; restore original psuedo time accumulator
call t_rtmark
mov sp,bp
pop bp ; restore bp
test tmrflg,0FFh ; test for interrupted system task
jnz tick4
xor ax,ax ; terminate task
mov tmr_ilck,al ; enable reentrance
retn ; near return to system task management

tick4: sys__rctx ; restore processor context
cli ; interrupts off
mov tmr_ilck,0 ; enable reentrance
pop ds ; restore ds
iret ; return to interrupted task

; update system tick counter

tick5: mov ax,td_tct ; test for no overflow
inc ax
cmp ax,td_ref
jne tick6
call td__upd ; update clock
xor ax,ax ; reset tick counter
mov td_ref,ax
mov td_tct,ax
tick6: inc td_tct ; increment tick counter
retn ; return

t__tick endp

comment ~
tmr__int initialize timer

tmr__int()

All data areas necessary for clock maintenance are initialized. The hardware
timer is programmed for the appropriate rate and its interrupt vector is made
to point to sys_tmr. The original vector is relocated and will be used by
sys_tmr as the alternate time base.
~

tmr__int proc near
call tmr__dsi ; diable interrupts
mov ax,dgroup ; set data segment
mov sys_dgrp,ax
mov ax,cs ; set code segment
lea si,sys_stat
mov [si].rcs,ax
cli ; interrupts off
mov tmr_ilck,0FFh ; lockout t__tick
mov bx,tmr_sync ; test for no synchronization function
test bx,bx
jz int0
lea bx,tmr_sync ; synchronize timer interrupt
call [bx]
jmp short int1 ; continue
int0: call tmr__tmr ; start timer
int1: call t_rdclk ; set real time clock phase
mov t_rttick,ax
mov t_rtrfct,ax ; set reference count
mov t_rtactg,offset dgroup:t_syxtm ; initialize time accumulator
call td__set ; set current time
sti ; interrupts on
xor ax,ax ; form 0
push ds ; protect ds
mov ds,ax ; relocate original interrupt vector
mov di,ax
cli
mov ax,[di+4*TMRINT]
mov [di+4*RLCINT],ax
mov ax,[di+4*TMRINT+2]
mov [di+4*RLCINT+2],ax
mov ax,offset pgroup:t__tick ; set interrupt service
mov [di+4*TMRINT],ax
mov ax,cs
mov [di+4*TMRINT+2],ax
sti ; interrupts on
pop ds ; restore ds
call tmr__eni ; enable interrupts
ret ; return
tmr__int endp


comment ~
tmr__clr reset time base generation

tmr__clr()

The time base adjustment variables are reset. This function is to be called by
td__set when the time of day is initially set from a continuous clock. Nothing
is returned.
~

tmr__clr proc near
xor ax,ax ; zero time base generation variables
mov tmr_idv0,al
mov tmr_idv1,al
mov tmr_idv2,al
ret ; return
tmr__clr endp


comment ~
tmr__rst reset timer

tmr__rst()

The original interrupt service routine is restored and the hardware clock is
reprogrammed. However, the original hardware values are not available in this
edition. Therefore the original system state cannot always be restored.


tmr__rst proc near
mov tmr_ilck,0FFh ; lock out interrupt service
push ds ; protect ds
xor ax,ax ; restore original interrupt vector
mov ds,ax
mov di,ax
call tmr__dsi ; disable timer interrupt
cli ; interrupts off
mov ax,[di+4*RLCINT]
mov [di+4*TMRINT],ax
mov ax,[di+4*RLCINT+2]
mov [di+4*TMRINT+2],ax
pop ds ; restore ds
xor bx,bx ; restart hardware timer
call tmr__str
sti ; interrupts on
call tmr__eni ; enable timer interrupt
ret ; return
tmr__rst endp

comment ~
tmr__tmr restart hardware timer

tmr__tmr\\

Channel 0 of an 8253 timer is initialized to mode 3. The count in bx is then
programmed.


tmr__tmr proc near ; restart timer
mov bx,tmr_dvsr ; set tele system tick period
tmr__str proc near ; set timer period
mov al,20 ; reset 8253 (mode 0, count >= 8,192)
out TMRPRT+3,al ; [> 6.8 msec]
iowait
out TMRPRT,al
mov al,36h ; initialize 8253 (mode 3, both bytes)
iowait
out TMRPRT+3,al
mov al,bl
iowait
out TMRPRT,al
mov al,bh
iowait
out TMRPRT,al
ret ; return
tmr__str endp
tmr__tmr endp

comment ~
tmr__sts read timer status

tmr__sts()

The returned value is the current count in the timer.
~

tmr__sts proc near ; read timer status
mov al,00h ; set read mode
out TMRPRT+3,al
nop ; allow timer chip to recover
in al,TMRPRT ; read count
mov ah,al
in al,TMRPRT
xchg ah,al
ret ; return
tmr__sts endp

comment ~
tmr__dsi disable interrupt

tmr__dsi()

The timer interrupt is disabled at the 8259 interrupt controller.
~

tmr__dsi proc near
cli ; interrupts off
in al,INTPRT+1 ; disable timer interrupt
or al,TMRMSK
iowait
out INTPRT+1,al
sti ; interrupts on
ret ; return
tmr__dsi endp

comment ~
tmr__eni enable interrupt

tmr__eni()

The timer interrupt is enabled at the 8259 interrupt controller.
~

tmr__eni proc near
cli ; interrupts off
in al,INTPRT+1; ; enable timer interrupt
and al,not TMRMSK
iowait
out INTPRT+1,al
sti ; interrupts on
ret ; return
tmr__eni endp

comment ~
t_rdclk read real time clock

t_rdclk()

The current value of the real time clock is read and returned.
~

DMAREG equ 0 ; refresh address DMA register

t_rdclk proc near
rdclk0: mov dx,DMAREG ; set DMA register address
call t__rdclk ; read time
mov bx,ax ; store time
call t__rdclk ; read time again
cmp ah,bh ; test for interruption
jne rdclk0
ret ; return
t_rdclk endp

t__rdclk proc near
cli ; interrupts off
in al,dx ; read time
mov ah,al
iowait
in al,dx
xchg al,ah
sti ; interrupts on
ret ; return
t__rdclk endp

comment ~
t_rtmark mark execution interval

t_rtmark(np)
pointer *np;

The number of refreshes since the last call to t_rtmark is accumulated. Then
the reference count is reset. np points to the area that will accumulate the
number of refreshes to the next call. The returned value is the original
accumulator pointer.


t_rtmark proc near
push bp ; protect bp
mov bp,sp ; establish parameter addressability
call tmr__dsi ; disable timer interrupt
call t_rdclk ; read real time clock
mov bx,ax ; protect current count
xchg bx,t_rtrfct ; update reference count
sub ax,bx ; compute execution interval
jnc mark1 ; test for no overflow
neg ax ; adjust count
mark1: mov bx,t_rtactg ; accumulate execution time
add ax,[bx]
mov [bx],ax
jnc markxit
add word ptr [bx+2],1
jnc markxit
inc word ptr [bx+4]
markxit: mov ax,bx ; return orginal pointer
mov bx,[bp].t_np0 ; set new accumulator pointer
mov t_rtactg,bx
call tmr__eni ; enable timer interrupt
pop bp ; restore bp
ret ; return
t_rtmark endp

comment ~
w__cdspl display physical buffer

w__cdspl(pw)
struct w_phys *pw;

Physical window pw is displayed. This function is called by the system tick
clock interrupt service function. Nothing is returned.
~

w__cdspl proc near
ret ; return
w__cdspl endp

comment ~
w__sync synchronize interrupt to display

w__sync()

The system tick clock timer is adjusted so that w__dsply executes just prior
to the vertical blanking interval. Nothing is returned.
~

w__sync proc near
call tmr__tmr ; start timer
w__sync endp

comment ~
td__set set time of day clock

td__set()

The clock is set to the current time. Nothing is returned.
~

td__set proc near
ret ; return
td__set endp

comment ~
td__upd update clock

td__upd()

The clock is updated based on the number of ticks since it was last updated.
The normal return (ax) is _F. _E is returned if the call was locked out.
~

td__upd proc near
ret ; return
td__upd endp

endps

end



  3 Responses to “Category : Files from Magazines
Archive   : DDJ8612.ZIP
Filename : BERRY.DEC

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/