home *** CD-ROM | disk | FTP | other *** search
Text File | 1986-12-31 | 62.2 KB | 1,814 lines |
- /*
- 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++<q -> 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++<sizeof( struct sys_parm ); )*s = 0; /* clear t_ps */
- _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<T_SCLS; ++i, ++cls ) /* initialize priority queues */
- {
- 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 <s>
- 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 <s>
- 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,<byte ptr [bx]>
- 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 <byte ptr [bx]> ; 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 <byte ptr [bx]> ; 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
-