home *** CD-ROM | disk | FTP | other *** search
/ RBBS in a Box Volume 1 #2 / RBBS_vol1_no2.iso / add2 / amag0389.zip / AMAG0389.TXT
Text File  |  1989-03-28  |  80KB  |  2,223 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10. THE ASSEMBLY LANGUAGE "MAGAZINE"                  VOL 1 NUMBER 2
  11.                                                   March 1989
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.   ##     ####    ####   ####### ##   ## ######  ####    ##  ##
  30.  ####   ##  ##  ##  ##   ##   # ### ###  ##  ##  ##     ##  ##
  31. ##  ##  ###     ###      ## #   #######  ##  ##  ##     ##  ##
  32. ##  ##   ###     ###     ####   #######  #####   ##      ####
  33. ######     ###     ###   ## #   ## # ##  ##  ##  ##   #   ##
  34. ##  ##  ##  ##  ##  ##   ##   # ##   ##  ##  ##  ##  ##   ##
  35. ##  ##   ####    ####   ####### ##   ## ######  #######  ####
  36.  
  37.         ####      ##    ##   ##   ####  ##  ##    ##      ####  #######
  38.          ##      ####   ###  ##  ##  ## ##  ##   ####    ##  ##  ##   #
  39.          ##     ##  ##  #### ## ##      ##  ##  ##  ##  ##       ## #
  40.          ##     ##  ##  ## #### ##      ##  ##  ##  ##  ##       ####
  41.          ##   # ######  ##  ### ##  ### ##  ##  ######  ##  ###  ## #
  42.          ##  ## ##  ##  ##   ##  ##  ## ##  ##  ##  ##   ##  ##  ##   #
  43.         ####### ##  ##  ##   ##   ##### ######  ##  ##    ##### #######
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59. Written by and for assembly language programmers.
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.           
  67.           
  68.           
  69.           
  70.                             March     1989    Contents
  71.           
  72.           Policy...................................................  3
  73.           
  74.           Editorial................................................  4
  75.           
  76.           Beginners Corner.........................................  5
  77.           
  78.           What is SDN?.............................................  7
  79.           
  80.           FASTPRINT................................................  8
  81.                    by Dennis Yelle
  82.           The EXEC Function........................................ 11
  83.                    by Patrick O'Riva
  84.           TSR's.................................................... 13
  85.                    by David O'Riva
  86.           Book Reviews............................................. 17
  87.           
  88.           Program Spotlight........................................ 18
  89.           
  90.           
  91.           Source listings in order of appearance
  92.           
  93.           
  94.           
  95.           
  96.                It has been suggested that the source listings be placed
  97.           at the end of the "Magazine" rather than following the
  98.           associated article. If you prefer it one way or the other
  99.           please advise the editor.
  100.           
  101.           Address of The Assembly Language "Magazine"
  102.                     AsmLang and CFS  FidoNet 143/37 408-259-2223
  103.                     Patrick O'Riva
  104.                     2726 Hostetter Rd.
  105.                     San Jose, CA 95132
  106.           
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.                                         2
  124.  
  125.  
  126.  
  127.  
  128.  
  129.           
  130.           
  131.                    GUIDE LINES FOR CONTRIBUTORS AND 'ADVERTISERS'
  132.           
  133.           
  134.                Name and address must be included with all articles and
  135.           files.  Executable file size and percent of assembly code
  136.           (when available) should be included when a program is
  137.           mentioned and is required from an author or publisher.
  138.           
  139.                Any article of interest to Assembly language programmers
  140.           will be considered for inclusion.  Quality of writing will not
  141.           be a factor, but I reserve the right to try and correct
  142.           spelling errors and minor mistakes in grammar.  Non-exclusive
  143.           copyright must be given. No monetary compensation will be
  144.           made.
  145.           
  146.                Outlines of projects that might be undertaken jointly are
  147.           welcome.  For example: One person who is capable with hardware
  148.           needs support from a user friendly programmer and a math whiz.
  149.           
  150.                Advertisements as such are not acceptable.  Authors and
  151.           publishers wishing to contribute reviews of their own products
  152.           will be considered and included as space and time permit.
  153.           These must include executable file size, percent of assembly
  154.           code and time comparisons.
  155.           
  156.                Your editor would like information on math libraries, and
  157.           reviews of such.
  158.           
  159.                Articles must be submitted in pclone readable format or
  160.           sent E-mail.
  161.           
  162.           
  163.                Money: Your editor has none.  Therefore no compensation
  164.           can be made for articles included.  Subscription fees
  165.           obviously don't exist.  Publication costs I expect to be nil
  166.           (NUL). Small contributions will be accepted to support the BBS
  167.           where back issues are available as well as files and programs
  168.           mentioned in articles(if PD or Shareware ONLY).
  169.           
  170.                Shareware-- Many of the programs mentioned in the
  171.           "Magazine" are Shareware.  Most of the readers are prospective
  172.           authors of programs that can be successfully marketed as
  173.           Shareware.  If you make significant use of these programs the
  174.           author is entitled to his registration fee or donation.
  175.           Please help Shareware to continue to be a viable marketing
  176.           method for all of us by urging everyone to register and by
  177.           helping to distribute quality programs.
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.                                         3
  187.  
  188.  
  189.  
  190.  
  191.  
  192.           
  193.                                     Editorial
  194.           
  195.                This is the second monthly edition of the Assembly
  196.           Language Magazine.  I have been disappointed in the response
  197.           to the first issue both in the number of comments I have
  198.           received and in the lack of articles submitted for inclusion
  199.           in this issue.  I would like to give a special thank you to
  200.           Richard Hendricks for his letter of suggestions and comments,
  201.           most of which I hope to address in this issue. He felt that a
  202.           less full look to the pages would improve the readability and
  203.           appearance.
  204.           
  205.                My original idea was to fill the page as much as possible
  206.           to reduce the amount of print out.  Many of his other comments
  207.           reflect my lack of experience as an editor, and I will try to
  208.           improve.
  209.           
  210.                Without some articles being sent in this will be near the
  211.           last issue. The time is not available for your editors to
  212.           write the entire magazine every month, and even if it were,
  213.           the quality would suffer from lack of variety. Please send
  214.           those submissions.
  215.           
  216.                Please excuse the late publication this month.
  217.           
  218.                                       ERRATA
  219.           
  220.                The name of the Author of the A86 Assembler was
  221.           misspelled.  The correct spelling is: Eric Isaacson
  222.           
  223.                In the article about fast memory moves I repeatedly
  224.           referred to the 8259 as the DMA processor.  The 8259 is the
  225.           interrupt controller and has nothing to do with DMA transfers.
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.                                         4
  250.  
  251.  
  252.  
  253.  
  254.  
  255.           
  256.                                 Beginners Corner.
  257.           
  258.                Obviously the first requirement for learning any assembly
  259.           language is to have a list of the instructions.  This may
  260.           sound easy and it is something that most novice level books
  261.           claim to have, but it is one of the most difficult things to
  262.           find.
  263.           
  264.                Every source I have found is very incomplete and/or
  265.           unclear.  The exact use of each command and the hundreds of
  266.           variations on each forces even scarred veterans to look back
  267.           at a reference now and again.
  268.           
  269.                At least one of your references must contain the clocks
  270.           data for each instruction.  For the 80XXX series of processors
  271.           this is a very confusing table of adds for all occasions. The
  272.           basic time for the instruction is given plus the number of
  273.           accesses plus EA calculation.  It is different for a
  274.           conditional jump taken and when it is not.  To make matters
  275.           even worse we are dealing with not one processor, but with at
  276.           least 5: 8088, 80286, 80386, V20, V30.  Each of these works
  277.           differently and thus each has its own timing.  Because it is
  278.           the worst case and because there are so many installed it is
  279.           always best to use the timing for the 8088 unless you are
  280.           writing for a particular application or system.
  281.           
  282.                A first glance at the EA calculation table will be very
  283.           enlightening to those who have used a high level language.
  284.           Most of the variables passed and most all of the structures
  285.           addressed are done with pointers and offsets to pointers.
  286.           These are VERY costly time wise.  Even pushes and pops take
  287.           far longer than one would think.  A memory access (fetching
  288.           the value of a variable) especially using the AX register pair
  289.           is faster than a push and pop.  Be familiar with your
  290.           instructions and how long they take.  Only use half of the
  291.           register pair if that is all you need because it saves an
  292.           additional fetch, cutting the time almost in half.
  293.           
  294.                A clear verbal description of each instructions including
  295.           its peculiarities is essential. This is true for all, but the
  296.           more complex instructions such as rep movsb make it mandatory.
  297.           
  298.                Each instruction should list the flags it can affect.
  299.           These are not always what you want or need.  For example: the
  300.           INC instruction does not affect the carry flag.  As silly as
  301.           it may sound you have to use an instruction that affects the
  302.           flag you want to test for.
  303.           
  304.                The Rotate and Shift group of instructions should be
  305.           accompanied with diagrams showing their operation. A glance at
  306.           the diagrams will show exactly which one to use where it could
  307.           take reading pages to do the same thing.
  308.           
  309.  
  310.  
  311.  
  312.                                         5
  313.  
  314.  
  315.  
  316.  
  317.  
  318.                One final note of caution that seems to fit in here --
  319.           unless you are doing signed arithmetic operations avoid the
  320.           use of the JG and JL type instructions.  They take the sign
  321.           bit into account and can cause very hard to trace bugs.  Use
  322.           the JA and JB instructions instead.
  323.           
  324.                Your next most important reference is a description of
  325.           the BIOS calls.  Most of these are very straight forward and
  326.           require little by way of explanation.
  327.           
  328.                Next comes a DOS reference. The critical ones of these
  329.           are also quite simple to understand and use. Don't get
  330.           involved with FCB's; the handle method of file access is the
  331.           only way to go.
  332.           
  333.                For your BIOS and DOS references almost any will work,
  334.           but your basic instruction description look long and hard. You
  335.           will probably end up with several you use regularly.
  336.           
  337.                With all of your reference works stacked up around you,
  338.           sitting at your computer, what next?  You need to choose an
  339.           assembler.  There are at least 4 major packages available,
  340.           each with its supporters and its weaknesses. The Microsoft
  341.           MASM is complete and the de facto standard.  It is also large
  342.           and slow. TASM from Borland is faster, and is mostly
  343.           compatible, but tricky for beginners. Optasm I am not very
  344.           familiar with, though it sounds pretty good. It is much faster
  345.           than MASM, and is a full 2 pass assembler. If you are not
  346.           concerned with compatibility A86 is fast, small and simple to
  347.           use, and the D86 debugger is adequate.
  348.           
  349.                The text editor you use must produce a pure ASCII file.
  350.           Whatever you enjoy is the one to use. Qedit from Semware can
  351.           be configured to act like almost any other, and is fast and
  352.           small.
  353.           
  354.                  Next month: Segmentation and Memory allocation.
  355.           
  356.                                 Useful Shareware:
  357.           1029ref                       DOS and Pc Tech Reference
  358.           inter                         Complete interrupt listing
  359.           @last200                      Pop up tables
  360.           LW86                          Pop up instruction summary
  361.           Qedit                         Text editor
  362.           A86                           Assembler
  363.           D86                           Symbolic Debugger
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.                                         6
  376.  
  377.  
  378.  
  379.  
  380.  
  381.           
  382.                                    What is SDN?
  383.           
  384.                SDN stands for Shareware Distribution Network. It is a
  385.           relatively new organization operating largely within FidoNet
  386.           but in no way affiliated with it. SDN receives software direct
  387.           from the author on disk, compresses it using the PAK facility
  388.           from No Gate and distributes it to affiliated BBS's throughout
  389.           the country, in a highly traceable manner.
  390.           
  391.                This distribution method is advantageous for both the
  392.           author and  the user. It assures the author of quick and
  393.           complete distribution nationwide, and it assure the user of
  394.           complete and uncontaminated software.
  395.           
  396.                There is no charge to either the author or the user for
  397.           this service, but the author must comply with the instructions
  398.           for transmitting the software to the SDN home point.
  399.           
  400.                Complete information is available from your local SDN BBS
  401.           or as a last resort you can get the informational files from
  402.           AsmLang.
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.                                         7
  439.  
  440.  
  441.  
  442.  
  443.  
  444.           
  445.           
  446.                     FASTPRINT: The fix for one of PRINT's bugs
  447.                                  by Dennis Yelle
  448.           
  449.           
  450.                Does your printer slow down when you run LIST or your
  451.           favorite editor, word processor, debugger, or other program
  452.           that spends most of its time just waiting for you to type at
  453.           it?  Does this annoy you?  It annoyed me!  It annoyed me
  454.           enough so that I did something about it.
  455.           
  456.           How to use it:
  457.           --------------
  458.                Just type FASTPRINT at the DOS prompt, either before or
  459.           after you run PRINT.  Or put the FASTPRINT command in your
  460.           AUTOEXEC.BAT file, that's what I do.  If you put FASTPRINT in
  461.           your AUTOEXEC.BAT file, it should normally be placed AFTER any
  462.           utility that increases the size of the keyboard type-ahead
  463.           buffer.
  464.           
  465.           How it works, if you like grubby details:
  466.           -----------------------------------------
  467.                The PRINT command installs a TSR that prints files in the
  468.           background.  This allows you to run other programs on your
  469.           computer while the file(s) print.  The PRINT TSR "steals" some
  470.           computer time from you, but usually not enough to bother you.
  471.           The problem is that sometimes (usually) it doesn't steal
  472.           enough to keep the printer running at anywhere near full
  473.           speed.  Fortunately, there is a way to "give" the PRINT TSR
  474.           more time.  And, it turns out that COMMAND.COM does just that
  475.           when it is waiting for you to type a DOS command.  The problem
  476.           is that most programs that you run don't do this.  And so the
  477.           printer slows down.  ugh!  Now we get to the good part.
  478.           FASTPRINT looks for some signs that indicate that the
  479.           foreground program is waiting for something, like a keystroke,
  480.           and tells PRINT to do some printing while we wait.
  481.           
  482.           How it works, only for those who like the REALLY grubby
  483.           details:
  484.           -------------------------------------------------------
  485.           
  486.                The way to "give" the PRINT TSR some computer time is to
  487.           put 0080H in AX, and do an INT 2FH.  What FASTPRINT does, is
  488.           link itself into interrupts 15H and 16H.  INT 16H is used to
  489.           read the keyboard.  When a program tries to read a key that
  490.           the human has not typed yet, FASTPRINT gives PRINT a bit of
  491.           computer time, and then checks to see if the human has typed
  492.           the key yet.  If not, then it gives PRINT some more time and
  493.           checks the keyboard again...INT 15H function 90H is used on
  494.           the AT only to tell other programs that we are waiting for
  495.           something that may take some time.  So, if this happens, then
  496.           FASTPRINT gives some time to PRINT.
  497.  
  498.  
  499.  
  500.  
  501.                                         8
  502.  
  503.  
  504.  
  505.  
  506.  
  507.                To make FASTPRINT even more useful to those who like
  508.           grubby details, I am including the A86 source code for the
  509.           program.
  510.           
  511.           How to pay for it:
  512.           ------------------
  513.           1. If it is before March 30, 1989 then just:  Send a message
  514.           to me reporting how well FASTPRINT worked for you, including:
  515.           
  516.           (A. the hardware you are running on;
  517.           (B. the version of DOS you are using;
  518.           (C. how well it works, that is, for example, how many seconds
  519.           does it take to print a www byte xxx line file with a yyy
  520.           printer with and without using FASTPRINT while inside program
  521.           zzz; and
  522.           (D. anything else you have discovered about it, including any
  523.           incompatibility with other programs.
  524.           
  525.                You may send this message to my PO Box, or to me at any
  526.           of these BBS'S:
  527.                           AsmLang and CFS (Opus 1:143/37)  408-259-2223
  528.                           HomeBase 408-988-4004
  529.                           PDSE     408-745-0880
  530.           
  531.           2. Just send a check for about 1/4 of what you think it is
  532.           worth to you to:
  533.               Dennis Yelle
  534.               P. O. Box 62276
  535.               Sunnyvale, CA  94088
  536.           
  537.                If you want to donate, but don't know how much it is
  538.           worth, then just send me $10.
  539.           
  540.           3. FOR PROGRAMMERS ONLY:  If you want to use any or all of the
  541.           source code in the file FASTPRIN.8 in your own program(s), you
  542.           may buy the right to do so for $25.
  543.           
  544.           Legal mumbo jumbo
  545.           -----------------
  546.                This document and the program files FASTPRIN.COM and
  547.           FASTPRIN.8 are copyrighted by the author.  The copyright owner
  548.           hereby licenses you to: use the software; make as many copies
  549.           of it as you wish; give the copies to anyone; and to post this
  550.           .ARC file on BBS'S, if the BBS is free.  There is no charge
  551.           for any of the above.
  552.                However, you are specifically prohibited from charging,
  553.           or requesting donations, for any copies, however made; and
  554.           from distributing this software and/or documentation with
  555.           commercial products without prior permission.
  556.                No copy of this software may be distributed or given away
  557.           without this document; and this notice must not be removed.
  558.           There is no warranty of any kind, and the copyright owner is
  559.           not liable for damages of any kind.  By using this software,
  560.           you agree to this.
  561.  
  562.  
  563.  
  564.                                         9
  565.  
  566.  
  567.  
  568.  
  569.  
  570.           
  571.           --------------------------------------------------------------
  572.                Editors note: This is the documentation for FASTPRINT and
  573.           has been included in the magazine at the author's suggestion
  574.           as it describes the operation, is written in assembly and
  575.           includes the source.
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606.  
  607.  
  608.  
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.                                         10
  628.  
  629.  
  630.  
  631.  
  632.  
  633.           
  634.                                 The EXEC Function
  635.                                         by
  636.                                   Patrick O'Riva
  637.           
  638.                The EXEC function is one of the most powerful features of
  639.           DOS.  It allows shelling out of an application, and even going
  640.           as far as invoking another command interpreter. It is also
  641.           rather complex to use and there is no debugging help from DOS.
  642.           
  643.                The EXEC command comes in three basic flavors; Load and
  644.           execute a file, Load and overlay, and the 3rd is an internal
  645.           DOS function of load a file. Only the load and execute a file
  646.           will be covered in detail this month.
  647.           
  648.                I freely admit I'm not an expert on the use of the EXEC
  649.           function, but I have convinced it to work for me and done so
  650.           recently enough I can remember most of the mistakes. If anyone
  651.           reading this is better informed, I encourage them to write a
  652.           supplementary article.
  653.           
  654.                DOS requires that you supply three separate pieces of
  655.           information. The program <filename> fully qualified as to
  656.           drive, path, filename and extension. My experience is that it
  657.           will not make a path search, but this might be inaccurate and
  658.           caused by a slight error in syntax. The second item is the
  659.           command line arguments in DOS format, where the first byte
  660.           specifies the length of the argument including the length
  661.           byte.  The third item is an environment block. For this one
  662.           you are allowed to default to current block as passed to the
  663.           program you are EXEC'ing out of. To execute a batch file or
  664.           use the built-in DOS commands you must EXEC command.com itself
  665.           and pass the program name in the arguments.
  666.           
  667.                For "load and execute" a program the syntax is as
  668.           follows:
  669.           
  670.                AH=4Bh    EXEC function number within INT 21h
  671.                AL=0      specify "load and execute"
  672.                DX        points to program name,
  673.                               i.e. 'C:\MYSTUFF\RUNME.EXE'
  674.                ES:BX     points to the "EXEC control block", defined
  675.                          as follows:
  676.                            WORD   segment of environment block to pass
  677.                                if 0 defaults to parent block.
  678.                                environment is assumed to be at offset 0
  679.                                within this segment
  680.                            DWORD  pointer to command tail
  681.                            DWORD  pointer to 1st FCB
  682.                            DWORD  pointer to 2nd FCB
  683.           
  684.                "COMMAND TAIL" is defined as that portion of a command
  685.           line following the program name, preceded by a one byte count
  686.  
  687.  
  688.  
  689.  
  690.                                         11
  691.  
  692.  
  693.  
  694.  
  695.  
  696.           of the length of the tail plus 1 for the terminating CR (0Dh),
  697.           i.e.      DB   12,'/h /Ox1.obj',0Dh
  698.           
  699.                The first job most any program should do is return to DOS
  700.           any portion of memory that is not required. Without this
  701.           operation there would be no place for DOS to load the new
  702.           program. It is also best to do this to inform your program how
  703.           much memory is available to it to use for data storage and
  704.           other general uses. If FFFF paragraphs are requested from DOS
  705.           naturally a fail will be returned, but more importantly the
  706.           amount available will also be returned. After determining that
  707.           there is sufficient to at least attempt the EXEC the program
  708.           can continue.
  709.           
  710.                Let's use the terms parent and child for the two
  711.           programs.  Once the EXEC is called the parent has no further
  712.           control over the operation of the child. All control must be
  713.           exercised through the information passed in the parameter
  714.           block.  You can tailor the environment block, specify the
  715.           command tail, and point the 2 FCB's if the program uses them.
  716.           If the program doesn't use them you can just point them to 5CH
  717.           and 6CH of the parent's PSP(The segment address is supplied by
  718.           DOS in ES and DS after the parent is loaded).
  719.           
  720.                I am including a short program that does nothing except
  721.           EXEC according to your instructions.  With some playing around
  722.           it should be a good introductory tool.  A sample program name
  723.           and command tail are included, but these you will want to
  724.           change.
  725.           
  726.                Some of the code in there is unnecessary, but may make it
  727.           easier to customize or illustrates some point. With relatively
  728.           small changes this could be included in another program to
  729.           serve as an exec subroutine.  The source is compatible with
  730.           both MASM and A86.
  731.  
  732.  
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749.  
  750.  
  751.  
  752.  
  753.                                         12
  754.  
  755.  
  756.  
  757.  
  758.  
  759.           
  760.                                       TSR's
  761.                          How to get user input, Part Two
  762.                        (along with lotsa other neat stuff)
  763.                                  by David O'Riva
  764.                                          
  765.                This article is a multi-part package, all rolled into one
  766.           month, mainly because a good deal of it comes in one chunk:
  767.           How to write a well-behaved TSR. For those of you who aren't
  768.           quite sure what a TSR really is, a short definition follows.
  769.           
  770.                TSR, n, 1. Terminate and Stay Resident.   2. A program or
  771.           routine that, after being loaded, carves a niche of memory for
  772.           itself and holes up there, only showing itself when a certain
  773.           circumstance occurs.  This is what is meant by"serially
  774.           multitasking."  You press a "hotkey", and for some length of
  775.           time the program you were working on is subjugated to the
  776.           background, and the TSR gets to use the computer.
  777.                          3. A real pain to write.
  778.           
  779.                TSR'S have numerous uses:  print spoolers, expanded
  780.           keyboard buffers, text editors, directory manipulators,
  781.           background disk formatters, display managers, background file
  782.           transferors - anything you may want to do while you're in the
  783.           middle of another application.
  784.                TSR's usually have the following basic structure
  785.           (depending on what they do):
  786.           
  787.                   jump to initialization
  788.           
  789.                   main body of resident code
  790.           
  791.                   keyboard interrupt interceptor
  792.           
  793.                   timer tick interceptor
  794.           
  795.                   DOS console interceptor
  796.           
  797.                   un-installation routine
  798.           
  799.                   initialization code
  800.           
  801.           
  802.                An explanation of each of these follows:
  803.           
  804.           
  805.                                Initialization Code
  806.           
  807.                The initialization code must check to see if the TSR is
  808.           already resident in memory (aborting if so), hook all of the
  809.           interrupt servers into their respective chains, perform any
  810.           other tasks necessary to install the program, then deallocate
  811.           all unused memory and exit to DOS with a TSR call.
  812.           
  813.  
  814.  
  815.  
  816.                                         13
  817.  
  818.  
  819.  
  820.  
  821.  
  822.                To determine whether or not a copy of the TSR is already
  823.           resident, you could assign an unused interrupt to it.  The
  824.           example uses INT 69H, function ABCD hex.  If the example is
  825.           already installed, it returns with DCBA hex in AX.
  826.           
  827.                This "residency check" interrupt could also handle
  828.           functions for the TSR:  i.e. if the TSR was a print
  829.           spooler,and there was no "hot key" code written for it (like
  830.           the DOS PRINT command), then the program could call INT 69H
  831.           with function AB00H to add a file to the print queue.
  832.           
  833.                To hook an interrupt into a chain, you must replace the
  834.           appropriate vector with a pointer to your interrupt server,
  835.           and your interrupt server must jump to or call the code that
  836.           the vector used to point to.  Failure to do this caused many
  837.           early TSR's to refuse to co-habit with other TSR's,
  838.           occasionally making the machine bomb, etc...  Unless you have
  839.           a very good reason, ALWAYS continue the interrupt chain.
  840.           
  841.                Two TSR exits are available:  The first is INT 27H,which
  842.           has some limitations (only 64K of your program can remain
  843.           resident, which shouldn't be too onerous), and which Microsoft
  844.           does not recommend for anything except DOS 1.  The second is
  845.           INT 21H function 31H, which allows up to a meg to remain
  846.           resident (right) and allows you to send a return code back to
  847.           the caller.
  848.           
  849.                The initialization code usually de-allocates itself upon
  850.           exiting.
  851.           
  852.           
  853.                           Keyboard Interrupt Interceptor
  854.           
  855.                This is only required for programs that wish to pop up
  856.           when the hot key is pressed or wish to monitor the keyboard
  857.           for some other reason.  Much of what they have to do was
  858.           discussed last month, with two exceptions.
  859.           
  860.                The first is how to prevent a keystroke from reaching the
  861.           BIOS code without leaving the keyboard locked up.  To do this,
  862.           you have to tell the keyboard that you received the character,
  863.           then reset the interrupt controller and exit (without chaining
  864.           to the next interrupt.)  The keyboard is cleared by toggling
  865.           bit 7 of port 61H on, then off.  The interrupt controller is
  866.           cleared by sending an EOI(End Of Interrupt) code 20H to the
  867.           8259 at port 20H (weird,huh?).  At that point you should do an
  868.           IRET.
  869.           
  870.                The second is the necessity of monitoring the InDOS flag.
  871.           Note that YOU ONLY HAVE TO DO THIS IF YOUR TSR USES DOS
  872.           FUNCTIONS.  Also note that this flag is NOT documented by IBM
  873.           OR Microsoft, and that it is not strictly "compatible."
  874.           
  875.  
  876.  
  877.  
  878.  
  879.                                         14
  880.  
  881.  
  882.  
  883.  
  884.  
  885.                The address of the InDOS flag can be acquired by a call
  886.           to INT 21H function 34H.  The flag is non-zero if a DOS
  887.           function is currently active.  You need this flag because DOS
  888.           is not re-entrant.  That is, if you call DOS from your TSR,and
  889.           DOS was active when the TSR gained control, the TSR will work
  890.           fine, but when you return from it, the function in progress
  891.           will have lost its entire stack and much of its data area.
  892.           Nasty stuff.
  893.           
  894.                If the InDOS flag is set when the keyboard trap is
  895.           activated, the keyboard trap should set a flag saying "I want
  896.           to activate but I can't" and return.
  897.           
  898.           
  899.                               Timer Tick Interceptor
  900.           
  901.                These are always fun.  18.2 times per second, you get
  902.           control of the machine.  This is useful for print spoolers,
  903.           resident screen clocks, and TSR'S that need to perform DOS
  904.           functions.
  905.           
  906.                In the last case, the timer tick trap should check to see
  907.           if the TSR wants to activate, and if so whether the InDOS flag
  908.           is set.  If the InDOS flag is clear, then the TSR can be
  909.           activated.
  910.           
  911.           
  912.                              DOS Console Interceptor
  913.           
  914.                This interrupt (INT 28H) is called by DOS whenever a DOS
  915.           console function is in progress.  This is useful to have
  916.           because during a console input, the InDOS flag is set, but it
  917.           is actually safe to use any DOS function ABOVE 0CH.
  918.           
  919.                This trap should check to see if the TSR wants to
  920.           activate, and if so then activate it.
  921.           
  922.           
  923.                                Main Body of the TSR
  924.           
  925.                The only requirement for this is that if you use more
  926.           than two words (yes, this is an arbitrary measure that seems
  927.           safe to me) of stack, you should use your internal stack
  928.           instead of the one that you were called with.  This is because
  929.           you have no idea how large the stack you're working on is, and
  930.           no way of telling how far you can go before you start to
  931.           overwrite data...
  932.           
  933.           
  934.                            The Un-Installation routine
  935.           
  936.                This is a very nice thing to have.  The only problem is
  937.           that it needs to use a DOS call to de-allocate its memory.
  938.  
  939.  
  940.  
  941.  
  942.                                         15
  943.  
  944.  
  945.  
  946.  
  947.  
  948.           Unless, of course, you want to directly modify the memory
  949.           control blocks... which could be very dangerous.
  950.           
  951.                The routine in the example TSR does check the memory
  952.           control block immediately after it to make sure that there are
  953.           no programs installed in memory after the TSR.  DOS gets upset
  954.           when there are "holes" in memory.  At least, it's supposed to.
  955.           The structure included for the MCB is complete as far as I
  956.           know, but it is also *extremely* undocumented.  Microsoft
  957.           calls it an "arena header" and tells programmers to keep their
  958.           hands off of it.
  959.                All vectors must be unhooked.
  960.           
  961.                The DOS calls to de-allocate the memory are necessary.
  962.           
  963.           
  964.                            Neat tricks you can pull...
  965.           
  966.                The command line area in the PSP makes for a convenient
  967.           40 word internal stack.  If you aren't using the FCBS, the FCB
  968.           storage area can be commandeered as well.
  969.           
  970.                The environment segment's size can be checked (with a
  971.           look at the MCB) and that can be used for stack, data or code
  972.           as well.
  973.           
  974.           
  975.           The Example TSR
  976.           
  977.                As far as actual use goes, the example TSR is a very
  978.           simple beast.  When resident, press LSHIFT-RSHIFT-T (it'll
  979.           beep).  Then press "Q" to return to normal processing, or
  980.           press "N" to Nuke the TSR (remove it from memory).  If it
  981.           cannot remove itself, it will beep three times.
  982.           
  983.                Well, that's about all there is to it.  With all these
  984.           routines (or at least the ones you need) combined in one
  985.           cohesive package, you have a full-fledged TSR skeleton. The
  986.           example TSR includes most of these techniques.  Use and enjoy.
  987.           Comments on this article, or expansions on the subject matter
  988.           are greatly appreciated and will be published in later issues
  989.           of the magazine.
  990.  
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004.  
  1005.                                         16
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011.           
  1012.           
  1013.                           Book Reviews by Patrick O'Riva
  1014.           
  1015.           
  1016.           
  1017.           PROGRAMMER'S TECHNICAL REFERENCE FOR MSDOS AND THE IBM PC
  1018.                By Dave Williams P.O. box 181, Jacksonville, AR 72087
  1019.           
  1020.                This is a first glance review that I wanted to get into
  1021.           this month's issue.  It is a user supported book on disk.  I
  1022.           haven't had the time to read through it, but it appears to be
  1023.           one of the best available in any format.  In compressed form
  1024.           it is over 200k, and expands to over 500k.  It is very
  1025.           complete and includes some hard to find tables and version
  1026.           histories.  Requested $15 support includes 2 additional disks
  1027.           and updates.  Probably one of the best buys around.
  1028.           
  1029.                It is available on various BBS's (AsmLang included)
  1030.           though its 200k+ size makes for slow distribution.  The
  1031.           complete package direct from the author is probably best.
  1032.           
  1033.           
  1034.           IBM Technical Reference- Personal Computer XT
  1035.           
  1036.                This comes in the standard binder/box and is available
  1037.           from IBM corporation at a hefty $50. In addition to some
  1038.           information on port assignments and memory maps it contains
  1039.           two sets of information that I have found nowhere else.
  1040.           
  1041.                A complete listing of the ROM BIOS for the XT that is
  1042.           invaluable as both an example of programming each piece of
  1043.           hardware and clues as to how to optimize for a specific
  1044.           application.
  1045.           
  1046.                Complete schematics of the motherboard of the XT that can
  1047.           help to explain why something won't work if you are
  1048.           technically inclined.
  1049.           
  1050.                I have found it invaluable, but it is not for everyone.
  1051.                Similar publications are available for the other IBM
  1052.           products and for the PCDOS.
  1053.                For further information contact IBM at 1-800-426-7282
  1054.  
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066.  
  1067.  
  1068.                                         17
  1069.  
  1070.  
  1071.  
  1072.  
  1073.  
  1074.           
  1075.           
  1076.                                 Program Spotlight
  1077.                                Exceptional Programs
  1078.           
  1079.                This is really a nonexistent column this month as nothing
  1080.           new has come to my notice that meets the qualifications of
  1081.           high speed and small size.
  1082.           
  1083.                There is a nice piece of source code available under the
  1084.           name of CRC16 that calculates and verifies 16 bit CRC values.
  1085.           If this meets a need of yours keep a look out for it.
  1086.           
  1087.                Although I haven't tried it out yet, a program called the
  1088.           Brand X symbolic debugger has been highly recommended to me.
  1089.           Other comments would be welcomed.
  1090.           
  1091.                QFILE31G handles copying, deleting and moving files, as
  1092.           well as maintaining and listing ARC's and ZIP's. Nicely done,
  1093.           but too slow and too large to really fit here, and hangs up on
  1094.           some error conditions.
  1095.           
  1096.                WHIZ1 a file finding program certainly qualifies in speed
  1097.           as a multi disk search with wild card only takes a few
  1098.           seconds.  It is a bit larger than it might be, but at the
  1099.           least it is enhanced with assembly routines. It is a shareware
  1100.           offering and is widely available.
  1101.  
  1102.  
  1103.  
  1104.  
  1105.  
  1106.  
  1107.  
  1108.  
  1109.  
  1110.  
  1111.  
  1112.  
  1113.  
  1114.  
  1115.  
  1116.  
  1117.  
  1118.  
  1119.  
  1120.  
  1121.  
  1122.  
  1123.  
  1124.  
  1125.  
  1126.  
  1127.  
  1128.  
  1129.  
  1130.  
  1131.                                         18
  1132.  
  1133.  
  1134.  
  1135. ;Ed -This is the source code on FASTPRINT
  1136.         jmp     install ; This will be a .COM
  1137.  
  1138. db cr, '   ', cr, lf     ; On most displays, if this file is TYPEed,
  1139.                ; these 3 spaces will erase
  1140.                ; the 3 characters in the JMP instruction above.
  1141. message0:
  1142.      db   'FASTPRIN 0.0 Copyright 1989 by Dennis Yelle,'
  1143.      db   ' PO Box 62276, Sunnyvale CA 94088'
  1144.      db   cr, lf
  1145. message0_len = $ - message0
  1146.      db   'Last change:  Mar 4, 1989', cr, lf
  1147.  
  1148. db 26     ; This 26 is a control-Z, the DOS EOF character.
  1149.      ; I put it here so that if someone TYPEs this .COM file,
  1150.      ; only the characters before the 26 will be printed on the screen.
  1151.  
  1152. id_size = $ - 0100
  1153.  
  1154. ;    To assemble this program, put the source in a file called
  1155. ;    FASTPRIN.8 and then type
  1156. ;    A86 FASTPRIN.8
  1157. ;    This will produce a file called FASTPRIN.COM directly,
  1158. ;    in about 2 seconds!  No need to run a linker!
  1159. ;    The program A86.COM is available from many BBSs in an .ARC file
  1160. ;    that starts with A86.
  1161. ;    In particular, A86.COM is available from the "AsmLang and CFS" BBS
  1162. ;    (Opus 1:143/37) 408-259-2223 in the file A86V319A.ZIP.
  1163. ;    Or HomeBase 408-988-4004 in the file A86V309A.ARC.
  1164. ;    Or PDSE     408-745-0880 in the file A86V314A.ARC.
  1165. ;
  1166. ;    FASTPRIN installs a TSR which speeds up the printing done by the
  1167. ;    DOS PRINT command by calling INT 02FH with AX = 0080H whenever the
  1168. ;    system is idle.  We know the system is idle whenever:
  1169. ;
  1170. ;    1. INT 016 is called with AH = 0 and there are no characters in
  1171. ;       the keyboard buffer.  or
  1172. ;    2. INT 015 is called with AH = 090.  This will only happen on an AT.
  1173. ;
  1174. ;    Termination codes:
  1175. ;         0 - Successfully installed.
  1176. ;         1 - Unable to determine if already installed, installed anyway.
  1177. ;         2 - Already installed.
  1178. ;
  1179. ;    If this program has been helpful to you, then please send a
  1180. ;    small gift to the author, Dennis Yelle, PO Box 62276,
  1181. ;    Sunnyvale, CA  94088.  A gift of $10 is suggested.
  1182.  
  1183. cr = 0d
  1184. lf = 0a
  1185.  
  1186.      even
  1187. old_int_15 dw 2 dup (?)
  1188. old_int_16 dw 2 dup (?)
  1189.  
  1190. get_vect macro
  1191.      push es
  1192. #rx1l
  1193.      mov  ax, 03500 + 0#x
  1194.  
  1195.  
  1196.      int  021
  1197.      mov  old_int_#x, bx
  1198.      mov  old_int_#x[2], es
  1199. #er
  1200.      pop  es
  1201. #em
  1202.  
  1203. set_vect macro
  1204. #rx1l
  1205.      mov  dx, offset new_int_#x
  1206.      mov  ax, 02500 + 0#x
  1207.      int  021
  1208. #er
  1209. #em
  1210.  
  1211. new_int_16:
  1212.      pushf
  1213.      sti
  1214.      test ah,ah
  1215.      jz   wait_16
  1216.      popf
  1217.      jmp  cs: d old_int_16
  1218.  
  1219. wait_16_loop:
  1220.      mov  ax, 0080
  1221.      int  02f       ; Do some printing.
  1222. wait_16:
  1223.      mov  ah, 1
  1224.      int  016       ; Are any chars ready?
  1225.      jz   wait_16_loop   ; Jump if not.
  1226.      mov  ah, 0
  1227.      popf
  1228.      jmp  cs: d old_int_16
  1229.  
  1230. new_int_15:
  1231.      pushf
  1232.      sti
  1233.      cmp  ah, 090
  1234.      je   idle
  1235.      popf
  1236.      jmp  cs: d old_int_15
  1237.  
  1238. idle:
  1239.      push ax
  1240.      mov  ax, 0080
  1241.      int  02f       ; Do some printing.
  1242.      pop  ax
  1243.      popf
  1244.      jmp  cs:d old_int_15
  1245.  
  1246. end_of_resident:
  1247. ;---------------------------------------------------------
  1248.  
  1249. install:
  1250.      mov  ah, 040
  1251.      mov  bx, 1          ; Write to stdout
  1252.      mov  dx, message0
  1253.      mov  cx, message0_len
  1254.      int  021
  1255.      mov  ah, 052
  1256.  
  1257.  
  1258.      int  021
  1259.      mov  ax, es:[bx-2]
  1260.      mov  dx, ds
  1261.      dec  dx
  1262.      cld
  1263. find:
  1264.      cmp  ax, dx
  1265.      je   install_it
  1266.      ja   mem_bad
  1267.      mov  es, ax
  1268.      mov  si, 0100
  1269.      mov  di, 0110
  1270.      mov  cx, id_size/2
  1271.      repe cmpsw
  1272.      je   already_installed
  1273.      stc
  1274.      adc  ax, es:[3]
  1275.      jnc  find
  1276. mem_bad:  
  1277.      mov  w installed_msg, mem_bad_msg
  1278.      inc  b term_code
  1279. install_it:
  1280.      get_vect 15, 16
  1281.      set_vect 15, 16
  1282.  
  1283.      mov  ah, 049
  1284.      mov  es, [02c]
  1285.      int  021       ; Free the ENV segment.
  1286.  
  1287.      mov  dx, installed_msg
  1288.      mov  ah, 9
  1289.      int  021       ; Print the INSTALLED message.
  1290.  
  1291.      mov  ah, 031
  1292.      mov  al, term_code
  1293.      mov  dx, (end_of_resident+15)/16
  1294.      int  021       ; Terminate and stay resident.
  1295. ;-------------------------------------------------------------
  1296.  
  1297. already_installed:
  1298.      mov  dx, ai_msg
  1299.      mov  ah, 9
  1300.      int  021       ; Print the message.
  1301.      mov  ax, 04c02
  1302.      int  021
  1303.  
  1304. installed: db 'FASTPRIN is now installed.', cr, lf, '$'
  1305.  
  1306. mem_bad_msg:
  1307. db 'FASTPRIN was unable to determine if it was previously installed, or not,'
  1308. db cr, lf,
  1309. db 'so it installed itself anyway.', cr, lf, '$'
  1310.  
  1311. ai_msg: db 'FASTPRIN was already installed.', cr, lf, '$'
  1312.  
  1313. installed_msg dw installed
  1314. term_code     db 0
  1315.  
  1316.  
  1317. ;THIS IS THE SOURCE CODE FOR THE EXEC FUNCTION ARTICLE
  1318. ;
  1319. ;THIS PROGRAM WITH FEW IF ANY SYNTAX CHANGES SHOULD BE COMPATIBLE WITH BOTH A86
  1320. ;AND MASM.
  1321. ;IT IS NOT DESIGNED TO BE A STAND ALONE PROGRAM OR EVEN USER FRIENDLY BUT A
  1322. ;BARE SHELL WITH WHICH TO PLAY AROUND WITH IN LEARNING TO USE THE DOS EXEC
  1323. ;FUNCTION
  1324. ;THE PROGRAM NAME SHOULD BE ENTERED BETWEEN THE QUOTE MARKS AT THE VARIABLE
  1325. ;-PROGRAM- AND ANY OTHER COMMAND LINE ARGUMENTS SHOULD BE ENTERED BETWEEN THE
  1326. ;QUOTE MARKS AT THE VARIABLE -COMMAND- BEFORE ASSEMBLY. MANY IMPROVEMENTS ARE
  1327. ;OBVIOUS, SUCH AS BEING ABLE TO ENTER THE NAMES AND ARGUMENTS FROM THE CONSOLE
  1328. ;BUT THESE ARE LEFT TO EXPERIMENTER.
  1329. ;THE ONE SOPHISTICATION IF YOU COULD CALL IT THAT IS THAT THE ERROR LEVEL OF
  1330. ;THE EXEC'D PROGRAM IS FETCHED, BUT NOTHING IS DONE WITH IT.
  1331. CODE SEGMENT 'CODE'
  1332. ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
  1333. org     0
  1334. PROG_ORG        LABEL   BYTE
  1335. org     0100
  1336. ENTRY:          JMP     START
  1337.  
  1338.  
  1339.                 db      32 DUP ('STACK   ')     ;THIS SETS ASIDE 256 BYTES-
  1340.                                                 ;REQUIRED DOS STACK
  1341. STAK            LABEL   BYTE                    ;THIS MARKS TOP OF STACK
  1342.  
  1343. THIS_SEG        DW      0               ;STORAGE FOR ADDRESS OF THIS SEGMENT
  1344.  
  1345. CTL_LEN         DW      0               ;THIS IS THE START OF THE *****
  1346. PROGRAM         DB      'c:\dos\list.com',0           ;ASCIIZ STRING OF PROGRAM TO
  1347. EXEC
  1348.  
  1349. CMDL            LABEL   BYTE            ;BEG ADDRESS OF COMMAND TAIL
  1350. CMDLEN          DB      0               ;OFFSET CR - OFFSET COMMAND
  1351. COMMAND         DB      'exec.asm'             ;THE COMMAND TAIL ITSELF
  1352. CR              DB      0DH             ;TERMINATING CARRIAGE RETURN
  1353.  
  1354. PARMS           LABEL   BYTE            ;ADDRESS OF PARAMETER TABLE
  1355.  ENV            DW      0               ;POINTER TO ENVIRONMENT BLOCK
  1356.                                         ;0 DEFAULTS TO PARENT
  1357.  CMDLNLOW       DW      0               ;OFFSET OF COMMAND TAIL
  1358.  CMDLNHI        DW      0               ;SEGMENT OF COMMAND TAIL
  1359.  FCB11          DW      0               ;OFFSET  OF FCB1
  1360.  FCB12          DW      0               ;SEGMENT OF FCB1
  1361.  FCB21          DW      0               ;OFFSETT OF FCB2
  1362.  FCB22          DW      0               ;SEGMENT OF FCB2
  1363. MS1             DB      'DEALLOCATION ERROR',0DH,'$' ;MESSAGE #1
  1364. MS2             DB      'EXEC ERROR',0DH,'$'         ;MESSAGE #2
  1365. START:
  1366.                 CLI                     ;TURN OFF INTERRUPTS WHILE SWITCHING
  1367.                                         ;STACK FRAMES
  1368.                 MOV     SP,OFFSET STAK  ;POINT STACK WHERE WE WANT IT
  1369.                 STI                     ;INTS OK NOW
  1370.                 MOV     AX,DS           ;BEING A COM PROGRAM DS CONTAINS THIS
  1371.                                         ;SEGMENT
  1372.                 MOV     THIS_SEG,AX     ;PUT IT WHERE WE CAN GET IT EASILY
  1373. RESIZE:
  1374.                 MOV     BX,(OFFSET PROG_END - OFFSET PROG_ORG)  ;FIND OUT
  1375.                                         ;HOW BIG THE PROGRAM IS
  1376.                 MOV     CL,4            ;TURN THIS VALUE INTO PARAGRAPHS
  1377.  
  1378.  
  1379.                 SHR     BX,CL
  1380.                                         ;
  1381.                 INC     BX              ;NEEDS 1 MORE TO CATCH OVERFLOW
  1382.                 MOV     AH,04AH         ;ASK FOR DEALLOCATION OF ALL BUT THIS
  1383.                 INT     021H
  1384.                 JNC     S1              ;IF CARRY BAD PROBLEM
  1385.                 MOV     AX,OFFSET MS1   ;POINT AX AT MESSAGE 1
  1386.                 JMP     END_ERROR       ;NOW LEAVE
  1387. S1:
  1388.                                 ;AN ASSUMPTION IS MADE AT THIS POINT, THAT
  1389.                                 ;THERE IS ENOUGH MEMORY FOR THE PROGRAM TO BE
  1390.                                 ;EXEC'D TO OPERATE IN. IF NOT AN EXEC ERROR
  1391.                                 ;WILL BE RETURNED.
  1392.  
  1393.                 MOV     AX,OFFSET CR    ;FIND LENGTH OF COMMAND TAIL
  1394.                 SUB     AX,OFFSET CMDL  ;AND
  1395.                 MOV     CMDLEN,AL       ;PUT IT IN CMDLEN
  1396.                 MOV     DX,OFFSET CMDL  ;FILL IN THE COMMAND TAIL POINTER IN
  1397.                                         ;THE PARAMETER BLOCK
  1398.                 MOV     CMDLNLOW,DX
  1399.                 MOV     CMDLNHI,DS
  1400.                 MOV     DX,OFFSET PROGRAM ;POINT DX AT PROGRAM NAME
  1401.                 MOV     ES,THIS_SEG     ;MAKE SURE ES IS POINTING AT THIS SEG
  1402.                 MOV     BX,OFFSET PARMS ;POINT BX AT PARAMETER BLOCK
  1403.                 MOV     AX,05CH         ;THIS IS OFFSET OF PARENT FCB1 BUT
  1404.                                         ;COULD BE ANY INFO DESIRED TO PASS TO
  1405.                                         ;CHILD THAT WOULD BE LOOKED FOR AT PSP
  1406.                                         ;5CH
  1407.                 MOV     FCB11,AX        ;PUT IT IN PARAMETER BLOCK
  1408.                 MOV     FCB12,ES        ;DESIRED SEGMENT OF FCB1 DATA
  1409.                 MOV     AX,06CH         ;FILL IN FCB2. ABOVE COMMENTS APPLY
  1410.                 MOV     FCB21,AX
  1411.                 MOV     FCB22,ES
  1412.                 MOV     AH,04BH         ;THE EXEC FUNCTION
  1413.                 MOV     AL,0            ;LOAD AND EXECUTE
  1414. PREX:
  1415.                 INT     021H            ;DOS
  1416.                 JNC     FINISHED        ;ALL ACCORDING TO PLAN
  1417.                 MOV     AX,OFFSET MS2   ;SOMETHING WRONG IN EXEC
  1418.                 JMP     SHORT END_ERROR
  1419. FINISHED:
  1420.                 MOV     AH,04DH         ;TO REACH HERE THE CHILD MUST HAVE
  1421.                                         ;TERMINATED. THIS REQUESTS THE
  1422.                                         ;TERMINATION CODE
  1423.                 INT     021H            ;DOS TERMINATION CODE RETURNED IN AH
  1424.                                         ;CHILD'S AL PASSED THROUGH
  1425.                 MOV     AH,04CH         ;TERMINATE THIS PROG
  1426.                 INT     021H
  1427. END_ERROR:
  1428.                 MOV     DX,AX           ;SAVE THE MESSAGE ADDRESS TO DX
  1429.                 MOV     BX,1            ;DEVICE HANDLE IS CONSOLE
  1430.                 MOV     CX,20           ;20 BYTES IS ENOUGH FOR THE MESSAGE
  1431.                 MOV     AH,040H         ;WRITE TO DEVICE (CONSOLE)
  1432.                 INT     021H            ;DOS
  1433.                 MOV     AH,04CH         ;TERMINATE THIS PROGRAM
  1434.                 INT     021H
  1435.  
  1436. PROG_END        LABEL   BYTE
  1437. CODE            ENDS
  1438.                 END     ENTRY
  1439.  
  1440.  
  1441.                 PAGE    60,132
  1442.                 TITLE   EXMPLTSR.ASM - An example of a TSR program
  1443.  
  1444. COMMENT~*********************************************************************
  1445. *        --++**> This file is Copyright 1989 by David O'Riva <**++--        *
  1446. *****************************************************************************
  1447. *                                                                           *
  1448. * Written for the Microsoft Macro Assembler version 5.1, DOS v2.0 - 3.3     *
  1449. *                                                                           *
  1450. * MUST BE CONVERTED INTO A .COM FILE BEFORE RUNNING!!!                      *
  1451. *                                                                           *
  1452. *       Anyone who wants to incorporate this code into their programs is    *
  1453. * welcome to, as long as they don't try to sell this file as it is or any   *
  1454. * unmodified piece of it, and leave this message in when distributing it.   *
  1455. * If you do not abide by the rules, poltergeists will invade your home      *
  1456. * and chain letters and junk mail will arrive by the ton.                   *
  1457. *                                                                           *
  1458. *                                                                           *
  1459. *                  Short advertisement - use QEdit!                         *
  1460. *           Available on your local friendly Bulletin Board                 *
  1461. *                                                                           *
  1462. ****************************************************************************~
  1463. .XLIST
  1464. ;
  1465. ; Macros used by this program
  1466. ;
  1467.  
  1468. ?PLevel         =       0
  1469.  
  1470. PNPROC          MACRO   PNAME           ;;declare near public procedure
  1471.                 IF2
  1472.                 %OUT    Routine: &PNAME
  1473.                 ENDIF
  1474.                 PUBLIC  &PNAME
  1475. &PNAME          PROC    NEAR
  1476. ?PLevel         =       ?PLevel+1       ;;next level of nesting
  1477. @@SAVE_NAME     &PNAME,%?PLevel
  1478.                 ENDM
  1479.  
  1480. PFPROC          MACRO   PNAME           ;;declare near public procedure
  1481.                 IF2
  1482.                 %OUT    Routine: &PNAME
  1483.                 ENDIF
  1484.                 PUBLIC  &PNAME
  1485. &PNAME          PROC    FAR
  1486. ?PLevel         =       ?PLevel+1       ;;next level of nesting
  1487. @@SAVE_NAME     &PNAME,%?PLevel
  1488.                 ENDM
  1489.  
  1490. ENDPROC         MACRO
  1491. @@REC_NAME      %?PLevel
  1492. @@EP1           %@@TEMP
  1493. ?PLevel         =       ?PLevel-1
  1494.                 ENDM
  1495.  
  1496. @@SAVE_NAME     MACRO   PNAME,LVL
  1497. ?PN&LVL         EQU     <&PNAME>
  1498.                 ENDM
  1499.  
  1500.  
  1501.  
  1502. @@REC_NAME      MACRO   LVL
  1503. @@TEMP          EQU     <?PN&LVL>
  1504.                 ENDM
  1505.  
  1506. @@EP1           MACRO   PNAME
  1507. &PNAME          ENDP
  1508.                 ENDM
  1509.  
  1510. PUSHM           MACRO   LST
  1511. IRP             REG,<&LST&>
  1512.                 PUSH    REG
  1513.                 ENDM
  1514.                 ENDM
  1515.  
  1516. POPM            MACRO   LST
  1517. IRP             REG,<&LST&>
  1518.                 POP     REG
  1519.                 ENDM
  1520.                 ENDM
  1521.  
  1522. UPCASE          MACRO   REG
  1523.                 LOCAL   NOUP
  1524.                 CMP     REG,'a'
  1525.                 JB      NOUP
  1526.                 CMP     REG,'z'
  1527.                 JA      NOUP
  1528.                 SUB     REG,'a'-'A'
  1529. NOUP:
  1530.                 ENDM
  1531.  
  1532. @CHANGE_VECT    MACRO   INUM,GARB,NEW,GARB2,SAVEAREA
  1533.                 MOV     AX,0
  1534.                 MOV     ES,AX
  1535.                 MOV     AX,ES:[INUM*4]
  1536.                 MOV     DX,ES:[INUM*4+2]
  1537.                 MOV     WPTR CS:[SAVEAREA],AX
  1538.                 MOV     WPTR CS:[SAVEAREA+2],DX
  1539.                 MOV     AX,OFFSET CS:NEW
  1540.                 CLI
  1541.                 MOV     ES:[INUM*4],AX
  1542.                 MOV     ES:[INUM*4+2],CS
  1543.                 STI
  1544.                 ENDM
  1545.  
  1546. @RESTORE_VECT   MACRO   INUM,GARB,SAVEAREA
  1547.                 MOV     AX,WPTR CS:[SAVEAREA]
  1548.                 MOV     DX,WPTR CS:[SAVEAREA+2]
  1549.                 CLI
  1550.                 MOV     DS:[INUM*4],AX
  1551.                 MOV     DS:[INUM*4+2],DX
  1552.                 STI
  1553.                 ENDM
  1554.  
  1555. BPTR            EQU     <BYTE PTR>
  1556. WPTR            EQU     <WORD PTR>
  1557. DPTR            EQU     <DWORD PTR>
  1558. CR              EQU     <13>
  1559. LF              EQU     <10>
  1560. JR              EQU     <JMP     SHORT>
  1561.  
  1562.  
  1563. FALSE           EQU     <000H>
  1564. TRUE            EQU     <0FFH>
  1565.  
  1566. INT_CTRL        EQU     020H    ;Interrupt control port
  1567. EOI             EQU     020H    ;Reset interrupt controller command
  1568. KB_DATA         EQU     060H    ;Keyboard data port
  1569. KB_CTRL         EQU     061H    ;Keyboard control port
  1570. ;
  1571. ;****************************************************************************
  1572. ;
  1573. BIOSDATA        SEGMENT AT 00040H
  1574.  
  1575. ;----------------------------------------------------------------------------
  1576. ;Keyboard Data Area
  1577. ;----------------------------------------------------------------------------
  1578.                 ORG     00017H
  1579. KB_FLAG         LABEL   BYTE
  1580.  
  1581. ;----- Shift flag equates within KB_FLAG
  1582.  
  1583.         INS_STATE       EQU     80H     ;INSERT state is active
  1584.         CAPS_STATE      EQU     40H     ;CAPS LOCK state toggled
  1585.         NUM_STATE       EQU     20H     ;NUM LOCK state toggled
  1586.         SCROLL_STATE    EQU     10H     ;SCROLL LOCK state toggled
  1587.         ALT_SHIFT       EQU     08H     ;ALT key depressed
  1588.         CTRL_SHIFT      EQU     04H     ;CTRL key depressed
  1589.         LEFT_SHIFT      EQU     02H     ;left SHIFT key depressed
  1590.         RIGHT_SHIFT     EQU     01H     ;right SHIFT key depressed
  1591.  
  1592.                 ORG     00018H
  1593. KB_FLAG_1       LABEL   BYTE
  1594.  
  1595. ;----- Shift flag equates within KB_FLAG_1
  1596.  
  1597.         INS_SHIFT       EQU     80H     ;INSERT key depressed
  1598.         CAPS_SHIFT      EQU     40H     ;CAPS LOCK key depressed
  1599.         NUM_SHIFT       EQU     20H     ;NUM LOCK key depressed
  1600.         SCROLL_SHIFT    EQU     10H     ;SCROLL LOCK key depressed
  1601.         HOLD_STATE      EQU     08H     ;suspend key has been toggled
  1602.  
  1603.                 ORG     00019H
  1604. ALT_INPUT       LABEL   BYTE            ;storage for alternate keypad entry
  1605.  
  1606.                 ORG     0001AH
  1607. BUFFER_HEAD     LABEL   WORD            ;pointer to head of keyboard buffer
  1608.  
  1609.                 ORG     0001CH
  1610. BUFFER_TAIL     LABEL   WORD            ;pointer to tail of keyboard buffer
  1611.  
  1612.                 ORG     0001EH
  1613. KB_BUFFER       LABEL   WORD            ;keyboard buffer
  1614.  
  1615.                 ORG     0003EH
  1616. KB_BUFFER_END   LABEL   WORD
  1617.                                        ;
  1618. ;----- HEAD = TAIL indicates that the buffer is empty
  1619.  
  1620.         NUM_KEY         EQU     69      ;scan code for NUM LOCK
  1621.         SCROLL_KEY      EQU     70      ;sc for SCROLL LOCK
  1622.  
  1623.  
  1624.         ALT_KEY         EQU     56      ;sc for ALT key
  1625.  
  1626. BIOSDATA        ENDS
  1627.  
  1628. .list
  1629. .lall
  1630. ;
  1631. ;****************************************************************************
  1632. ;
  1633. CODE            SEGMENT PARA PUBLIC 'CODE'
  1634.                 ASSUME  CS:CODE,DS:CODE,ES:CODE,SS:CODE
  1635.  
  1636.                 ORG     02CH
  1637. ENVIRONMENTSEG  LABEL   WORD
  1638.  
  1639.                 ORG     100H
  1640. MAIN            PROC    FAR
  1641.  
  1642. STACKTOP:                               ;allow the stack to overwrite the
  1643.                                         ;command line in the PSP
  1644. ENTRY:          JMP     INSTALL
  1645.  
  1646. ;============================================================================
  1647. ;
  1648. ; MY LOCAL DATA
  1649. ;
  1650.  
  1651. MCBOVL          STRUC                   ;definition of DOS's memory control
  1652. ;                                       ;block structure
  1653. MCB_KIND        DB      ' '
  1654. MCB_PSP_ADDR    DW      0
  1655. MCB_LENGTH      DW      0
  1656. MCB_UNDEFINED   DB      11 DUP(?)
  1657. ;
  1658. MCBOVL          ENDS
  1659.  
  1660.   m@BLOCK       EQU     <'M'>           ;possible entries in the MCB_TYPE field
  1661.   m@LAST        EQU     <'Z'>
  1662.  
  1663. OLD9            DD      ?               ;old INT 09H vector
  1664. OLD08           DD      ?
  1665. OLD28           DD      ?
  1666. OLD69           DD      ?
  1667.  
  1668. InDOS           DD      ?               ;address of the InDOS flag
  1669. CODSEG          DW      ?               ;code segment
  1670.  
  1671. AllowPop        DB      FALSE           ;TRUE = the INT 09H server is allowed
  1672.                                         ;       to try to run the TSR.
  1673.  
  1674. TryPop          DB      FALSE           ;TRUE = The INT 09H server couldn't
  1675.                                         ;       run the TSR because DOS was
  1676.                                         ;       processing a command at the
  1677.                                         ;       time.
  1678.                                        ;
  1679. InPop           DB      FALSE           ;TRUE = the popped-up code is running
  1680.                                         ;       at the moment.
  1681.  
  1682. OLDSS           DW      ?               ;storage for stack frame information
  1683. OLDSP           DW      ?
  1684.  
  1685.  
  1686.  
  1687. PopShifts       DB      LEFT_SHIFT+RIGHT_SHIFT  ;shift state necessary for
  1688.                                                 ;  pop-up
  1689.  
  1690. PopKey          DB      14H             ;key # to press to pop up ('T')
  1691.  
  1692. ;============================================================================
  1693.  
  1694.  
  1695.                 PAGE
  1696. ;****************************************************************************
  1697. ; START - main program loop
  1698. ;
  1699. ;
  1700. ;     ENTRY:    from hot key
  1701. ;
  1702. ;      EXIT:    nothing
  1703. ;
  1704. ; DESTROYED:    none
  1705. ;
  1706. ;----------------------------------------------------------------------------
  1707. PNPROC          START
  1708.  
  1709. ;------------------------------------------------------------------------------
  1710. ; set up my stack frame
  1711. ;------------------------------------------------------------------------------
  1712.                 MOV     CS:OLDSS,SS
  1713.                 MOV     CS:OLDSP,SP
  1714.                 CLI
  1715.                 MOV     SS,CS:CODSEG
  1716.                 MOV     SP,OFFSET STACKTOP
  1717.                 STI
  1718.                 PUSH    AX
  1719.  
  1720. ;------------------------------------------------------------------------------
  1721. ; MAIN LOOP
  1722. ;------------------------------------------------------------------------------
  1723.                 CALL    BEEP
  1724. GETAKEY:
  1725.                 MOV     AH,0            ;get a key
  1726.                 INT     016H
  1727.                 UPCASE  AL
  1728.  
  1729.                 CMP     AL,'N'          ;'N' for NUKE THE TSR!
  1730.                 JNE     NOT_NUKE
  1731.  
  1732.                 CALL    UNLOAD          ;try to unload myself
  1733.                 JNC     LEAVE
  1734.                 CALL    BEEP            ;string of beeps if I can't
  1735.                 CALL    BEEP
  1736.                 CALL    BEEP
  1737.                 JMP     GETAKEY
  1738.  
  1739. NOT_NUKE:       CMP     AL,'Q'          ;'Q' for quit TSR
  1740.                 JE      LEAVE
  1741.                                        ;
  1742.                 CALL    BEEP            ;unrecognized key, complain
  1743.                 JMP     GETAKEY         ;... and get another
  1744.  
  1745. LEAVE:          POP     AX              ;recover * ALL * modified registers
  1746.  
  1747.  
  1748.                                         ;        -------
  1749. ;------------------------------------------------------------------------------
  1750. ; recover original stack frame
  1751. ;------------------------------------------------------------------------------
  1752.                 CLI
  1753.                 MOV     SS,CS:OLDSS
  1754.                 MOV     SP,CS:OLDSP
  1755.                 STI
  1756.  
  1757.                 RET
  1758. ENDPROC
  1759.  
  1760.  
  1761.                 PAGE
  1762. ;******************************************************************************
  1763. ; BEEP - Beeps the speaker
  1764. ;
  1765. ;
  1766. ;     ENTRY:    nothing
  1767. ;
  1768. ;      EXIT:    nothing
  1769. ;
  1770. ; DESTROYED:    none
  1771. ;
  1772. ;------------------------------------------------------------------------------
  1773. PNPROC          BEEP
  1774.  
  1775.                 PUSH    AX
  1776.                 PUSH    CX
  1777.                 MOV     AL,10110110B
  1778.                 OUT     043H,AL
  1779.                 MOV     AX,1000
  1780.                 OUT     042H,AL
  1781.                 MOV     AL,AH
  1782.                 OUT     042H,AL
  1783.  
  1784.                 IN      AL,061H
  1785.                 MOV     AH,AL
  1786.                 OR      AL,3
  1787.                 OUT     061H,AL
  1788.                 SUB     CX,CX
  1789.                 LOOP    $
  1790.                 MOV     AL,AH
  1791.                 OUT     061H,AL
  1792.                 POP     CX
  1793.                 POP     AX
  1794.                 RET
  1795. ENDPROC
  1796.  
  1797.  
  1798. ;                PAGE
  1799. ;;****************************************************************************
  1800. ;; REGISTERTOTEXT - Converts AL into ASCII hex digits in CS:[SI]
  1801. ;;
  1802. ;;       For debugging - uncomment this routine if you need it.
  1803. ;;                                    ;
  1804. ;;     ENTRY:    AL = register to translate
  1805. ;;               SI = place to put translated digits
  1806. ;;
  1807. ;;      EXIT:    AX = hex digits
  1808.  
  1809.  
  1810. ;;
  1811. ;; DESTROYED:    AX
  1812. ;;
  1813. ;;----------------------------------------------------------------------------
  1814. ;ASSUME ds:NOTHING,es:NOTHING
  1815. ;PNPROC          REGISTERTOTEXT
  1816. ;;----------------------------------------------------------------------------
  1817. ;; split AL into two nibbles
  1818. ;;----------------------------------------------------------------------------
  1819. ;                MOV     AH,AL
  1820. ;                SHR     AH,1
  1821. ;                SHR     AH,1
  1822. ;                SHR     AH,1
  1823. ;                SHR     AH,1
  1824. ;                AND     AL,0FH
  1825. ;;----------------------------------------------------------------------------
  1826. ;; convert AL into a hex digit
  1827. ;;----------------------------------------------------------------------------
  1828. ;                ADD     AL,'0'                  ;AL = actual digit
  1829. ;                CMP     AL,'9'
  1830. ;                JBE     R_1
  1831. ;                ADD     AL,'A'-'0'-10
  1832. ;;----------------------------------------------------------------------------
  1833. ;; convert AH into a hex digit
  1834. ;;----------------------------------------------------------------------------
  1835. ;R_1:            ADD     AH,'0'                  ;AH = actual digit
  1836. ;                CMP     AH,'9'
  1837. ;                JBE     R_2
  1838. ;                ADD     AH,'A'-'0'-10
  1839. ;;----------------------------------------------------------------------------
  1840. ;; store hex number in [SI]
  1841. ;;----------------------------------------------------------------------------
  1842. ;R_2:            MOV     CS:[SI],AH
  1843. ;                MOV     CS:[SI+1],AL
  1844. ;                RET
  1845. ;ENDPROC
  1846. ;
  1847.  
  1848.                 PAGE
  1849. ;****************************************************************************
  1850. ; TRAPPER9 - Intercepts the incoming keyboard scan code
  1851. ;
  1852. ;       Looks for the hot key in the incoming scan codes.  If found, it
  1853. ; check the InDOS flag to see if DOS is currently in the middle of something.
  1854. ; If not, the TSR code (at START) is invoked.  Otherwise, a flag is set and
  1855. ; control is passed back to DOS.
  1856. ;
  1857. ;     ENTRY:    from IRQ 1, machine state is ???
  1858. ;
  1859. ;      EXIT:    continues KB interrupt chain
  1860. ;
  1861. ; DESTROYED:    ALL PRESERVED
  1862. ;
  1863. ;----------------------------------------------------------------------------
  1864. ASSUME ds:BIOSDATA,es:NOTHING
  1865. PFPROC          TRAPPER9
  1866.                 PUSHM   <AX,BX,DS,ES>   ;save everthing I use
  1867.  
  1868.                 MOV     AX,SEG BIOSDATA ;DS-> BIOS's data seg
  1869.                 MOV     DS,AX
  1870.  
  1871.  
  1872. ;----------------------------------------------------------------------------
  1873. ; are we in the correct shift state?
  1874. ;----------------------------------------------------------------------------
  1875.                 MOV     AL,KB_FLAG      ;get current shift states
  1876.                 AND     AL,00FH         ;clean up the byte
  1877.                 CMP     AL,CS:PopShifts ;is it the right shift?
  1878.                 JNE     T_chainon       ;no, go to next handler
  1879.  
  1880.                 IN      AL,KB_DATA      ;Poll keyboard controller
  1881.                 MOV     BH,AL           ;save keypress
  1882.                 AND     AL,07FH         ;strip off the MAKE/BREAK bit
  1883.                 CMP     AL,CS:PopKey    ;is this our key?
  1884.                 JNE     T_ChainOn       ;If it's not our code, ignore it...
  1885. ;----------------------------------------------------------------------------
  1886. ; reset the keyboard controller
  1887. ;----------------------------------------------------------------------------
  1888.                 IN      AL,KB_CTRL      ;get multi-purpose control byte
  1889.                 MOV     AH,AL           ;save original value
  1890.                 OR      AL,080H         ;set "character recieved" bit
  1891.                 OUT     KB_CTRL,AL      ;send it
  1892.                 MOV     AL,AH           ;get original value back
  1893.                 OUT     KB_CTRL,AL      ;send it
  1894. ;------------------------------------------------------------------------------
  1895. ; what do we do with this key?
  1896. ;------------------------------------------------------------------------------
  1897.                 CMP     CS:AllowPop,FALSE ;Are we allowed to pop up now?
  1898.                 JE      T_ResetLeave    ;if not, exit here...
  1899.  
  1900.                 TEST    BH,080H         ;was it the BREAK code?
  1901.                 JZ      T_WasMake       ;no, go run the pop-up
  1902.                 JMP     T_ResetLeave    ;otherwise, ignore this code
  1903.  
  1904. T_WasMake:      MOV     CS:AllowPop,FALSE ;can't pop up again
  1905.  
  1906.                 PUSHM   <ES,BX>         ;check the InDOS flag...
  1907.                 LES     BX,CS:InDOS
  1908.                 CMP     BPTR ES:[BX],0
  1909.                 POPM    <BX,ES>
  1910.  
  1911.                 JNZ     T_InDOSnow      ;if in DOS, don't invoke TSR
  1912.  
  1913.                 MOV     AL,EOI          ;otherwise, set interrupts on...
  1914.                 OUT     INT_CTRL,AL
  1915.                 MOV     CS:InPop,TRUE   ;...set a flag...
  1916.                 STI
  1917.                 CALL    START           ;...and run the TSR.
  1918.                 CLI
  1919.                 MOV     CS:AllowPop,TRUE
  1920.                 MOV     CS:InPop,FALSE
  1921.                 JMP     T_Leave
  1922.  
  1923. T_InDOSnow:     MOV     CS:TryPop,TRUE  ;DOS call in progress, try later...
  1924.                                        ;
  1925. T_ResetLeave:   MOV     AL,EOI          ;enable the KB interrupt again
  1926.                 OUT     020H,AL
  1927. T_Leave:        POPM    <ES,DS,BX,AX>   ;throw away this key code
  1928.                 IRET
  1929. ;----------------------------------------------------------------------------
  1930. ; Continue down the KB handler chain...
  1931. ;----------------------------------------------------------------------------
  1932.  
  1933.  
  1934. T_chainon:      POPM    <ES,DS,BX,AX>
  1935.                 JMP     DWORD PTR CS:OLD9
  1936. ENDPROC
  1937.  
  1938.  
  1939.  
  1940.                 PAGE
  1941. ;******************************************************************************
  1942. ; TRAPPER08 - Intercepts the timer tick to try to pop up the TSR
  1943. ;
  1944. ;       Upon being called, this routine determines whether:
  1945. ;               a) the TSR wants to pop up, and
  1946. ;               b) there is no DOS call in progress
  1947. ;       If these are BOTH true, then the TSR is invoked from here.
  1948. ;
  1949. ;       NOTE: Technically, you are supposed to trap vector 1CH for timer
  1950. ; ticks instead of INT 08, but some BIOSes do not issue an EOI for the timer
  1951. ; until AFTER 1C is called, and you don't want to mess up the system clock...
  1952. ;
  1953. ;     ENTRY:    on timer tick
  1954. ;
  1955. ;      EXIT:    nothing
  1956. ;
  1957. ; DESTROYED:    ALL PRESERVED
  1958. ;
  1959. ;------------------------------------------------------------------------------
  1960. PFPROC          TRAPPER08
  1961. ASSUME ds:NOTHING,es:NOTHING
  1962.  
  1963.                 PUSHF
  1964.                 CALL    DWORD PTR CS:[OLD08]
  1965.  
  1966.                 CLI
  1967.  
  1968.                 CMP     CS:TryPop,FALSE ;Are we trying to pop up?
  1969.                 JE      C_OUT           ;if not, leave now
  1970.  
  1971.                 PUSHM   <ES,BX>         ;Is a DOS call in progress?
  1972.                 LES     BX,CS:InDOS
  1973.                 CMP     BPTR ES:[BX],0
  1974.                 POPM    <BX,ES>
  1975.  
  1976.                 JE      C_Invoke        ;if not, then fire it up...
  1977.  
  1978. C_OUT:          IRET
  1979.  
  1980. C_Invoke:       MOV     CS:TryPop,FALSE ;set the right flags...
  1981.                 MOV     CS:InPop,TRUE
  1982.                 STI
  1983.                 CALL    START           ;run the TSR...
  1984.                 MOV     CS:InPop,FALSE  ;set some more flags...
  1985.                 MOV     CS:AllowPop,TRUE
  1986.                                        ;
  1987.                 IRET                    ;and leave.
  1988. ENDPROC
  1989.  
  1990.  
  1991.                 PAGE
  1992. ;******************************************************************************
  1993. ; TRAPPER28 - Intercepts the DOS "console wait" loop
  1994.  
  1995.  
  1996. ;
  1997. ;       This routine allows the TSR to be invoked during DOS console operations
  1998. ; where the InDOS flag is set but it is actually safe to use any DOS function
  1999. ; above 0CH.
  2000. ;
  2001. ;     ENTRY:    During DOS console operations
  2002. ;
  2003. ;      EXIT:    nothing
  2004. ;
  2005. ; DESTROYED:    ALL PRESERVED
  2006. ;
  2007. ;------------------------------------------------------------------------------
  2008. ASSUME ds:NOTHING,es:NOTHING
  2009. PFPROC          TRAPPER28
  2010.  
  2011.                 CMP     CS:TryPop,FALSE ;does the TSR want to pop up?
  2012.                 JE      C1_OUT          ;if not, get out of here now
  2013.                 MOV     CS:TryPop,FALSE ;prevent re-entrant interrupts
  2014.                 MOV     CS:InPop,TRUE   ;set the "in TSR" flag
  2015.                 STI
  2016.                 CALL    START           ;run it!
  2017.                 CLI
  2018.                 MOV     CS:AllowPop,TRUE;finished, we can pop up again
  2019.                 MOV     CS:InPop,FALSE  ;no longer running the TSR
  2020. C1_OUT:         JMP     DWORD PTR CS:OLD28 ;continue down the console chain
  2021. ENDPROC
  2022.  
  2023.  
  2024.                 PAGE
  2025. ;******************************************************************************
  2026. ; TRAPPER69 - Chains to INT 69H so we can determine if the TSR's already here
  2027. ;
  2028. ;       This routine provides a method of checking to see whether a copy of
  2029. ; this TSR already exists in memory.  This entry could also be used to
  2030. ; reconfigure the resident portion of the program (i.e. to reset a clock,
  2031. ; to add a file to a print queue... etc.)
  2032. ;
  2033. ;     ENTRY:    AX = 0ABCDH
  2034. ;
  2035. ;      EXIT:    If the TSR is already resident:
  2036. ;                       AX = 0DCBAH
  2037. ;
  2038. ;               If the TSR is NOT resident:
  2039. ;                       AX = 0ABCDH
  2040. ;
  2041. ; DESTROYED:    AX if resident
  2042. ;
  2043. ;------------------------------------------------------------------------------
  2044. ASSUME ds:NOTHING,es:NOTHING
  2045. PFPROC          TRAPPER69
  2046.                                          ;
  2047.                 CMP     AX,0ABCDH               ;Is it the correct function?
  2048.                 JE      CK_OURS                 ;yes, respond to it
  2049.                 JMP     DWORD PTR CS:OLD69
  2050. CK_OURS:        MOV     AX,0DCBAH               ;set return code
  2051.                 IRET
  2052. ENDPROC
  2053.  
  2054.  
  2055.                 PAGE
  2056.  
  2057.  
  2058. ;****************************************************************************
  2059. ; UNLOAD - Unhooks all vectors and exits
  2060. ;
  2061. ;       This routine removes the TSR from memory, if possible.  The sequence
  2062. ; of events is:
  2063. ;       a) a check is made to be sure that we are the LAST program in memory
  2064. ;       b) all vectors are unhooked
  2065. ;       c) the environment segment that DOS gave me is deallocated
  2066. ;       d) the current code segment is deallocated
  2067. ;       e) control is returned to whatever program was running before
  2068. ;
  2069. ;     ENTRY:    nothing
  2070. ;
  2071. ;      EXIT:    nothing
  2072. ;
  2073. ; DESTROYED:    this program, hopefully
  2074. ;
  2075. ;----------------------------------------------------------------------------
  2076. ASSUME ds:CODE,es:CODE
  2077. PNPROC          UNLOAD
  2078.  
  2079. ;------------------------------------------------------------------------------
  2080. ; see if there are active memory control blocks after mine
  2081. ;------------------------------------------------------------------------------
  2082.                 PUSH    AX
  2083.                 PUSH    ES
  2084.                 MOV     AX,CS                   ;my MCB starts 1 seg before
  2085.                 DEC     AX                      ;  my code seg
  2086.                 MOV     ES,AX
  2087.                 ADD     AX,ES:[0].MCB_LENGTH    ;find out how long it is
  2088.                 INC     AX                      ;fiddle the value
  2089.                 MOV     ES,AX
  2090.                 MOV     AL,ES:[0].MCB_KIND      ;what kind is the next MCB?
  2091.                 CMP     AL,m@LAST               ;if it's not the last...
  2092.                 POP     ES
  2093.                 POP     AX
  2094.                 JNZ     BAD_UNLOAD              ;...then leave now
  2095. ;------------------------------------------------------------------------------
  2096. ; unhook all the vectors
  2097. ;------------------------------------------------------------------------------
  2098.                 PUSH    AX
  2099.                 PUSH    DX
  2100.                 PUSH    ES
  2101.                 PUSH    DS
  2102.                 MOV     AX,0
  2103.                 MOV     DS,AX
  2104.                 @RESTORE_VECT 009H FROM OLD9    ;Restore keyboard vector
  2105.                 @RESTORE_VECT 008H FROM OLD08   ;Restore timer vector
  2106.                 @RESTORE_VECT 028H FROM OLD28   ;Restore console vector
  2107.                 @RESTORE_VECT 069H FROM OLD69   ;Restore my TSR vector
  2108. ;------------------------------------------------------------------------------
  2109. ; deallocate everything
  2110. ;------------------------------------------------------------------------------
  2111.                 MOV     ES,CS:ENVIRONMENTSEG
  2112.                 MOV     AH,049H                 ;de-allocate the environment
  2113.                 INT     021H                    ;  block
  2114.                 PUSH    CS
  2115.                 POP     ES
  2116.                 MOV     AH,049H                 ;de-allocate the code block
  2117.                 INT     021H
  2118.  
  2119.  
  2120.                 POP     DS
  2121.                 POP     ES
  2122.                 POP     DX
  2123.                 POP     AX
  2124.                 CLC
  2125.                 RET
  2126. ;------------------------------------------------------------------------------
  2127. ;can't unload: memory control blocks after mine...
  2128. ;------------------------------------------------------------------------------
  2129. BAD_UNLOAD:     STC
  2130.                 RET
  2131.  
  2132. ENDPROC
  2133.  
  2134.  
  2135.                 PAGE
  2136. ;****************************************************************************
  2137. ; INSTALL - Installs traps, then runs the program.
  2138. ;
  2139. ;     ENTRY:    called on entry to the program
  2140. ;
  2141. ;      EXIT:    TSR's the main program and exits to DOS
  2142. ;
  2143. ; DESTROYED:    ALL
  2144. ;
  2145. ;----------------------------------------------------------------------------
  2146. ASSUME ds:CODE,es:CODE
  2147. PNPROC          INSTALL
  2148.                 PUSH    CS
  2149.                 PUSH    CS
  2150.                 POP     DS
  2151.                 POP     ES
  2152.                 MOV     CS:CODSEG,CS
  2153. ;------------------------------------------------------------------------------
  2154. ; see if this program is already in memory
  2155. ;------------------------------------------------------------------------------
  2156.                 MOV     AX,0ABCDH
  2157.                 INT     069H
  2158.                 CMP     AX,0DCBAH
  2159.                 JNE     NOT_THERE
  2160.                 JMP     ALREADY_THERE
  2161. ;----------------------------------------------------------------------------
  2162. ; install our keyboard hardware interrupt trap
  2163. ;----------------------------------------------------------------------------
  2164. NOT_THERE:      MOV     AllowPop,FALSE
  2165.                 MOV     TryPop,FALSE
  2166.                 MOV     AX,03400H               ;get the InDOS flag's address
  2167.                 INT     21H
  2168.                 MOV     WPTR CS:InDOS,BX        ;...and save it
  2169.                 MOV     WPTR CS:InDOS[2],ES
  2170.                 @CHANGE_VECT 009H TO TRAPPER9 SAVEIN OLD9
  2171.                 @CHANGE_VECT 008H TO TRAPPER08 SAVEIN OLD08
  2172.                 @CHANGE_VECT 028H TO TRAPPER28 SAVEIN OLD28
  2173.                 @CHANGE_VECT 069H TO TRAPPER69 SAVEIN OLD69
  2174. ;----------------------------------------------------------------------------
  2175. ; print copyright notice
  2176. ;----------------------------------------------------------------------------
  2177.                 MOV     AH,9
  2178.                 MOV     DX,OFFSET NOTICE
  2179.                 INT     021H
  2180.  
  2181.  
  2182.                 MOV     CS:AllowPop,TRUE
  2183. ;------------------------------------------------------------------------------
  2184. ; calculate total program size and leave
  2185. ;------------------------------------------------------------------------------
  2186. TSR_OUT:        MOV     AX,03100H
  2187.                 MOV     DX,OFFSET INSTALL
  2188.                 SHR     DX,1
  2189.                 SHR     DX,1
  2190.                 SHR     DX,1
  2191.                 SHR     DX,1
  2192.                 INC     DX
  2193.                 INT     021H
  2194. ;------------------------------------------------------------------------------
  2195. ; ERROR: program is already resident!
  2196. ;------------------------------------------------------------------------------
  2197. ALREADY_THERE:  MOV     AH,9
  2198.                 MOV     DX,OFFSET ALREADY
  2199.                 INT     021H
  2200.                 MOV     AX,04C01H
  2201.                 INT     021H
  2202. ENDPROC
  2203.  
  2204. ;==============================================================================
  2205. ; DATA THAT'S ONLY USED DURING INSTALLATION
  2206. ;
  2207. ;
  2208.  
  2209. NOTICE          LABEL   BYTE
  2210. DB CR,LF
  2211. DB 'Example TSR         v1.0  Sun  03-19-1989',CR,LF
  2212. DB 'Copyright (C) 1988 ORivation',CR,LF
  2213. DB CR,LF
  2214. DB 'Press LSHIFT-RSHIFT-T to execute',CR,LF,'$'
  2215. ALREADY         LABEL   BYTE
  2216. DB CR,LF,'The Example TSR is already installed!',7,CR,LF,'$'
  2217.  
  2218. MAIN            ENDP
  2219. ;
  2220. ;****************************************************************************
  2221. ;
  2222. CODE            ENDS
  2223.                 END     ENTRY