home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1986 / 12 / berry.dec next >
Text File  |  1986-12-31  |  64KB  |  1,814 lines

  1. /*
  2. Listing 1      Scheduling Algorithm
  3. (C) Copyright 1986 Ken Berry.
  4. All rights reserved.
  5. Copies may be made for non-commercial, private use only.
  6. */
  7.  
  8. #define _F 0             /* false */
  9. #define _T 1             /* true */
  10. #define _E -1            /* error */
  11.  
  12. #define _NULL 0          /* null pointer */
  13.  
  14. typedef char pointer;    /* pointer type */
  15. typedef char logical;    /* logical type */
  16. typedef unsigned selector; /* 8086 selector type */
  17.  
  18. struct sys_parm          /* register storage block for 8086 interface */
  19. {
  20.   union {unsigned sys_rax; struct {char sys_ral, sys_rah;} sys_byt;} sys_ra;
  21.   union {unsigned sys_rbx; struct {char sys_rbl, sys_rbh;} sys_byt;} sys_rb;
  22.   union {unsigned sys_rcx; struct {char sys_rcl, sys_rch;} sys_byt;} sys_rc;
  23.   union {unsigned sys_rdx; struct {char sys_rdl, sys_rdh;} sys_byt;} sys_rd;
  24. #define sys_ax sys_ra.sys_rax
  25. #define sys_al sys_ra.sys_byt.sys_ral
  26. #define sys_ah sys_ra.sys_byt.sys_rah
  27. #define sys_bx sys_rb.sys_rbx
  28. #define sys_bl sys_rb.sys_byt.sys_rbl
  29. #define sys_bh sys_rb.sys_byt.sys_rbh
  30. #define sys_cx sys_rc.sys_rcx
  31. #define sys_cl sys_rc.sys_byt.sys_rcl
  32. #define sys_ch sys_rc.sys_byt.sys_rch
  33. #define sys_dx sys_rd.sys_rdx
  34. #define sys_dl sys_rd.sys_byt.sys_rdl
  35. #define sys_dh sys_rd.sys_byt.sys_rdh
  36.   unsigned sys_bp;       /* base pointer */
  37.   unsigned sys_si;       /* source index */
  38.   unsigned sys_di;       /* destination index */
  39.   unsigned sys_sp;       /* stack pointer */
  40.   unsigned sys_cs;       /* code segment */
  41.   unsigned sys_ds;       /* data segment */
  42.   unsigned sys_ss;       /* stack segment */
  43.   unsigned sys_es;       /* extra segment */
  44.   unsigned sys_pf;       /* 80286 processor flags */
  45. #define SYS_OF 0x0800         /* overflow flag- 1: lost significance */
  46. #define SYS_DF 0x0400         /* direction flag- 1: strings auto-decrement */
  47. #define SYS_IF 0x0200         /* interrupt flag- 1: enable interrupts */
  48. #define SYS_TF 0x0100         /* trap flag- 1: interrupt every instruction */
  49. #define SYS_SF 0x0080         /* sign flag- 1: result negative */
  50. #define SYS_ZF 0x0040         /* zero flag- 1: result 0 */
  51. #define SYS_AF 0x0010         /* auxiliary carry flag- 1: carry from bit 3 */
  52. #define SYS_PF 0x0004         /* parity flag- 1: even number of 1's */
  53. #define SYS_CF 0x0001         /* carry flag- 1: carry from bit 8 or 16 */
  54.   unsigned sys_sw;       /* status word */
  55. #define SYS_TS 0x0008         /* task switch */
  56. #define SYS_EM 0x0004         /* processor extension emulation */
  57. #define SYS_MP 0x0002         /* monitor processor extension */
  58. #define SYS_PE 0x0001         /* protection enable */
  59.   unsigned sys_ip;       /* instruction pointer */
  60.   unsigned sys_res;      /* unused */
  61. };
  62.  
  63. struct t_xstck
  64. {
  65.   unsigned t_xbase;      /* application stack base (overflow detection) */
  66.   unsigned t_xes;        /* es */
  67.   unsigned t_xbp;        /* bp */
  68.   unsigned t_xdi;        /* di */
  69.   unsigned t_xsi;        /* si */
  70.   unsigned t_xdx;        /* dx */
  71.   unsigned t_xcx;        /* cx */
  72.   unsigned t_xbx;        /* bx */
  73.   unsigned t_xax;        /* ax */
  74.   unsigned t_xds;        /* ds */
  75.   unsigned t_xip;        /* ip */
  76.   unsigned t_xcs;        /* cs */
  77.   unsigned t_xpf;        /* pf */
  78.   unsigned t_retip;      /* return address */
  79. };
  80.  
  81. struct t_task
  82. {
  83.   char t_type;           /* task type */
  84. #define T_X 0x80         /* execute queue */
  85. #define T_W 0x40         /* wait queue */
  86. #define T_P 0x20         /* priority queue */
  87. #define T_SW 0x10        /* secondary wait queue */
  88. #define T_ATASK 0x01     /* abreviated task */
  89.   unsigned t_wttk;       /* wait tick count */
  90.   unsigned t_cls;        /* priority queue index */
  91.   struct t_task *t_pqtsk,*t_nqtsk; /* queue linkage */
  92.   struct t_task *t_ratsk,*t_pstsk,*t_nstsk,*t_fdtsk,*t_ldtsk; /* family */
  93.   struct sys_parm t_ps;  /* processor status */
  94.   unsigned t_xtm0;       /* execution time accumulator */
  95.   unsigned t_xtm1;
  96.   unsigned t_xtm2;
  97.   pointer *t_axstk;      /* execution stack pointer */
  98. };
  99.  
  100. extern pointer *sys_task; /* current task control table pointer */
  101. #define _tsk ( ( struct t_task * ) sys_task ) /* task control table ref */
  102.  
  103. #define T_SCLS 4         /* number of scheduling classes */
  104.  
  105. struct t_scls            /* scheduling class queue */
  106. {
  107.   unsigned t_sfrq;       /* scheduling frequency */
  108.   int t_sct;             /* queue length */
  109.   struct t_task *t_fqtsk,*t_lqtsk; /* queue header */
  110. };
  111.  
  112. struct t_schd            /* scheduling control table */
  113. {
  114.   int t_xct;             /* execution queue length */
  115.   struct t_task *t_fxtsk, *t_lxtsk; /* execution queue header */
  116.   int t_wct;             /* wait queue length */
  117.   struct t_task *t_fwtsk, *t_lwtsk; /* wait queue header */
  118.   int t_swct;            /* secondary wait queue length */
  119.   struct t_task *t_fswtsk, *t_lswtsk; /* secondary wait queue header */
  120.   int t_sclsl;           /* scheduling class index limit */
  121.   struct t_scls **t_sclsp; /* scheduling class array pointer */
  122. };
  123.  
  124. extern pointer *sys_tsch; /* task scheduling control table pointer */
  125. #define _tschd ( ( struct t_schd * ) sys_tsch ) /* quick pointer */
  126.  
  127. /*
  128. t__krnl                  /* security kernel */
  129. */
  130. t__krnl()
  131. /*
  132. This is the security kernel.  It never returns, being the most trusted
  133. software in the system. The current contents in t__crtss and t__crtsp
  134. are used to set the stack for when the current task is resumed. */ 
  135.   extern logical t_astrm; /* tick termination flag */
  136.   extern selector t__crtss; /* current task ss storage */
  137.   extern pointer *t__crtsp; /* current task sp storage */
  138.   extern unsigned tmr_tkct; /* tick clock */
  139.   int xtskct;            /* task queue count (at entry) */
  140.   int ttc;               /* task termination code */
  141.   _tsk -> t_ps.sys_ss = t__crtss; /* set current task stack */
  142.   _tsk -> t_ps.sys_sp = t__crtsp;
  143.   while(_T)              /* find executable task */
  144.   {
  145.     xtskct = _tschd -> t_xct; /* save task count */
  146.     if ( t_astrm ) t__wtst( tmr_tkct ); /* process wait tasks */
  147.     if ( xtskct == 0 ) t__sch(); /* schedule application tasks if necessary */
  148.     sys_task = _tschd -> t_fxtsk; /* set next task address */
  149.     if ( sys_task != _NULL )  /* test for executable task available */
  150.     {
  151.       _tschd -> t_xct--; /* decrement executing task count */
  152.       _tschd -> t_fxtsk = _tsk -> t_nqtsk; /* delink task */
  153.       if ( _tschd -> t_fxtsk == _NULL )
  154.         _tschd -> t_lxtsk = _NULL;
  155.       else _tschd -> t_fxtsk -> t_pqtsk = _NULL;
  156.       _tsk -> t_type &= ~T_X; /* indicate task not in execution queue */
  157.       ttc = t__xtsk( sys_task ); /* execute application task */
  158.       if ( !sys_task ) continue; /* test for task terminated */
  159.       if ( ttc < 0 ) t__inxq(); /* insert task into execution queue */
  160.       else if ( ttc == 0 ) t__inpq(); /* insert task into priority queue */
  161.       else t__inwq( ttc ); /* insert into wait queue */
  162.     }
  163.   }
  164. }
  165.  
  166. /*
  167. t__wtst                  test waiting tasks
  168. */
  169. t__wtst( tc)
  170. unsigned tc;
  171. /*
  172. The wait queue is traversed.  All tasks with a wait value of tc are executed.
  173. _F is always returned. */
  174. {
  175.   while(_T)              /* traverse wait queue */
  176.   {
  177.     sys_task = _tschd -> t_fwtsk; /* set current task pointer */
  178.     if ( !sys_task ) break; /* test for no waiting tasks */
  179.     _tsk -> t_type &= ~T_W; /* remove task from wait queue */
  180.     _tsk -> t_type |= T_X; /* indicate task in execution queue */
  181.     if ( _tsk -> t_wttk > tc ) break; /* test for effective end of list */
  182.     --_tschd -> t_wct;   /* decrement waiting task  count */
  183.     _tschd -> t_fwtsk = _tsk -> t_nqtsk; /* delink from wait queue */
  184.     if ( _tsk -> t_nqtsk == _NULL )
  185.       _tschd -> t_lwtsk = _NULL;
  186.     else _tsk -> t_nqtsk -> t_pqtsk = _NULL;
  187.     _tsk -> t_pqtsk = _NULL; /* insert at top of execution queue */
  188.     _tsk -> t_nqtsk = _tschd -> t_fxtsk;
  189.     _tschd -> t_fxtsk = sys_task;
  190.     ++_tschd -> t_xct;   /* increment executable task count */
  191.     if ( _tschd -> t_lxtsk == _NULL )
  192.       _tschd -> t_lxtsk = sys_task;
  193.     else _tsk -> t_nqtsk -> t_pqtsk = sys_task;
  194.   }
  195.   return _F;             /* return */
  196. }
  197.  
  198. /*
  199. t__sch                   schedule task
  200. */
  201. t__sch()
  202. /*
  203. This function searches the priority queues and links tasks ready for execution
  204. into the execution queue. The return is always _F. */
  205. {
  206.   struct t_scls **a;     /* priority queue pointer array pointer */
  207.   struct t_scls *q;      /* priority queue pointer */
  208.   int i,j;               /* iteration variables */
  209.   a = _tschd -> t_sclsp; /* set pointer array address */
  210. /*  while(_T)              /* nonterminating task */
  211.   { */
  212.     for ( i = 0; i < _tschd -> t_sclsl; ++i ) /* traverse queues */
  213.     { 
  214.       q = a[i];          /* set priority queue pointer */
  215.       for ( j = 0; j++<q -> t_sfrq; ) /* schedule tasks from priority queue */
  216.       { 
  217.         if ( q -> t_fqtsk == _NULL ) break; /* test for queue empty */
  218.         if ( _tschd -> t_lxtsk ) /* link to end of execution queue */
  219.           _tschd -> t_lxtsk -> t_nqtsk = q -> t_fqtsk;
  220.         else _tschd -> t_fxtsk = q -> t_fqtsk;
  221.         q -> t_fqtsk -> t_type &= ~T_P; /* indicate not in priority queue */
  222.         q -> t_fqtsk -> t_pqtsk = _tschd -> t_lxtsk;
  223.         _tschd -> t_lxtsk = q -> t_fqtsk;
  224.         q -> t_fqtsk = q -> t_fqtsk -> t_nqtsk; /* update queue header */
  225.         _tschd -> t_lxtsk -> t_nqtsk = _NULL;
  226.         if ( q -> t_fqtsk == _NULL )
  227.           q -> t_lqtsk = _NULL;
  228.         else q -> t_fqtsk -> t_pqtsk = _NULL;
  229.         q -> t_sct --;   /* decrement queue count */
  230.         ++ _tschd -> t_xct; /* increment execution queue length */
  231.         _tschd -> t_lxtsk -> t_type |= T_X; /* ind. task in execution queue */
  232.       }
  233.     }
  234. /*    t_rels();            /* return to bottom of execution queue */
  235.   }*/
  236.   return _F;             /* return */
  237. }
  238.  
  239. /*
  240. t__inxq                  insert task into execution queue
  241. */
  242. t__inxq()
  243. /*
  244. The current task is inserted into the execution queue. _F is always returned.
  245. */
  246. {
  247.   _tsk -> t_wttk = 0;    /* indicate not waiting for system tick */
  248.   if ( _tschd -> t_lxtsk == _NULL ) /* test for execution queue empty */
  249.   {
  250.     _tschd -> t_fxtsk = sys_task; /* insert in empty queue */
  251.     _tsk -> t_pqtsk = _NULL;
  252.   }
  253.   else                   /* execution queue not empty */
  254.   { 
  255.     _tschd -> t_lxtsk -> t_nqtsk = sys_task; /* insert at end of queue */
  256.     _tsk -> t_pqtsk = _tschd -> t_lxtsk;
  257.   }
  258.   _tsk -> t_nqtsk = _NULL; /* new task at end of list */
  259.   _tschd -> t_lxtsk = sys_task;
  260.   _tschd -> t_xct++;     /* increment executable task count */
  261.   _tschd -> t_lxtsk -> t_type |= T_X; /* indicate task in execution queue */
  262.   return _F;             /* return */
  263. }
  264.  
  265. /*
  266. t__secw                  process secondary wait queue
  267. */
  268. t__secw()
  269. /*
  270. This program executes every 64K system ticks. It moves the secondary
  271. wait queue to the primary wait queue and changes the type of the waiting
  272. tasks. */
  273. {
  274.   struct t_task *tsk;    /* task control table pointer */
  275.   char swtflg;           /* system state flag */
  276.   while(_T)              /* nonterminating task */
  277.   { 
  278.     t__syntr( &swtflg ); /* enter system state */
  279.     for ( tsk = _tschd -> t_fwtsk; tsk; tsk = tsk -> t_nqtsk ) /* traverse */
  280.     {
  281.       tsk -> t_type &= ~T_SW;
  282.       tsk -> t_type |= T_W; /* change task type */
  283.     }
  284.     _tschd -> t_wct = _tschd -> t_swct; /* append secondary wait queue */
  285.     _tschd -> t_fwtsk = _tschd -> t_fswtsk;
  286.     _tschd -> t_lwtsk = _tschd -> t_lswtsk;
  287.     _tschd -> t_fswtsk = _tschd -> t_lswtsk = _NULL; /* empty sec. queue */
  288.     _tschd -> t_swct = 0;
  289.     t__inwq( 0xFFFF - tmr_tkct ); /* insert self into wait queue at end */
  290.     sys_task = _NULL;    /* remove task from kernel control */
  291.     t_term();            /* suspend execution */
  292.   }
  293. }
  294.  
  295. /*
  296. t__inwq                  insert task into wait queue
  297. */
  298. t__inwq(tc)
  299. unsigned tc;
  300. /*
  301. The  current task is inserted into the wait queue.  tc is the number of system
  302. ticks that the task is to wait. _F is always returned. */
  303. {
  304.   extern unsigned tmr_tkct; /* tick clock */
  305.   unsigned crtk;         /* current tick */
  306.   crtk = tmr_tkct;       /* set current system tick */
  307.   _tsk -> t_wttk = tc + crtk; /* compute reactivation time */
  308.   if ( _tsk -> t_wttk >= crtk ) /* test for task in wait queue */
  309.   { t__inwt( &_tschd -> t_wct ); /* insert in wait queue */
  310.     _tsk -> t_type |= T_W;
  311.   }else                  /* task in secondary wait queue */
  312.   { t__inwt( &_tschd -> t_swct ); /* insert in secondary wait queue */
  313.     _tsk -> t_type |= T_SW;
  314.   }return _F;            /* indicate task inserted */
  315. }
  316.  
  317. /*
  318. t__inwt                  insert into wait or secondary wait queue
  319. */
  320. struct t_wtq
  321. {
  322.   int wct;               /* wait queue length */
  323.   struct t_task *frs,*lst; /* queue header */
  324. };
  325. t__inwt( w )
  326. struct t_wtq *w;
  327. /*
  328. The t_wtq structure is implicitly contained in the scheduling control table
  329. (t_schd structure).  The current task is inserted into the queue. _F is always
  330. returned. */
  331. {
  332.   struct t_task *p;      /* task pointer */
  333.   unsigned tc;           /* reactivation time */
  334.   tc = _tsk -> t_wttk;   /* set reactivation time */
  335.   ++w -> wct;            /* increment queue length */
  336.   for ( p = w -> frs; p; p = p -> t_nqtsk ) /* traverse queue */
  337.   {
  338.     if ( tc < p -> t_wttk ) /* test for task earlier */
  339.     {
  340.       _tsk -> t_nqtsk = p; /* insert within queue */
  341.       _tsk -> t_pqtsk = p -> t_pqtsk;
  342.       p -> t_pqtsk = sys_task;
  343.       if ( ( p = _tsk -> t_pqtsk ) ) p -> t_nqtsk = sys_task;
  344.       else w -> frs = sys_task;
  345.       return _F;         /* indicate task inserted */
  346.     }
  347.   }
  348.   if ( ( p = w -> lst ) ) /* test for wait queue not empty */
  349.   {
  350.     p -> t_nqtsk = w -> lst = sys_task; /* insert at end of queue */
  351.     _tsk -> t_pqtsk = p;
  352.     _tsk -> t_nqtsk = _NULL;
  353.   }
  354.   else                   /* wait queue empty */
  355.   {
  356.     w -> frs = w -> lst = sys_task; /* initialize wait queue */
  357.     _tsk -> t_nqtsk = _tsk -> t_pqtsk = _NULL;
  358.   }
  359.   return _F;             /* indicate task inserted */
  360. }
  361.  
  362. /*
  363. t__inpq                  insert into priority queue
  364. */
  365. t__inpq()
  366. /*
  367. The current task is inserted into its priority queue. _F is always returned.
  368. */
  369.   struct t_scls *q;      /* priority queue pointer */
  370.   _tsk -> t_wttk = 0;    /* indicate not waiting for tick */
  371.   q = _tschd -> t_sclsp[ _tsk -> t_cls ]; /* set priority queue address */
  372.   _tsk -> t_pqtsk = q -> t_lqtsk; /* link task into priority queue */
  373.   _tsk -> t_nqtsk = _NULL;
  374.   if ( q -> t_lqtsk == _NULL ) q -> t_fqtsk = sys_task;
  375.   else q -> t_lqtsk -> t_nqtsk = sys_task;
  376.   q -> t_lqtsk = sys_task;
  377.   ++q -> t_sct;          /* increment queue length */
  378.   _tsk -> t_type |= T_P; /* indicate task in priority queue */
  379.   return _F;             /* return */
  380. }
  381.  
  382. /*
  383. t__xtsk                  execute task
  384. */
  385. t__xtsk( t )
  386. struct t_task *t;
  387. /*
  388. Task t is executed. The returned value is the termination code. 
  389. */
  390. {
  391.   extern unsigned t_mnxtm; /* minimum execution time */
  392.   extern unsigned t_syxtm[]; /* system pseudo time accumulator */
  393.   extern logical t_astrm; /* application termination flag */
  394.   int ttc;               /* return value storage */
  395.   unsigned atm;          /* accumulated time */
  396.   unsigned rtm;          /* reference time */
  397.   int xtm;               /* execution time */
  398.   atm = 0;               /* initialize accumulated execution time */
  399.   while(_T)              /* execute task */
  400.   { 
  401.     rtm = t -> t_xtm0;   /* set reference time */
  402.     t_rtmark( &t -> t_xtm0 ); /* accumulate pseudo time */
  403.     ttc = t__dspap( t -> t_ps.sys_ss, t -> t_ps.sys_sp ); /* execute task */
  404.     t -> t_ps.sys_ss = t__crtss; /* store ss */
  405.     t -> t_ps.sys_sp = t__crtsp; /* store sp */
  406.     t_rtmark( &t_syxtm ); /* accumulate pseudo time */
  407.     if ( ( ttc != 0 ) || !t_astrm ) break; /* test for not tick termination */
  408.     xtm = t -> t_xtm0 - rtm; /* compute execution time */
  409.     if ( xtm < rtm ) xtm = -xtm;
  410.     atm += xtm;          /* accumulate execution time */
  411.     if ( atm >= t_mnxtm ) break; /* test for minimum time satisfied */
  412.   }
  413.   return ttc;            /* return */
  414. }
  415. /*
  416. t__init                  initialize task system
  417. */
  418. t__init()
  419. /*
  420. This function initializes the task system. _F is the normal return. _E is
  421. returned if the system cannot be initialized. */ 
  422. #define WSTK 252         /* t_wqupd stack size */
  423.   extern struct sys_parm sys_stat; /* initial processor status */
  424.   extern struct t_task *t_wqupd; /* secondary wait queue update task */
  425.   extern selector sys_dgrp; /* data segment selector storage */
  426.   extern char *sys_ssbs; /* system stack pointer */
  427.   extern unsigned sys_sssz; /* system stack length */
  428.   extern char tmr_ilck;  /* tick service interlock */
  429.   int t__secw();         /* wait queue update function */
  430.   struct t_scls *cls;    /* priority queue pointer */
  431.   struct t_scls **ary;   /* priority queue pointer array pointer */
  432.   int i;                 /* iteration variable */
  433.   char *s;               /* pointer */
  434.   tmr__int();            /* initialize system tick clock */
  435.   sys_task = sys_ssbs + sys_sssz; /* set main task control table pointer */
  436.   _tsk -> t_xtm0 =       /* initialize execution time */
  437.   _tsk -> t_xtm1 = 
  438.   _tsk -> t_xtm2 = 0;
  439.   if( ( sys_tsch = mm_aloc( sizeof( struct t_schd ) ) ) == _NULL )goto err1;
  440.   if( ( ary = mm_aloc( T_SCLS*( sizeof( struct t_scls )+2 ) ) )
  441.      == _NULL )goto err2;
  442.   _tsk -> t_pqtsk =      /* NULL linkage */
  443.   _tsk -> t_nqtsk =
  444.   _tsk -> t_ratsk =
  445.   _tsk -> t_pstsk =
  446.   _tsk -> t_nstsk =
  447.   _tsk -> t_fdtsk =
  448.   _tsk -> t_ldtsk = _NULL;
  449.   _tsk -> t_cls = 0;     /* set priority class 0 */
  450.   _tsk -> t_wttk = 0;    /* indicate not waiting */
  451.   for( i = 0, s = &_tsk -> t_ps;
  452.     i++<sizeof( struct sys_parm ); )*s = 0; /* clear t_ps */
  453.   _tsk -> t_ps.sys_cs = sys_stat.sys_cs; /* set selectors */
  454.   _tsk -> t_ps.sys_ds =
  455.   _tsk -> t_ps.sys_es =
  456.   _tsk -> t_ps.sys_ss = sys_dgrp;
  457.   _tsk -> t_axstk = _NULL; /* NULL execution stack pointer */
  458.   _tschd -> t_xct = 1;   /* set execution task count */
  459.   _tschd -> t_fxtsk =    /* set execution queue */
  460.   _tschd -> t_lxtsk = sys_task;
  461.   _tschd -> t_wct = 0;   /* indicate idle wait queue */
  462.   _tschd -> t_fwtsk =    /* set wait queue */
  463.   _tschd -> t_lwtsk = _NULL;
  464.   _tschd -> t_swct = 0;  /* indicate empty secondary wait queue */
  465.   _tschd -> t_fswtsk =   /* NULL secondary wait queue */
  466.   _tschd -> t_lswtsk = _NULL;
  467.   _tschd -> t_sclsl = T_SCLS; /* set priority queue count */
  468.   _tschd -> t_sclsp = ary; /* set priority queue pointer array address */
  469.   cls = &ary[ T_SCLS ];  /* set first t_scls pointer */
  470.   for( i = 0; i<T_SCLS; ++i, ++cls ) /* initialize priority queues */
  471.   {
  472.     ary[i] = cls;        /* set priority queue pointer */
  473.     cls -> t_sfrq = 1;   /* set default frequency */
  474.     cls -> t_sct = 0;    /* indicate empty queue */
  475.     cls -> t_fqtsk =     /* NULL queue linkage */
  476.     cls -> t_lqtsk = _NULL;
  477.   }
  478.   t_wqupd =              /* create task to update wait queue */
  479.     t_crt( t__secw, 0, 0, WSTK, 0, 0, 0 );
  480.   if( t_wqupd == _NULL )goto err3;
  481.   t_wqupd -> t_wttk = 0xFFFF; /* update wait queue at wraparound time */
  482.   t__dspsy();            /* dispatch system */
  483.   tmr_ilck = 0x00;       /* enable tick service */
  484.   return _F;             /* indicate task system initialized */
  485. err3: mm_free( ary );    /* error nest */
  486. err2: mm_free( sys_tsch );
  487. err1: return _E;
  488. }
  489.  
  490. /*
  491. t__term
  492. */
  493. t__term()
  494. /*
  495. The task system is terminated. All tasks and storage allocated by t__init are
  496. released. The return is always _F. */
  497. {
  498.   extern char *sys_ssbs; /* system stack base */
  499.   extern unsigned sys_sssz; /* system stack size */
  500.   struct t_task *t;      /* t_task pointer */
  501.   char trmflg;           /* system state flag storage */
  502.   tmr__rst();            /* reset system tick clock */
  503.   t__syntr( &trmflg );   /* enter system state */
  504.   sys_task = sys_ssbs + sys_sssz; /* set original task address */
  505.   while( ( t = _tsk -> t_fdtsk ) ) /* delete all created tasks */
  506.     t_del( t, _F );
  507.   mm_free( _tschd -> t_sclsp );
  508.   mm_free( sys_tsch );
  509.   return _F;             /* normal return */
  510. }
  511.  
  512. /*
  513. t_crt                    create task
  514. */
  515. t_crt( xadr, pcnt, padr, ssiz, dsiz, sadr, prty )
  516. pointer *xadr;
  517. unsigned pcnt;
  518. unsigned *padr;
  519. unsigned ssiz, dsiz;
  520. pointer *sadr;
  521. unsigned prty;
  522. /*
  523. A  new task is created with execution priority prty.  Execution will begin  at 
  524. xadr.  pcnt parameters will be passed (on the new task stack).  The parameters 
  525. are  in  an array addressed by padr.  The new task will have a stack  of  ssiz 
  526. bytes  and a dynamic memory area of dsiz bytes.  dsiz may be zero to  indicate 
  527. that no dynamic memory is required.  sadr will recieve a termination code when 
  528. the  task  terminates. If sadr is _NULL, an abreviated task is created. _F  is 
  529. returned if insufficient memory  is  available.  Otherwise the address of the 
  530. t_ftask table is returned. */
  531. {
  532.   extern int t__halt();  /* return address */
  533.   struct t_task *tsk;    /* task control table pointer (t_task) */
  534.   struct t_scls *pq;     /* priority queue pointer */
  535.   struct t_xstck *sp;    /* execution stack pointer */
  536.   pointer *ss;           /* stack start */
  537.   unsigned *pr;          /* parameter pointer */
  538.   unsigned ln;           /* task control table length */
  539.   int i;                 /* iteration variable */
  540.   char *s;               /* pointer */
  541.   char *sptr;            /* execution stack pointer */
  542.   logical crtflg;        /* system state flag storage */
  543.   t__syntr( &crtflg );   /* enter system state */
  544.   ln = sizeof( struct t_task );  /* allocate task control table */
  545.   if( ( tsk = mm_aloc( ln ) ) == _NULL ) goto err1;
  546.   ssiz += sizeof( struct t_xstck ); /* allocate stack */
  547.   if( ( ss = tsk -> t_axstk = mm_aloc( ssiz ) ) == _NULL )goto err2;
  548.   tsk -> t_type = T_ATASK; /* indicate abreviated task control table */
  549.   tsk -> t_wttk = 0;     /* indicate not waiting */
  550.   tsk -> t_ratsk = sys_task; /* task family linkage */
  551.   tsk -> t_pstsk = _tsk -> t_ldtsk;
  552.   tsk -> t_nstsk =
  553.   tsk -> t_fdtsk =
  554.   tsk -> t_ldtsk = _NULL;
  555.   _tsk -> t_ldtsk = tsk;
  556.   if( tsk -> t_pstsk == _NULL )_tsk -> t_fdtsk = tsk;
  557.   else tsk -> t_pstsk -> t_nstsk = tsk;
  558.   if( prty > _tschd -> t_sclsl ) /* adjust priority */
  559.     prty = _tschd -> t_sclsl-1;
  560.   tsk -> t_cls = prty;   /* set priority */
  561.   pq = _tschd -> t_sclsp[ prty ]; /* set scheduling array pointer */
  562.   ++pq -> t_sct;         /* scheduling linkage */
  563.   tsk -> t_pqtsk = pq -> t_lqtsk;
  564.   tsk -> t_nqtsk = _NULL;
  565.   if( tsk -> t_pqtsk == _NULL )pq -> t_fqtsk = tsk;
  566.   else tsk -> t_pqtsk -> t_nqtsk = tsk;
  567.   pq -> t_lqtsk = tsk;
  568.   tsk -> t_xtm0 =        /* no execution time yet */
  569.   tsk -> t_xtm1 =
  570.   tsk -> t_xtm2 = 0;
  571.   pr = sptr = ss+ssiz-2*pcnt; /* initialize execution stack & t_ps */
  572.   tsk -> t_ps.sys_sp =
  573.   sp = sptr - sizeof( struct t_xstck );
  574.   sp -> t_xbp = ss + ssiz;
  575.   sp -> t_xbase = ss;
  576.   while( pcnt-- )*pr++ = *padr++;
  577.   for( i = 0, s = &tsk -> t_ps; i++ < sizeof( struct sys_parm ); )*s = 0;
  578.   tsk -> t_ps.sys_ds =
  579.   tsk -> t_ps.sys_es =
  580.   tsk -> t_ps.sys_ss =
  581.   sp -> t_xds =
  582.   sp -> t_xes =  _tsk -> t_ps.sys_ds;
  583.   sp -> t_xdi =
  584.   sp -> t_xsi =
  585.   sp -> t_xdx =
  586.   sp -> t_xcx =
  587.   sp -> t_xbx =
  588.   sp -> t_xax = _NULL;
  589.   sp -> t_xip = xadr;
  590.   tsk -> t_ps.sys_cs =
  591.   sp -> t_xcs =
  592.   _tsk -> t_ps.sys_cs;
  593.   tsk -> t_ps.sys_pf =
  594.   sp -> t_xpf = SYS_IF;
  595.   tsk -> t_ps.sys_ip =
  596.   sp -> t_retip = &t__halt;
  597.   t__syxit( &crtflg );   /* exit system state */
  598.   return tsk;            /* return */
  599. err3: mm_free( tsk -> t_ps.sys_ss );
  600. err2: mm_free( tsk );
  601. err1: t__syxit( &crtflg );
  602.   return _NULL;
  603. }
  604.  
  605. /*
  606. t__halt                  terminate task
  607. */
  608. t__halt()
  609. /*
  610. If  a subtask returns into its orginal stack,  control will pass  to  t__halt. 
  611. This  function  deletes the subtask and then clears the sys_task pointer  just 
  612. before returning on the system stack (to reenter the security kernel). */
  613. {
  614.   logical haltflg;       /* system state flag storage */
  615.   t__syntr( &haltflg );  /* enter system state */
  616.   t_rtmark( &_tsk -> t_ratsk -> t_xtm0 ); /* accumulate pseudo time */
  617.   t_del( sys_task, _F ); /* delete current task */
  618.   sys_task = _NULL;      /* indicate task terminated */
  619.   while(_T)t_term();     /* return to security kernel */
  620. }
  621.  
  622. /*
  623. t_del                    delete task
  624. */
  625. t_del( tsk, st )
  626. struct t_task *tsk;
  627. int st;
  628. /*
  629. Task tsk is killed. st is the status returned to the calling program.
  630. */
  631. {
  632. #define tskf ( ( struct t_ftask * )tsk ) /** (t_ftask) */
  633.   struct t_task *t;      /* task control table pointer */
  634.   logical delflg;        /* system state flag storage */
  635.   t__syntr( &delflg );   /* enter system state */
  636.   while( ( t = tsk -> t_fdtsk ) )t_del( t, st ); /* delete subtasks first */
  637.   if( tsk -> t_pstsk )   /* family linkage */
  638.     tsk -> t_pstsk -> t_nstsk = tsk -> t_nstsk;
  639.   else tsk -> t_ratsk -> t_ldtsk = tsk -> t_nstsk;
  640.   if( tsk -> t_nstsk )
  641.     tsk -> t_nstsk -> t_pstsk = tsk -> t_pstsk;
  642.   else tsk -> t_ratsk -> t_fdtsk = tsk -> t_pstsk;
  643.   if( tsk -> t_pqtsk )   /* queue linkage */
  644.     tsk -> t_pqtsk -> t_nqtsk = tsk -> t_nqtsk;
  645.   else if( ( tsk -> t_type&T_P )
  646.        && ( _tschd -> t_sclsp[ tsk -> t_cls ] -> t_fqtsk == tsk ) )
  647.          _tschd -> t_sclsp[ tsk -> t_cls ] -> t_fqtsk = tsk -> t_nqtsk;
  648.   else if( ( tsk -> t_type&T_W ) && ( _tschd -> t_fwtsk == tsk ) )
  649.     _tschd -> t_fwtsk = tsk -> t_nqtsk;
  650.   else if( ( tsk -> t_type&T_SW ) && ( _tschd -> t_fswtsk == tsk ) )
  651.     _tschd -> t_fswtsk = tsk -> t_nqtsk;
  652.   else if( ( tsk -> t_type&T_X ) && ( _tschd -> t_fxtsk == tsk ) )
  653.     _tschd -> t_fxtsk = tsk -> t_nqtsk;
  654.   if( tsk -> t_nqtsk )tsk -> t_nqtsk -> t_pqtsk = tsk -> t_pqtsk;
  655.   else if( ( tsk -> t_type&T_P )
  656.        && ( _tschd -> t_sclsp[ tsk -> t_cls ] -> t_lqtsk == tsk ) )
  657.          _tschd -> t_sclsp[tsk -> t_cls] -> t_lqtsk = tsk -> t_pqtsk;
  658.   else if( ( tsk -> t_type&T_W ) && ( _tschd -> t_fwtsk == tsk ) )
  659.     _tschd -> t_lwtsk = tsk -> t_pqtsk;
  660.   else if( ( tsk -> t_type&T_SW ) && ( _tschd -> t_fswtsk == tsk ) )
  661.     _tschd -> t_lswtsk = tsk -> t_pqtsk;
  662.   else if( ( tsk -> t_type&T_X ) && ( _tschd -> t_fxtsk == tsk ) )
  663.    _tschd -> t_lxtsk = tsk -> t_pqtsk;
  664.   t = sys_task;          /* save current t_task pointer */
  665.   sys_task = tsk -> t_ratsk; /* set ancestor task */
  666.   mm_free( tsk -> t_ps.sys_ss ); /* free stack */
  667.   mm_free( tsk );        /* free t_task table */
  668.   sys_task = t;          /* restore current task pointer */
  669.   t__syxit( &delflg );   /* exit system state */
  670.   return _F;             /* return */
  671. }
  672.  
  673. /*
  674. mm_aloc                  memory allocation
  675. */
  676. mm_aloc(ln)
  677. unsigned ln;
  678. /*
  679. ln bytes are allocated from the heap. The address of the first byte is
  680. returned. If there is not enough available memory to satisfy the request,
  681. _NULL is returned. */
  682. {
  683.   return malloc(ln);     /* allocate storage */
  684. }
  685.  
  686. /*
  687. mm_free                  memory deallocation
  688. */
  689. mm_free(st)
  690. char *st;
  691. /*
  692. st is the address returned by a previous call to function mm_free. The storage
  693. previously allocated is made available for future use. The normal return is
  694. _F. _E is returned if st does not point to an area previously allocated by
  695. mm_aloc. */
  696. {
  697.   return free(st);       /* deallocate storage */
  698.  
  699. /*
  700. main                     test program
  701. */
  702. main()
  703. /*
  704. This function serves to test the task scheduler. Two tasks are created, each
  705. of which increments a variable. The original task continually displays the
  706. counts, as well as its own iteration number. Depressing any key will cause a
  707. return to MS-DOS. */
  708. {
  709.   int ctr1, ctr2, ctr3;  /* counters */
  710.   int count();           /* counting subroutine */
  711.   int param[ 2 ];        /* parameter array */
  712.   printf("tasktest (C) 1986 Ken Berry- All Rights Reserved\n");
  713.   printf("Tele task scheduler: 1986 September 2 version (DDJ mod)\n\n");
  714.   t__init();             /* initialize task scheduler */
  715.   ctr1 = ctr2 = ctr3 = 0; /* initialize counters */
  716.   param[ 0 ] = &ctr1;    /* create first task */
  717.   param[ 1 ] = 1;
  718.   t_crt( count, 2, ¶m, 256, 0, 0, 0);
  719.   param[ 0 ] = &ctr2;    /* create second task */
  720.   param[ 1 ] = 2;
  721.   t_crt( count, 2, ¶m, 256, 0, 0, 0);
  722.   while( !kbhit() )      /* loop until key depressed */
  723.   {
  724.     ++ctr3;              /* increment main loop count */
  725.     printf("main = %d, task 1 = %d, task 2 = %d\n", ctr3, ctr1, ctr2 );
  726.   }
  727.   getch();               /* discard termination character */
  728.   t__term();             /* terminate task scheduler */
  729.   return _F;             /* return to MS÷DOS */
  730. }
  731.  
  732. count(ctr,inc)
  733. int *ctr,inc;
  734. {
  735.   while(_T)              /* infinite loop */
  736.   {
  737.     *ctr += inc;         /* update counter */
  738.   }
  739. }
  740.  
  741.  
  742.  
  743. Listing 2-     System Definitions
  744. (C) Copyright 1986 Ken Berry.
  745. All rights reserved.
  746. Copies may be made for non-commercial, private use only.
  747.  
  748.  
  749. sys_parm  struc          ;; register storage block
  750. rax       dw ?           ;; ax (general register A)
  751. rbx       dw ?           ;; bx (general register B)
  752. rcx       dw ?           ;; cx (general register C)
  753. rdx       dw ?           ;; dx (general register D)
  754. rbp       dw ?           ;; bp (base pointer)
  755. rsi       dw ?           ;; si (source index)
  756. rdi       dw ?           ;; di (destination index)
  757. rsp       dw ?           ;; sp (stack pointer)
  758. rcs       dw ?           ;; cs (code segment)
  759. rds       dw ?           ;; ds (data segment)
  760. rss       dw ?           ;; ss (stack segment)
  761. res       dw ?           ;; es (extra segment)
  762. rpf       dw ?           ;; pf (processor flags)
  763. rsw       dw ?           ;; sw (status word)
  764. rip       dw ?           ;; ip (instruction pointer)
  765. rres      dw ?           ;; unused
  766. sys_parm  ends
  767.  
  768. t_task    struc          ;; task control table
  769. t_type    db ?           ;; task type
  770. t_wttk    dw ?           ;; wait tick count
  771. t_cls     dw ?           ;; priority queue index
  772. t_pqtsk   dw ?           ;; prior t_task pointer
  773. t_nqtsk   dw ?           ;; next t_task pointer
  774. t_ratsk   dw ?           ;; ancestor t_task pointer
  775. t_pstsk   dw ?           ;; prior sibling t_task pointer
  776. t_nstsk   dw ?           ;; next sibling t_task pointer
  777. t_fdtsk   dw ?           ;; first desendant t_task pointer
  778. t_ldtsk   dw ?           ;; last desendant t_task pointer
  779. t_ps      db type sys_parm dup (?) ;; processor status
  780. t_xtm0    dw ?           ;; *  execution time accumulator
  781. t_xtm1    dw ?           ;; *
  782. t_xtm2    dw ?           ;; *
  783. t_axstk   dw ?           ;; application stack pointer
  784. t_task    ends
  785.  
  786. T_ATSK    equ 01h        ;; abreviated task
  787. T_X       equ 80h        ;; execute wueue
  788. T_W       equ 40h        ;; wait queue
  789. T_P       equ 20h        ;; priority queue
  790. t_SW      equ 10h        ;; secondary wait queue
  791.  
  792. t_scls    struc          ;; scheduling class queue
  793. t_sfrq    dw ?           ;; scheduling frequency
  794. t_sct     dw ?           ;; queue length
  795. t_fqtsk   dw ?           ;; first task in queue
  796. t_lqtsk   dw ?           ;; last task in queue
  797. t_scls    ends
  798.  
  799. t_schd    struc          ;; scheduling control table
  800. t_xct     dw ?           ;; execution queue length
  801. t_fxtsk   dw ?           ;; first task in execution queue
  802. t_lxtsk   dw ?           ;; last task in execution queue
  803. t_wct     dw ?           ;; wait queue length
  804. t_fwtsk   dw ?           ;; first task in wait queue
  805. t_lwtsk   dw ?           ;; last task in wait queue
  806. t_swct    dw ?           ;; secondary wait queue length
  807. t_fswtsk  dw ?           ;; first task in secondary wait queue
  808. t_lswtsk  dw ?           ;; last task in secondary wait queue
  809. t_sclsl   dw ?           ;; scheduling class index limit
  810. t_sclsp   dw ?           ;; scheduling class array pointer
  811. t_schd    ends
  812.  
  813. t_calln   struc          ;; near function call
  814. t_nbp     dw ?           ;; base pointer storage
  815. t_nret    dw ?           ;; return address
  816. t_np0     dw ?           ;; parameter 0
  817. t_np1     dw ?           ;; parameter 1
  818. t_np2     dw ?           ;; parameter 2
  819. t_np3     dw ?           ;; parameter 3
  820. t_np4     dw ?           ;; parameter 4
  821. t_np5     dw ?           ;; parameter 5
  822. t_np6     dw ?           ;; parameter 6
  823. t_np7     dw ?           ;; parameter 7
  824. t_calln   ends
  825.  
  826. t_xtsk    struc          ;; execution stack
  827. t_xbase   dw ?           ;; _base (for stack overflow detection)
  828. t_xes     dw ?           ;; es
  829. t_xbp     dw ?           ;; bp
  830. t_xdi     dw ?           ;; di
  831. t_xsi     dw ?           ;; si
  832. t_xdx     dw ?           ;; dx
  833. t_xcx     dw ?           ;; cx
  834. t_xbx     dw ?           ;; bx
  835. t_xax     dw ?           ;; ax
  836. t_xds     dw ?           ;; ds
  837. t_xip     dw ?           ;; ip
  838. t_xcs     dw ?           ;; cs
  839. t_xpf     dw ?           ;; pf
  840. t_retip   dw ?           ;; return ip
  841. t_xtsk    ends
  842.  
  843. retn      macro s        ;; near return 
  844.   ifnb <s>
  845.           db 0C2h        ;; pop ip & adjust sp
  846.           db high s      ;; *  adjustment value
  847.           db low s       ;; *
  848.   else
  849.           db 0C3h        ;; pop ip only
  850.   endif
  851.           endm
  852.  
  853. retf      macro s        ;; far return
  854.   ifnb <s>
  855.           db 0CCh        ;; pop ip, cs & adjust sp
  856.           db high s      ;; *  adjustment value
  857.           db low s       ;; *
  858.   else
  859.           db 0CBh        ;; pop ip, cs only
  860.   endif
  861.           endm
  862.  
  863. ilck      macro reg,flag
  864.           xchg reg,flag  ;; capture token
  865.           endm
  866.  
  867. iowait    macro
  868.           nop            ;; I/O delay
  869.           endm
  870.  
  871. sys_entr  macro flag     ;; enter system function
  872.   ifndef sys_ilck
  873.           extrn sys_ilck:byte
  874.   endif
  875.           mov al,0FFh    ;; ** system task interlock
  876.           ilck al,sys_ilck ;; **
  877.           mov flag,al    ;; save asynchronous status
  878.           endm
  879.  
  880. sys_exit  macro flag     ;; exit from system function
  881.           local exit1,exit2
  882.   ifndef sys_ilck
  883.           extrn sys_ilck:byte
  884.   endif
  885.   ifndef t_astrm
  886.           extrn t_astrm:byte
  887.   endif
  888.   ifndef t_term
  889.           extrn t_term:near
  890.   endif
  891.           test byte ptr t_astrm,0FFh ;; *  test for application terminated
  892.           jnz exit1      ;; *
  893.           mov byte ptr sys_ilck,0 ;; exit system state
  894.           jmp short exit2 ;; continue application task
  895. exit1:    test flag,0FFH ;; ** test for more stacked system tasks
  896.           jnz exit2      ;; **
  897.           call t_term    ;; terminate application task
  898. exit2:                   ;; macro exit
  899.           endm
  900.  
  901. sys_sync  macro flag     ;; synchronize system resource
  902.   ifndef t_sync
  903.           extrn t_sync:near
  904.   endif
  905.           lea bx,flag    ;; set flag offset
  906.           call t_sync    ;; suspend task until token obtained
  907.           endm
  908.  
  909. sys_sstk  macro          ;; conditionally establish system stack
  910.           local sstk1
  911.   ifndef t__sstk
  912.           extrn t__sstk:near
  913.   endif
  914.           or al,al       ;; *  test for system task interrupted
  915.           jnz sstk1      ;; *
  916.           call t__sstk   ;; establish system stack
  917. sstk1:    push ds        ;; ** set es = ds
  918.           pop es         ;; **
  919.           endm
  920.  
  921. sys_sctx  macro          ;; save processor context
  922.           push bx        ;; protect bx
  923.           push cx        ;; protect cx
  924.           push dx        ;; protect dx
  925.           push si        ;; protect si
  926.           push di        ;; protect di
  927.           push bp        ;; protect bp
  928.           push es        ;; protect es
  929.           cld            ;; clear direction flag
  930.           sys_sstk       ;; conditionally establish system stack
  931.           endm
  932.  
  933. sys__rctx macro          ;; restore processor context (except ds)
  934.           pop es         ;; restore es
  935.           pop bp         ;; restore bp
  936.           pop di         ;; restore di
  937.           pop si         ;; restore si
  938.           pop dx         ;; restore dx
  939.           pop cx         ;; restore cx
  940.           pop bx         ;; restore bx
  941.           pop ax         ;; restore ax
  942.           endm
  943.  
  944. sys_rctx  macro          ;; restore processor context
  945.           sys__rctx      ;; restore context (except ds)
  946.           pop ds         ;; restore ds
  947.           endm
  948.  
  949. sys_ient  macro flag
  950.           push ds        ;; protect ds
  951.           push ax        ;; protect ax
  952.           mov ax,dgroup  ;; *  establish data addressability
  953.           mov ds,ax      ;; *
  954.           sys_entr flag  ;; enter system state
  955.           sti            ;; interrupts on
  956.           sys_sctx       ;; save processor context
  957.           endm
  958.  
  959. sys_iret  macro flag
  960.           local iret1
  961.   ifndef t_astrm
  962.           extrn t_astrm:byte
  963.   endif
  964.           cli            ;; interrupts off
  965.           test byte ptr t_astrm,0FFh ;; *  test for application not terminated
  966.           jz iret1       ;; *
  967.           test flag,0FFh ;; ** test for system state interrupted
  968.           jnz iret1      ;; **
  969.           sti            ;; interrupts on
  970.           retn           ;; return to task management
  971. iret1:    sys_rctx       ;; restore processor context
  972.           iret           ;; resume interrupted task
  973.           endm
  974.  
  975. dseg      macro
  976. dgroup    group data
  977. data      segment word public 'data'
  978.           assume ds:dgroup,es:dgroup,ss:dgroup
  979.           endm
  980.  
  981. endds     macro
  982. data      ends
  983.           endm
  984.  
  985. pseg      macro
  986. pgroup    group prog
  987. prog      segment byte public 'prog'
  988.           assume cs:pgroup
  989.           endm
  990.  
  991. endps     macro
  992. prog      ends
  993.           endm
  994.  
  995.  
  996.  
  997. Listing 3      Scheduling Algorithm (Assembly Subroutines)
  998. (C) Copyright 1986 Ken Berry.
  999. All rights reserved.
  1000. Copies may be made for non-commercial, private use only.
  1001.  
  1002.  
  1003.           include tele.mac ; system definitions (listing 2)
  1004.  
  1005.           extrn t_astrm:byte ; application task termination flag
  1006.           extrn t_rtmark:near ; update pseudo time accumulator
  1007.           extrn t__krnl:near ; security kernel
  1008.  
  1009.           public sys_task ; current task pointer
  1010.           public sys_tsch ; task scheduling table pointer
  1011.           public sys_ilck ; system task interlock
  1012.           public sys_asbs ; application stack base
  1013.           public sys_dgrp ; data segment storage
  1014.           public sys_ssbs ; system stack base
  1015.           public sys_sssz ; system stack size
  1016.           public sys_sstp ; system stack top
  1017.           public sys_stat ; original register block
  1018.           public t_mnxtm ; minimum execution time
  1019.           public t_rels  ; release
  1020.           public t_spnd  ; suspend
  1021.           public t_syxtm ; system pseudo time accumulator
  1022.           public t_term  ; reschedule
  1023.           public t_wait  ; wait
  1024.           public t_wqupd ; wait queue update task pointer
  1025.           public t__crtss ; current task ss storage
  1026.           public t__crtsp ; current task sp storage
  1027.           public t__dspap ; dispatch application
  1028.           public t__dspsy ; dispatch system
  1029.           public t__sstk ; establish system stack
  1030.           public t__syntr ; enter system state
  1031.           public t__syxit ; exit system state
  1032.  
  1033. MINXTM    equ 500        ; minimum execution time
  1034. STKLN     equ 1024       ; system stack size
  1035.  
  1036.           dseg
  1037.  
  1038. tmrdx     dw 0           ; dx storage
  1039. spdss     dw 0           ; ss storage
  1040. spdsp     dw 0           ; sp storage
  1041.  
  1042. t__crtss  dw 0           ; current task ss storage
  1043. t__crtsp  dw 0           ; current task sp storage
  1044.  
  1045. sys_stat  db type sys_parm dup (0) ; original register block
  1046. sys_dgrp  dw 0           ; data segment storage
  1047. sys_task  dw 0           ; current task pointer
  1048. sys_tsch  dw 0           ; task scheduling table pointer
  1049. sys_asbs  dw 0           ; application stack base
  1050. sys_ssbs  dw stkbs       ; system stack base
  1051. sys_sssz  dw STKLN       ; system stack length
  1052. sys_sstp  dw STKLN       ; system stack top
  1053. sys_ilck  db 0FFh        ; system task interlock
  1054.  
  1055. t_wqupd   dw 0           ; wait queue update task pointer
  1056.  
  1057. t_syxtm   dw 3 dup (0)   ; system pseudo time accumulator
  1058.  
  1059. t_mnxtm   dw MINXTM      ; minimum execution time
  1060.  
  1061. stkbs     db STKLN dup (0) ; system stack
  1062.           db type t_task dup (0) ; main task control table
  1063.  
  1064.           endds
  1065.  
  1066.           pseg
  1067.  
  1068. comment ~
  1069.  
  1070. t__dspap(ss,sp)
  1071. selector ss;
  1072. unsigned sp;
  1073.  
  1074. ss  and  sp are placed in the stack registers.  Then the other  registers  are 
  1075. restored from the new stack.  Control passes to the restored task.  The return 
  1076. address  is left at the top of the system stack.  Therefore the restored  task 
  1077. may use the system stack to return to the caller of t__dspap. ax may contain a 
  1078. return code in this case.
  1079. ~
  1080.  
  1081. t__dspap  proc near
  1082.           push bp        ; protect bp
  1083.           mov bp,sp      ; establish parameter addressability
  1084.           mov ax,[bp].t_np0 ; set application stack
  1085.           mov bx,[bp].t_np1
  1086.           mov sys_sstp,sp ; store current top of system stack
  1087.           cli
  1088.           mov ss,ax
  1089.           mov sp,bx
  1090.           mov bp,sp      ; enable interrupts
  1091.           or [bp].t_xpf,0200h
  1092.           pop sys_asbs
  1093.           sti
  1094.           sys__rctx      ; restore context
  1095.           cli            ; interrupts off
  1096.           mov byte ptr sys_ilck,0 ; exit system state
  1097.           mov byte ptr t_astrm,0 ; initialize application interval
  1098.           pop ds         ; restore ds
  1099.           iret           ; execute task
  1100. t__dspap  endp
  1101.  
  1102. comment ~
  1103.  
  1104. t_term()       _F
  1105. t_spnd(tp)     tp
  1106. t_wait(tp)     tp
  1107. unsigned tp;
  1108. t_rels()       _E
  1109.  
  1110. All of these functions are similar.  The processor registers are stored on
  1111. the stack,  which  is  then  adjusted  to  match the pattern for interrupt
  1112. returns. Finally the system stack is established.  The  functions  differ  in
  1113. the  code returned  to  the caller of function t__dspap.  t__dspap restores
  1114. the registers and returns control to the caller of these functions.  The
  1115. returned  value  is shown with the appropriate call above.  tp is only used
  1116. with t_spnd and t_wait.  It is the number of system ticks to  wait  before
  1117. executing  the  task  again.  t_wait functions like t_spnd, except that t_rels
  1118. is invoked immediately.  ~
  1119.  
  1120. t_term    proc near
  1121.           call t__trmap  ; protect registers
  1122.           xor ax,ax      ; return _F
  1123.           ret
  1124. t_term    endp
  1125.  
  1126. t_spnd    proc near
  1127.           mov spdss,ss   ; store stack pointers
  1128.           mov spdsp,sp
  1129.           call t__trmap  ; protect registers
  1130.           mov es,spdss   ; return tick count
  1131.           mov si,spdsp
  1132.           mov ax,word ptr es:[si+2]
  1133.           push ds        ; set es = ds
  1134.           pop es
  1135.           ret            ; return
  1136. t_spnd    endp
  1137.  
  1138. t_wait    proc near
  1139.           push bp        ; protect bp
  1140.           mov bp,sp      ; establish stack addressability
  1141.           mov ax,[bp].t_np0 ; suspend task
  1142.           push ax
  1143.           call t_spnd
  1144.           mov sp,bp      ; unload stack
  1145.           pop bp         ; restore bp
  1146. t_rels    proc near
  1147.           call t__trmap  ; protect registers
  1148.           xor ax,ax      ; return _E
  1149.           dec ax
  1150.           ret
  1151. t_rels    endp
  1152. t_wait    endp
  1153.  
  1154. comment ~
  1155.  
  1156. t__dspsy()
  1157.  
  1158. A call to function t__trmap is made so that after the registers are stored in
  1159. the  application stack (and the system stack is made current),  control passes
  1160. to  function t__krnl,  the system security kernel.  Control will  return  from
  1161. t__dspsy when the calling task is resumed. Nothing is returned.
  1162. ~
  1163.  
  1164. t__dspsy  proc near
  1165.           mov ax,offset pgroup:t__krnl ; branch to system
  1166.           push ax
  1167.           sub sys_sstp,2 ; adjust system stack (for "pop bp" in t__sstk)
  1168.  
  1169. comment ~
  1170.  
  1171. t__trmap()
  1172.  
  1173. The  machine registers are stored on the application stack.  Then the system
  1174. stack is made current.  The return address from the call to t__trmap is put on
  1175. the system stack before returning to it. Nothing is returned.
  1176. ~
  1177.  
  1178. t__trmap  proc near
  1179.           mov byte ptr sys_ilck,0FFh ; force system state
  1180.           mov tmrdx,dx   ; save dx
  1181.           pop dx         ; set return address (from t__trmap)
  1182.           push cs        ; protect cs
  1183.           pushf          ; protect flags
  1184.           push ds        ; protect ds
  1185.           push ax        ; protect ax
  1186.           push bx        ; protect bx
  1187.           push cx        ; protect cx
  1188.           push tmrdx     ; protect dx
  1189.           push si        ; protect si
  1190.           push di        ; protect di
  1191.           push bp        ; protect bp
  1192.           push es        ; protect es
  1193.           push dx        ; restore return address to stack
  1194.           mov bp,sp      ; establish stack addressability
  1195.           mov ax,[bp].t_xip ; adjust stack for interrupt return
  1196.           xchg ax,[bp].t_xpf
  1197.           mov [bp].t_xip,ax
  1198.  
  1199. comment ~
  1200.  
  1201. t__sstk()
  1202.  
  1203. The  current application stack pointers are stored.  Then the system stack is
  1204. established as the current stack.  The return address from the call is placed
  1205. on the system stack before returning into it. Nothing is returned.
  1206. ~
  1207.  
  1208. t__sstk   proc near
  1209.           pop dx         ; unload return address
  1210.           push sys_asbs  ; protect stack protection reference
  1211.           mov bx,ss      ; set application stack registers
  1212.           mov cx,sp
  1213.           mov ax,sys_ssbs ; set system stack
  1214.           cli
  1215.           mov sys_asbs,ax
  1216.           push ds
  1217.           pop ss
  1218.           mov sp,sys_sstp
  1219.           sti
  1220.           pop bp         ; restore bp
  1221.           mov t__crtss,bx ; store current ss
  1222.           mov t__crtsp,cx ; store current bp
  1223.           push dx        ; return to caller
  1224.           ret
  1225. t__sstk   endp
  1226. t__trmap  endp
  1227. t__dspsy  endp
  1228.  
  1229. comment ~
  1230.  
  1231. t_sync(flg)
  1232. char *flg;
  1233.  
  1234. A wait loop will be entered until the required resource is available. This is
  1235. indicated  by flg containing 0x00.  0xFF is stored to prevent any other tasks
  1236. from acquiring the resource. The resource is released by resetting flg to
  1237. 0x00.
  1238. ~
  1239.  
  1240. t_sync    proc near
  1241.           push bp        ; protect bp
  1242.           mov bp,sp      ; establish stack addressability
  1243.           mov bx,[bp].t_np0 ; set pointer to resource flag
  1244.  
  1245. sync1:    mov al,0FFh    ; interlock token
  1246.           ilck al,<byte ptr [bx]>
  1247.           or al,al       ; test for token acquired
  1248.           jz sync2
  1249.           xor ax,ax      ; wait for 1 system tick
  1250.           inc ax
  1251.           push ax
  1252.           call t_spnd
  1253.           mov sp,bp
  1254.           jmp sync1      ; continue
  1255.  
  1256. sync2:    pop bp         ; restore bp
  1257.           call t_rels    ; release task
  1258.           ret            ; return
  1259. t_sync    endp
  1260.  
  1261. comment ~
  1262.  
  1263. t__syntr(flg)
  1264. char *flg;
  1265.  
  1266. This function expands the sys_entr macro for use by c functions.
  1267. ~
  1268.  
  1269. t__syntr  proc near
  1270.           push bp        ; protect bp
  1271.           mov bp,sp      ; establish stack addressability
  1272.           mov bx,[bp].t_np0 ; set flag address
  1273.           sys_entr <byte ptr [bx]> ; enter system state
  1274.           pop bp         ; restore bp
  1275.           ret            ; return
  1276. t__syntr  endp
  1277.  
  1278.  
  1279. comment ~
  1280.  
  1281. t__syxit(flg)
  1282. char *flg;
  1283.  
  1284. This function expands the sys_exit macro for use by c functions.
  1285. ~
  1286.  
  1287. t__syxit  proc near
  1288.           push bp        ; protect bp
  1289.           mov bp,sp      ; establish stack addressability
  1290.           mov bx,[bp].t_np0 ; set flag address
  1291.           sys_exit <byte ptr [bx]> ; exit system state
  1292.           pop bp         ; restore bp
  1293.           ret            ; return
  1294. t__syxit  endp
  1295.  
  1296.           endps
  1297.  
  1298.           end
  1299.  
  1300.  
  1301.  
  1302. Listing 4      High Resolution Clock
  1303. (C) Copyright 1986 Ken Berry.
  1304. All rights reserved.
  1305. Copies may be made for non-commercial, private use only.
  1306. ~
  1307.  
  1308.           include tele.mac ; system defintions (listing 2)
  1309.  
  1310.           extrn t_syxtm:word ; system execution time accumulator
  1311.           extrn sys_dgrp:word ; data segment storage
  1312.           extrn sys_stat:word ; original register block
  1313.  
  1314.           public t__tick ; system tick interrupt service
  1315.           public t_astrm ; application task termination flag
  1316.           public tmr_dspl ; physical display pointer
  1317.           public tmr_dvsr ; timer period
  1318.           public tmr_ilck ; tick service reentrant interlock
  1319.           public tmr_sync ; synchronization function address
  1320.           public tmr_tkct ; tick clock
  1321.           public tmr_xtm ; tick service execution time
  1322.           public tmr__clr ; reset time base generation
  1323.           public tmr__int ; timer initialization function
  1324.           public tmr__rst ; timer termination function
  1325.           public tmr__sts ; read timer status
  1326.           public tmr__tmr ; restart hardware timer
  1327.           public t_rdclk ; read high resolution clock
  1328.           public t_rtactg ; psuedo time accumulator pointer
  1329.           public t_rtmark ; mark execution interval
  1330.           public t__rdclk ; read real time clock
  1331.           public td_ref ; clock update tick reference count
  1332.           public td_tct ; clock tick timer
  1333.           public td__set ; set time of day clock
  1334.           public td__upd ; update time of day clock
  1335.           public w__cdspl ; physical display update function
  1336.           public w__sync ; physical display synchronization
  1337.  
  1338. RLCINT    equ 80h        ; relocated alternate time base interrupt
  1339. TMRINT    equ 8          ; hardware timer interrupt
  1340. TMRPRT    equ 40h        ; timer (8253) port
  1341. TMRPRD    equ 19912      ; timer period (60 Hz rate)
  1342. ;TMRPRD    equ 9956       ; timer period (120 Hz rate)
  1343. INTPRT    equ 20h        ; interrupt controller (8259) port
  1344. TMRMSK    equ 01h        ; hardware timer interrupt mask
  1345. INTEOI    equ 20h        ; interrupt termination value
  1346. DSPCT     equ 1          ; 60 Hz interrupt rate
  1347. ;DSPCT     equ 2          ; 120 Hz interrupt rate
  1348. IDV0      equ 3          ; tmr_idv0 divisor
  1349. ISKP0     equ 776        ; tmr_ict correction value
  1350. ISKP1     equ 11         ; tmr_idv1 correction value
  1351. ISKP2     equ 38         ; tmr_idv2 correction value
  1352.  
  1353.           dseg
  1354.  
  1355. tmr_tkct  dw 0           ; interrupt counter
  1356. tmr_dct   db 0           ; display counter
  1357. tmr_ict   dw 0           ; tick clock (for time base generation)
  1358. tmr_dvsr  dw TMRPRD      ; 1/2 timer period
  1359. t_astrm   db 0FFh        ; application task termination flag
  1360. tmrflg    db 0FFh        ; system state flag (t__tick)
  1361. tmr_ilck  db 0           ; tick service reentrant interlock
  1362. tmr_idv0  db 0           ; clock time base generator
  1363. tmr_idv1  db 0           ; primary alternate time base generator
  1364. tmr_idv2  db 0           ; secondary alternate time base generator
  1365. tmr_dspl  dw 0           ; console display w_pwdw pointer
  1366. t_rtactg  dw 0           ; psuedo time accumulator pointer
  1367. t_rtrfct  dw 0           ; real time reference count
  1368. t_rttick  dw 0           ; tick clock phase
  1369. tmr_xtm   dw 3 dup (0)   ; tick service psuedo time accumulator
  1370. tmrpxtm   dw 0           ; prior psuedo time accumulator pointer
  1371. tmr_sync  dw offset pgroup:w__sync ; synchronization function pointer
  1372. td_ref    dw 0           ; clock update tick reference count
  1373. td_tct    dw 0           ; clock tick timer
  1374.  
  1375.           endds
  1376.  
  1377.           pseg
  1378.  
  1379. comment ~
  1380. t__tick                  system tick service
  1381.  
  1382. t__tick\\
  1383.  
  1384. Control only comes here in response to an interrupt from the system clock.
  1385. This function serves three purposes. It maintains the system clock, which
  1386. provides the current date and time for both system and application uses. It
  1387. also  performs an update of the first physical display. And finally it
  1388. terminates the execution interval for the current application task. 
  1389.  
  1390. t__tick   proc far
  1391.  
  1392. ; reentrant lockout
  1393.  
  1394.           assume ss:nothing,ds:nothing,es:nothing
  1395.           sti            ; interrupts on
  1396.           push ds        ; protect ds
  1397.           push ax        ; protect ax
  1398.           mov ax,dgroup  ; establish data addressability
  1399.           mov ds,ax
  1400.           assume ds:dgroup
  1401.           mov al,INTEOI  ; terminate interrupt
  1402.           out INTPRT,al
  1403.           ilck al,tmr_ilck ; test for not reentrant call
  1404.           or al,al
  1405.           jz tick
  1406.           pop ax         ; restore ax
  1407.           pop ds         ; restore ds
  1408.           iret           ; return from interrupt
  1409.  
  1410. ; system interlock
  1411.  
  1412. tick:     mov t_astrm,0FFh ; terminate application task
  1413.           sys_entr tmrflg ; enter system state
  1414.  
  1415. ; set machine environment
  1416.  
  1417.           sys_sctx       ; save processor context
  1418.           push bp        ; protect bp
  1419.           mov bp,sp      ; mark stack location
  1420.           lea ax,tmr_xtm ; accumulate psuedo time
  1421.           push ax
  1422.           call t_rtmark
  1423.           mov sp,bp
  1424.           mov tmrpxtm,ax ; store prior pointer
  1425.  
  1426. ; real time system processing
  1427.  
  1428.           inc tmr_dct    ; remove display harmonics
  1429.           mov al,DSPCT
  1430.           xor al,tmr_dct
  1431.           jnz tick4
  1432.           mov tmr_dct,al
  1433.           push tmr_dspl  ; display physical window
  1434.           call w__cdspl
  1435.           mov sp,bp      ; restore stack pointer
  1436.           inc tmr_ict    ; increment interrupt counter
  1437.           inc tmr_tkct   ; increment tick clock
  1438.  
  1439. ; time base generation
  1440.  
  1441.           mov ax,ISKP0   ; long term time base correction
  1442.           xor ax,tmr_ict
  1443.           jnz tick1
  1444.           mov tmr_ict,ax
  1445.           call tick5     ; update system tick clock
  1446. tick1:    inc tmr_idv0   ; generate clock time base
  1447.           mov al,IDV0
  1448.           xor al,tmr_idv0
  1449.           jnz tick3
  1450.           mov tmr_idv0,al
  1451.           call tick5     ; update system tick clock
  1452.           inc tmr_idv1   ; primary alternate time base correction
  1453.           mov al,ISKP1
  1454.           xor al,tmr_idv1
  1455.           jnz tick2
  1456.           mov tmr_idv1,al
  1457.           int RLCINT     ; update alternate time base
  1458.           inc tmr_idv2   ; secondary alternate time base correction
  1459.           mov al,ISKP2
  1460.           xor al,tmr_idv2
  1461.           jnz tick2
  1462.           mov tmr_idv2,al
  1463.           int RLCINT     ; update alternate time base
  1464. tick2:    int RLCINT     ; update alternate time base
  1465.  
  1466. ; terminate interrupt service
  1467.  
  1468. tick3:    push tmrpxtm   ; restore original psuedo time accumulator
  1469.           call t_rtmark
  1470.           mov sp,bp
  1471.           pop bp         ; restore bp
  1472.           test tmrflg,0FFh ; test for interrupted system task
  1473.           jnz tick4
  1474.           xor ax,ax      ; terminate task
  1475.           mov tmr_ilck,al ; enable reentrance
  1476.           retn           ; near return to system task management
  1477.  
  1478. tick4:    sys__rctx      ; restore processor context
  1479.           cli            ; interrupts off
  1480.           mov tmr_ilck,0 ; enable reentrance
  1481.           pop ds         ; restore ds
  1482.           iret           ; return to interrupted task
  1483.  
  1484. ; update system tick counter
  1485.  
  1486. tick5:    mov ax,td_tct  ; test for no overflow
  1487.           inc ax
  1488.           cmp ax,td_ref
  1489.           jne tick6
  1490.           call td__upd   ; update clock
  1491.           xor ax,ax      ; reset tick counter
  1492.           mov td_ref,ax
  1493.           mov td_tct,ax
  1494. tick6:    inc td_tct     ; increment tick counter
  1495.           retn           ; return
  1496.  
  1497. t__tick   endp
  1498.  
  1499. comment ~
  1500. tmr__int                 initialize timer
  1501.  
  1502. tmr__int()
  1503.  
  1504. All data areas necessary for clock maintenance are initialized. The hardware
  1505. timer is programmed for the appropriate rate and its interrupt vector is made 
  1506. to point to sys_tmr. The original vector is relocated and will be used by
  1507. sys_tmr as the alternate time base.
  1508. ~
  1509.  
  1510. tmr__int  proc near
  1511.           call tmr__dsi  ; diable interrupts
  1512.           mov ax,dgroup  ; set data segment
  1513.           mov sys_dgrp,ax
  1514.           mov ax,cs      ; set code segment
  1515.           lea si,sys_stat
  1516.           mov [si].rcs,ax
  1517.           cli            ; interrupts off
  1518.           mov tmr_ilck,0FFh ; lockout t__tick
  1519.           mov bx,tmr_sync ; test for no synchronization function
  1520.           test bx,bx
  1521.           jz int0
  1522.           lea bx,tmr_sync ; synchronize timer interrupt
  1523.           call [bx]
  1524.           jmp short int1 ; continue
  1525. int0:     call tmr__tmr  ; start timer
  1526. int1:     call t_rdclk   ; set real time clock phase
  1527.           mov t_rttick,ax
  1528.           mov t_rtrfct,ax ; set reference count
  1529.           mov t_rtactg,offset dgroup:t_syxtm ; initialize time accumulator
  1530.           call td__set   ; set current time
  1531.           sti            ; interrupts on
  1532.           xor ax,ax      ; form 0
  1533.           push ds        ; protect ds
  1534.           mov ds,ax      ; relocate original interrupt vector
  1535.           mov di,ax
  1536.           cli
  1537.           mov ax,[di+4*TMRINT]
  1538.           mov [di+4*RLCINT],ax
  1539.           mov ax,[di+4*TMRINT+2]
  1540.           mov [di+4*RLCINT+2],ax
  1541.           mov ax,offset pgroup:t__tick ; set interrupt service
  1542.           mov [di+4*TMRINT],ax
  1543.           mov ax,cs
  1544.           mov [di+4*TMRINT+2],ax
  1545.           sti            ; interrupts on
  1546.           pop ds         ; restore ds
  1547.           call tmr__eni  ; enable interrupts
  1548.           ret            ; return
  1549. tmr__int  endp
  1550.  
  1551.  
  1552. comment ~
  1553. tmr__clr                 reset time base generation
  1554.  
  1555. tmr__clr()
  1556.  
  1557. The time base adjustment variables are reset. This function is to be called by
  1558. td__set when the time of day is initially set from a continuous clock. Nothing
  1559. is returned.
  1560. ~
  1561.  
  1562. tmr__clr  proc near
  1563.           xor ax,ax      ; zero time base generation variables
  1564.           mov tmr_idv0,al
  1565.           mov tmr_idv1,al
  1566.           mov tmr_idv2,al
  1567.           ret            ; return
  1568. tmr__clr  endp
  1569.  
  1570.  
  1571. comment ~
  1572. tmr__rst                 reset timer
  1573.  
  1574. tmr__rst()
  1575.  
  1576. The original interrupt service routine is restored and the hardware clock is
  1577. reprogrammed. However, the original hardware values are not available in this
  1578. edition. Therefore the original system state cannot always be restored.
  1579.  
  1580.  
  1581. tmr__rst  proc near
  1582.           mov tmr_ilck,0FFh ; lock out interrupt service
  1583.           push ds        ; protect ds
  1584.           xor ax,ax      ; restore original interrupt vector
  1585.           mov ds,ax
  1586.           mov di,ax
  1587.           call tmr__dsi  ; disable timer interrupt
  1588.           cli            ; interrupts off
  1589.           mov ax,[di+4*RLCINT]
  1590.           mov [di+4*TMRINT],ax
  1591.           mov ax,[di+4*RLCINT+2]
  1592.           mov [di+4*TMRINT+2],ax
  1593.           pop ds         ; restore ds
  1594.           xor bx,bx      ; restart hardware timer
  1595.           call tmr__str
  1596.           sti            ; interrupts on
  1597.           call tmr__eni  ; enable timer interrupt
  1598.           ret            ; return
  1599. tmr__rst  endp
  1600.  
  1601. comment ~
  1602. tmr__tmr                 restart hardware timer
  1603.  
  1604. tmr__tmr\\
  1605.  
  1606. Channel 0 of an 8253 timer is initialized to mode 3. The count in bx is then
  1607. programmed.
  1608.  
  1609.  
  1610. tmr__tmr  proc near      ; restart timer
  1611.           mov bx,tmr_dvsr ; set tele system tick period
  1612. tmr__str  proc near      ; set timer period
  1613.           mov al,20      ; reset 8253 (mode 0, count >= 8,192)
  1614.           out TMRPRT+3,al ; [> 6.8 msec]
  1615.           iowait
  1616.           out TMRPRT,al
  1617.           mov al,36h     ; initialize 8253 (mode 3, both bytes)
  1618.           iowait
  1619.           out TMRPRT+3,al
  1620.           mov al,bl
  1621.           iowait
  1622.           out TMRPRT,al
  1623.           mov al,bh
  1624.           iowait
  1625.           out TMRPRT,al
  1626.           ret            ; return
  1627. tmr__str  endp
  1628. tmr__tmr  endp
  1629.  
  1630. comment ~
  1631. tmr__sts                 read timer status
  1632.  
  1633. tmr__sts()
  1634.  
  1635. The returned value is the current count in the timer.
  1636. ~
  1637.  
  1638. tmr__sts  proc near      ; read timer status
  1639.           mov al,00h     ; set read mode
  1640.           out TMRPRT+3,al
  1641.           nop            ; allow timer chip to recover
  1642.           in al,TMRPRT   ; read count
  1643.           mov ah,al
  1644.           in al,TMRPRT
  1645.           xchg ah,al
  1646.           ret            ; return
  1647. tmr__sts  endp
  1648.  
  1649. comment ~
  1650. tmr__dsi                 disable interrupt
  1651.  
  1652. tmr__dsi()
  1653.  
  1654. The timer interrupt is disabled at the 8259 interrupt controller.
  1655. ~
  1656.  
  1657. tmr__dsi  proc near
  1658.           cli            ; interrupts off
  1659.           in al,INTPRT+1 ; disable timer interrupt
  1660.           or al,TMRMSK
  1661.           iowait
  1662.           out INTPRT+1,al
  1663.           sti            ; interrupts on
  1664.           ret            ; return
  1665. tmr__dsi  endp
  1666.  
  1667. comment ~
  1668. tmr__eni                 enable interrupt
  1669.  
  1670. tmr__eni()
  1671.  
  1672. The timer interrupt is enabled at the 8259 interrupt controller.
  1673. ~
  1674.  
  1675. tmr__eni  proc near
  1676.           cli            ; interrupts off
  1677.           in al,INTPRT+1; ; enable timer interrupt
  1678.           and al,not TMRMSK
  1679.           iowait
  1680.           out INTPRT+1,al
  1681.           sti            ; interrupts on
  1682.           ret            ; return
  1683. tmr__eni  endp
  1684.  
  1685. comment ~
  1686. t_rdclk                  read real time clock
  1687.  
  1688. t_rdclk()
  1689.  
  1690. The current value of the real time clock is read and returned.
  1691. ~
  1692.  
  1693. DMAREG    equ 0          ; refresh address DMA register
  1694.  
  1695. t_rdclk   proc near
  1696. rdclk0:   mov dx,DMAREG  ; set DMA register address
  1697.           call t__rdclk  ; read time
  1698.           mov bx,ax      ; store time
  1699.           call t__rdclk  ; read time again
  1700.           cmp ah,bh      ; test for interruption
  1701.           jne rdclk0
  1702.           ret            ; return
  1703. t_rdclk   endp
  1704.  
  1705. t__rdclk  proc near
  1706.           cli            ; interrupts off
  1707.           in al,dx       ; read time
  1708.           mov ah,al
  1709.           iowait
  1710.           in al,dx
  1711.           xchg al,ah
  1712.           sti            ; interrupts on
  1713.           ret            ; return
  1714. t__rdclk  endp
  1715.  
  1716. comment ~
  1717. t_rtmark                 mark execution interval
  1718.  
  1719. t_rtmark(np)
  1720. pointer *np;
  1721.  
  1722. The number of refreshes since the last call to t_rtmark is accumulated. Then
  1723. the reference count is reset. np points to the area that will accumulate the
  1724. number of refreshes to the next call. The returned value is the original
  1725. accumulator pointer.
  1726.  
  1727.  
  1728. t_rtmark  proc near
  1729.           push bp        ; protect bp
  1730.           mov bp,sp      ; establish parameter addressability
  1731.           call tmr__dsi  ; disable timer interrupt
  1732.           call t_rdclk   ; read real time clock
  1733.           mov bx,ax      ; protect current count
  1734.           xchg bx,t_rtrfct ; update reference count
  1735.           sub ax,bx      ; compute execution interval
  1736.           jnc mark1      ; test for no overflow
  1737.           neg ax         ; adjust count
  1738. mark1:    mov bx,t_rtactg ; accumulate execution time
  1739.           add ax,[bx]
  1740.           mov [bx],ax
  1741.           jnc markxit
  1742.           add word ptr [bx+2],1
  1743.           jnc markxit
  1744.           inc word ptr [bx+4]
  1745. markxit:  mov ax,bx      ; return orginal pointer
  1746.           mov bx,[bp].t_np0 ; set new accumulator pointer
  1747.           mov t_rtactg,bx
  1748.           call tmr__eni  ; enable timer interrupt
  1749.           pop bp         ; restore bp
  1750.           ret            ; return
  1751. t_rtmark  endp
  1752.  
  1753. comment ~
  1754. w__cdspl                 display physical buffer
  1755.  
  1756. w__cdspl(pw)
  1757. struct w_phys *pw;
  1758.  
  1759. Physical window pw is displayed.  This function is called by the system tick 
  1760. clock interrupt service function.  Nothing is returned.
  1761. ~
  1762.  
  1763. w__cdspl  proc near
  1764.           ret            ; return
  1765. w__cdspl  endp
  1766.  
  1767. comment ~
  1768. w__sync                  synchronize interrupt to display
  1769.  
  1770. w__sync()
  1771.  
  1772. The system tick clock timer is adjusted so that w__dsply executes just prior
  1773. to the vertical blanking interval.  Nothing is returned.
  1774. ~
  1775.  
  1776. w__sync   proc near
  1777.           call tmr__tmr  ; start timer
  1778. w__sync   endp
  1779.  
  1780. comment ~
  1781. td__set                  set time of day clock
  1782.  
  1783. td__set()
  1784.  
  1785. The clock is set to the current time.  Nothing is returned.
  1786. ~
  1787.  
  1788. td__set   proc near
  1789.           ret            ; return
  1790. td__set   endp
  1791.  
  1792. comment ~
  1793. td__upd                  update clock
  1794.  
  1795. td__upd()
  1796.  
  1797. The clock is updated based on the number of ticks since it was last updated.
  1798. The normal return (ax) is _F.  _E is returned if the call was locked out.
  1799. ~
  1800.  
  1801. td__upd   proc near
  1802.           ret            ; return
  1803. td__upd   endp
  1804.  
  1805.           endps
  1806.  
  1807.           end
  1808.  
  1809.