THE ASSEMBLY LANGUAGE "MAGAZINE" #2 1989










THE ASSEMBLY LANGUAGE "MAGAZINE"                  VOL 1 NUMBER 2
                                                  March 1989

















  ##     ####    ####   ####### ##   ## ######  ####    ##  ##
 ####   ##  ##  ##  ##   ##   # ### ###  ##  ##  ##     ##  ##
##  ##  ###     ###      ## #   #######  ##  ##  ##     ##  ##
##  ##   ###     ###     ####   #######  #####   ##      ####
######     ###     ###   ## #   ## # ##  ##  ##  ##   #   ##
##  ##  ##  ##  ##  ##   ##   # ##   ##  ##  ##  ##  ##   ##
##  ##   ####    ####   ####### ##   ## ######  #######  ####

        ####      ##    ##   ##   ####  ##  ##    ##      ####  #######
         ##      ####   ###  ##  ##  ## ##  ##   ####    ##  ##  ##   #
         ##     ##  ##  #### ## ##      ##  ##  ##  ##  ##       ## #
         ##     ##  ##  ## #### ##      ##  ##  ##  ##  ##       ####
         ##   # ######  ##  ### ##  ### ##  ##  ######  ##  ###  ## #
         ##  ## ##  ##  ##   ##  ##  ## ##  ##  ##  ##   ##  ##  ##   #
        ####### ##  ##  ##   ##   ##### ######  ##  ##    ##### #######















Written by and for assembly language programmers.






         
         
         
         
                            March     1989    Contents
         
          Policy...................................................  3
         
          Editorial................................................  4
         
          Beginners Corner.........................................  5
         
          What is SDN?.............................................  7
         
          FASTPRINT................................................  8
                   by Dennis Yelle
          The EXEC Function........................................ 11
                   by Patrick O'Riva
          TSR's.................................................... 13
                   by David O'Riva
          Book Reviews............................................. 17
         
          Program Spotlight........................................ 18
         
         
          Source listings in order of appearance
         
         
         
         
               It has been suggested that the source listings be placed
          at the end of the "Magazine" rather than following the
          associated article. If you prefer it one way or the other
          please advise the editor.
         
          Address of The Assembly Language "Magazine"
                    AsmLang and CFS  FidoNet 143/37 408-259-2223
                    Patrick O'Riva
                    2726 Hostetter Rd.
                    San Jose, CA 95132
         
















                                        2





         
         
                   GUIDE LINES FOR CONTRIBUTORS AND 'ADVERTISERS'
         
         
               Name and address must be included with all articles and
          files.  Executable file size and percent of assembly code
          (when available) should be included when a program is
          mentioned and is required from an author or publisher.
         
               Any article of interest to Assembly language programmers
          will be considered for inclusion.  Quality of writing will not
          be a factor, but I reserve the right to try and correct
          spelling errors and minor mistakes in grammar.  Non-exclusive
          copyright must be given. No monetary compensation will be
          made.
         
               Outlines of projects that might be undertaken jointly are
          welcome.  For example: One person who is capable with hardware
          needs support from a user friendly programmer and a math whiz.
         
               Advertisements as such are not acceptable.  Authors and
          publishers wishing to contribute reviews of their own products
          will be considered and included as space and time permit.
          These must include executable file size, percent of assembly
          code and time comparisons.
         
               Your editor would like information on math libraries, and
          reviews of such.
         
               Articles must be submitted in pclone readable format or
          sent E-mail.
         
         
               Money: Your editor has none.  Therefore no compensation
          can be made for articles included.  Subscription fees
          obviously don't exist.  Publication costs I expect to be nil
          (NUL). Small contributions will be accepted to support the BBS
          where back issues are available as well as files and programs
          mentioned in articles(if PD or Shareware ONLY).
         
               Shareware-- Many of the programs mentioned in the
          "Magazine" are Shareware.  Most of the readers are prospective
          authors of programs that can be successfully marketed as
          Shareware.  If you make significant use of these programs the
          author is entitled to his registration fee or donation.
          Please help Shareware to continue to be a viable marketing
          method for all of us by urging everyone to register and by
          helping to distribute quality programs.








                                        3





         
                                    Editorial
         
               This is the second monthly edition of the Assembly
          Language Magazine.  I have been disappointed in the response
          to the first issue both in the number of comments I have
          received and in the lack of articles submitted for inclusion
          in this issue.  I would like to give a special thank you to
          Richard Hendricks for his letter of suggestions and comments,
          most of which I hope to address in this issue. He felt that a
          less full look to the pages would improve the readability and
          appearance.
         
               My original idea was to fill the page as much as possible
          to reduce the amount of print out.  Many of his other comments
          reflect my lack of experience as an editor, and I will try to
          improve.
         
               Without some articles being sent in this will be near the
          last issue. The time is not available for your editors to
          write the entire magazine every month, and even if it were,
          the quality would suffer from lack of variety. Please send
          those submissions.
         
               Please excuse the late publication this month.
         
                                      ERRATA
         
               The name of the Author of the A86 Assembler was
          misspelled.  The correct spelling is: Eric Isaacson
         
               In the article about fast memory moves I repeatedly
          referred to the 8259 as the DMA processor.  The 8259 is the
          interrupt controller and has nothing to do with DMA transfers.























                                        4





         
                                Beginners Corner.
         
               Obviously the first requirement for learning any assembly
          language is to have a list of the instructions.  This may
          sound easy and it is something that most novice level books
          claim to have, but it is one of the most difficult things to
          find.
         
               Every source I have found is very incomplete and/or
          unclear.  The exact use of each command and the hundreds of
          variations on each forces even scarred veterans to look back
          at a reference now and again.
         
               At least one of your references must contain the clocks
          data for each instruction.  For the 80XXX series of processors
          this is a very confusing table of adds for all occasions. The
          basic time for the instruction is given plus the number of
          accesses plus EA calculation.  It is different for a
          conditional jump taken and when it is not.  To make matters
          even worse we are dealing with not one processor, but with at
          least 5: 8088, 80286, 80386, V20, V30.  Each of these works
          differently and thus each has its own timing.  Because it is
          the worst case and because there are so many installed it is
          always best to use the timing for the 8088 unless you are
          writing for a particular application or system.
         
               A first glance at the EA calculation table will be very
          enlightening to those who have used a high level language.
          Most of the variables passed and most all of the structures
          addressed are done with pointers and offsets to pointers.
          These are VERY costly time wise.  Even pushes and pops take
          far longer than one would think.  A memory access (fetching
          the value of a variable) especially using the AX register pair
          is faster than a push and pop.  Be familiar with your
          instructions and how long they take.  Only use half of the
          register pair if that is all you need because it saves an
          additional fetch, cutting the time almost in half.
         
               A clear verbal description of each instructions including
          its peculiarities is essential. This is true for all, but the
          more complex instructions such as rep movsb make it mandatory.
         
               Each instruction should list the flags it can affect.
          These are not always what you want or need.  For example: the
          INC instruction does not affect the carry flag.  As silly as
          it may sound you have to use an instruction that affects the
          flag you want to test for.
         
               The Rotate and Shift group of instructions should be
          accompanied with diagrams showing their operation. A glance at
          the diagrams will show exactly which one to use where it could
          take reading pages to do the same thing.
         



                                        5





               One final note of caution that seems to fit in here --
          unless you are doing signed arithmetic operations avoid the
          use of the JG and JL type instructions.  They take the sign
          bit into account and can cause very hard to trace bugs.  Use
          the JA and JB instructions instead.
         
               Your next most important reference is a description of
          the BIOS calls.  Most of these are very straight forward and
          require little by way of explanation.
         
               Next comes a DOS reference. The critical ones of these
          are also quite simple to understand and use. Don't get
          involved with FCB's; the handle method of file access is the
          only way to go.
         
               For your BIOS and DOS references almost any will work,
          but your basic instruction description look long and hard. You
          will probably end up with several you use regularly.
         
               With all of your reference works stacked up around you,
          sitting at your computer, what next?  You need to choose an
          assembler.  There are at least 4 major packages available,
          each with its supporters and its weaknesses. The Microsoft
          MASM is complete and the de facto standard.  It is also large
          and slow. TASM from Borland is faster, and is mostly
          compatible, but tricky for beginners. Optasm I am not very
          familiar with, though it sounds pretty good. It is much faster
          than MASM, and is a full 2 pass assembler. If you are not
          concerned with compatibility A86 is fast, small and simple to
          use, and the D86 debugger is adequate.
         
               The text editor you use must produce a pure ASCII file.
          Whatever you enjoy is the one to use. Qedit from Semware can
          be configured to act like almost any other, and is fast and
          small.
         
                 Next month: Segmentation and Memory allocation.
         
                                Useful Shareware:
          1029ref                       DOS and Pc Tech Reference
          inter                         Complete interrupt listing
          @last200                      Pop up tables
          LW86                          Pop up instruction summary
          Qedit                         Text editor
          A86                           Assembler
          D86                           Symbolic Debugger











                                        6





         
                                   What is SDN?
         
               SDN stands for Shareware Distribution Network. It is a
          relatively new organization operating largely within FidoNet
          but in no way affiliated with it. SDN receives software direct
          from the author on disk, compresses it using the PAK facility
          from No Gate and distributes it to affiliated BBS's throughout
          the country, in a highly traceable manner.
         
               This distribution method is advantageous for both the
          author and  the user. It assures the author of quick and
          complete distribution nationwide, and it assure the user of
          complete and uncontaminated software.
         
               There is no charge to either the author or the user for
          this service, but the author must comply with the instructions
          for transmitting the software to the SDN home point.
         
               Complete information is available from your local SDN BBS
          or as a last resort you can get the informational files from
          AsmLang.



































                                        7





         
         
                    FASTPRINT: The fix for one of PRINT's bugs
                                 by Dennis Yelle
         
         
               Does your printer slow down when you run LIST or your
          favorite editor, word processor, debugger, or other program
          that spends most of its time just waiting for you to type at
          it?  Does this annoy you?  It annoyed me!  It annoyed me
          enough so that I did something about it.
         
          How to use it:
          --------------
               Just type FASTPRINT at the DOS prompt, either before or
          after you run PRINT.  Or put the FASTPRINT command in your
          AUTOEXEC.BAT file, that's what I do.  If you put FASTPRINT in
          your AUTOEXEC.BAT file, it should normally be placed AFTER any
          utility that increases the size of the keyboard type-ahead
          buffer.
         
          How it works, if you like grubby details:
          -----------------------------------------
               The PRINT command installs a TSR that prints files in the
          background.  This allows you to run other programs on your
          computer while the file(s) print.  The PRINT TSR "steals" some
          computer time from you, but usually not enough to bother you.
          The problem is that sometimes (usually) it doesn't steal
          enough to keep the printer running at anywhere near full
          speed.  Fortunately, there is a way to "give" the PRINT TSR
          more time.  And, it turns out that COMMAND.COM does just that
          when it is waiting for you to type a DOS command.  The problem
          is that most programs that you run don't do this.  And so the
          printer slows down.  ugh!  Now we get to the good part.
          FASTPRINT looks for some signs that indicate that the
          foreground program is waiting for something, like a keystroke,
          and tells PRINT to do some printing while we wait.
         
          How it works, only for those who like the REALLY grubby
          details:
          -------------------------------------------------------
         
               The way to "give" the PRINT TSR some computer time is to
          put 0080H in AX, and do an INT 2FH.  What FASTPRINT does, is
          link itself into interrupts 15H and 16H.  INT 16H is used to
          read the keyboard.  When a program tries to read a key that
          the human has not typed yet, FASTPRINT gives PRINT a bit of
          computer time, and then checks to see if the human has typed
          the key yet.  If not, then it gives PRINT some more time and
          checks the keyboard again...INT 15H function 90H is used on
          the AT only to tell other programs that we are waiting for
          something that may take some time.  So, if this happens, then
          FASTPRINT gives some time to PRINT.




                                        8





               To make FASTPRINT even more useful to those who like
          grubby details, I am including the A86 source code for the
          program.
         
          How to pay for it:
          ------------------
          1. If it is before March 30, 1989 then just:  Send a message
          to me reporting how well FASTPRINT worked for you, including:
         
          (A. the hardware you are running on;
          (B. the version of DOS you are using;
          (C. how well it works, that is, for example, how many seconds
          does it take to print a www byte xxx line file with a yyy
          printer with and without using FASTPRINT while inside program
          zzz; and
          (D. anything else you have discovered about it, including any
          incompatibility with other programs.
         
               You may send this message to my PO Box, or to me at any
          of these BBS'S:
                          AsmLang and CFS (Opus 1:143/37)  408-259-2223
                          HomeBase 408-988-4004
                          PDSE     408-745-0880
         
          2. Just send a check for about 1/4 of what you think it is
          worth to you to:
              Dennis Yelle
              P. O. Box 62276
              Sunnyvale, CA  94088
         
               If you want to donate, but don't know how much it is
          worth, then just send me $10.
         
          3. FOR PROGRAMMERS ONLY:  If you want to use any or all of the
          source code in the file FASTPRIN.8 in your own program(s), you
          may buy the right to do so for $25.
         
          Legal mumbo jumbo
          -----------------
               This document and the program files FASTPRIN.COM and
          FASTPRIN.8 are copyrighted by the author.  The copyright owner
          hereby licenses you to: use the software; make as many copies
          of it as you wish; give the copies to anyone; and to post this
          .ARC file on BBS'S, if the BBS is free.  There is no charge
          for any of the above.
               However, you are specifically prohibited from charging,
          or requesting donations, for any copies, however made; and
          from distributing this software and/or documentation with
          commercial products without prior permission.
               No copy of this software may be distributed or given away
          without this document; and this notice must not be removed.
          There is no warranty of any kind, and the copyright owner is
          not liable for damages of any kind.  By using this software,
          you agree to this.



                                        9





         
          --------------------------------------------------------------
               Editors note: This is the documentation for FASTPRINT and
          has been included in the magazine at the author's suggestion
          as it describes the operation, is written in assembly and
          includes the source.



















































                                        10





         
                                The EXEC Function
                                        by
                                  Patrick O'Riva
         
               The EXEC function is one of the most powerful features of
          DOS.  It allows shelling out of an application, and even going
          as far as invoking another command interpreter. It is also
          rather complex to use and there is no debugging help from DOS.
         
               The EXEC command comes in three basic flavors; Load and
          execute a file, Load and overlay, and the 3rd is an internal
          DOS function of load a file. Only the load and execute a file
          will be covered in detail this month.
         
               I freely admit I'm not an expert on the use of the EXEC
          function, but I have convinced it to work for me and done so
          recently enough I can remember most of the mistakes. If anyone
          reading this is better informed, I encourage them to write a
          supplementary article.
         
               DOS requires that you supply three separate pieces of
          information. The program <filename> fully qualified as to
          drive, path, filename and extension. My experience is that it
          will not make a path search, but this might be inaccurate and
          caused by a slight error in syntax. The second item is the
          command line arguments in DOS format, where the first byte
          specifies the length of the argument including the length
          byte.  The third item is an environment block. For this one
          you are allowed to default to current block as passed to the
          program you are EXEC'ing out of. To execute a batch file or
          use the built-in DOS commands you must EXEC command.com itself
          and pass the program name in the arguments.
         
               For "load and execute" a program the syntax is as
          follows:
         
               AH=4Bh    EXEC function number within INT 21h
               AL=0      specify "load and execute"
               DX        points to program name,
                              i.e. 'C:\MYSTUFF\RUNME.EXE'
               ES:BX     points to the "EXEC control block", defined
                         as follows:
                           WORD   segment of environment block to pass
                               if 0 defaults to parent block.
                               environment is assumed to be at offset 0
                               within this segment
                           DWORD  pointer to command tail
                           DWORD  pointer to 1st FCB
                           DWORD  pointer to 2nd FCB
         
               "COMMAND TAIL" is defined as that portion of a command
          line following the program name, preceded by a one byte count




                                        11





          of the length of the tail plus 1 for the terminating CR (0Dh),
          i.e.      DB   12,'/h /Ox1.obj',0Dh
         
               The first job most any program should do is return to DOS
          any portion of memory that is not required. Without this
          operation there would be no place for DOS to load the new
          program. It is also best to do this to inform your program how
          much memory is available to it to use for data storage and
          other general uses. If FFFF paragraphs are requested from DOS
          naturally a fail will be returned, but more importantly the
          amount available will also be returned. After determining that
          there is sufficient to at least attempt the EXEC the program
          can continue.
         
               Let's use the terms parent and child for the two
          programs.  Once the EXEC is called the parent has no further
          control over the operation of the child. All control must be
          exercised through the information passed in the parameter
          block.  You can tailor the environment block, specify the
          command tail, and point the 2 FCB's if the program uses them.
          If the program doesn't use them you can just point them to 5CH
          and 6CH of the parent's PSP(The segment address is supplied by
          DOS in ES and DS after the parent is loaded).
         
               I am including a short program that does nothing except
          EXEC according to your instructions.  With some playing around
          it should be a good introductory tool.  A sample program name
          and command tail are included, but these you will want to
          change.
         
               Some of the code in there is unnecessary, but may make it
          easier to customize or illustrates some point. With relatively
          small changes this could be included in another program to
          serve as an exec subroutine.  The source is compatible with
          both MASM and A86.






















                                        12





         
                                      TSR's
                         How to get user input, Part Two
                       (along with lotsa other neat stuff)
                                 by David O'Riva
                                       
               This article is a multi-part package, all rolled into one
          month, mainly because a good deal of it comes in one chunk:
          How to write a well-behaved TSR. For those of you who aren't
          quite sure what a TSR really is, a short definition follows.
         
               TSR, n, 1. Terminate and Stay Resident.   2. A program or
          routine that, after being loaded, carves a niche of memory for
          itself and holes up there, only showing itself when a certain
          circumstance occurs.  This is what is meant by"serially
          multitasking."  You press a "hotkey", and for some length of
          time the program you were working on is subjugated to the
          background, and the TSR gets to use the computer.
                         3. A real pain to write.
         
               TSR'S have numerous uses:  print spoolers, expanded
          keyboard buffers, text editors, directory manipulators,
          background disk formatters, display managers, background file
          transferors - anything you may want to do while you're in the
          middle of another application.
               TSR's usually have the following basic structure
          (depending on what they do):
         
                  jump to initialization
         
                  main body of resident code
         
                  keyboard interrupt interceptor
         
                  timer tick interceptor
         
                  DOS console interceptor
         
                  un-installation routine
         
                  initialization code
         
         
               An explanation of each of these follows:
         
         
                               Initialization Code
         
               The initialization code must check to see if the TSR is
          already resident in memory (aborting if so), hook all of the
          interrupt servers into their respective chains, perform any
          other tasks necessary to install the program, then deallocate
          all unused memory and exit to DOS with a TSR call.
         



                                        13





               To determine whether or not a copy of the TSR is already
          resident, you could assign an unused interrupt to it.  The
          example uses INT 69H, function ABCD hex.  If the example is
          already installed, it returns with DCBA hex in AX.
         
               This "residency check" interrupt could also handle
          functions for the TSR:  i.e. if the TSR was a print
          spooler,and there was no "hot key" code written for it (like
          the DOS PRINT command), then the program could call INT 69H
          with function AB00H to add a file to the print queue.
         
               To hook an interrupt into a chain, you must replace the
          appropriate vector with a pointer to your interrupt server,
          and your interrupt server must jump to or call the code that
          the vector used to point to.  Failure to do this caused many
          early TSR's to refuse to co-habit with other TSR's,
          occasionally making the machine bomb, etc...  Unless you have
          a very good reason, ALWAYS continue the interrupt chain.
         
               Two TSR exits are available:  The first is INT 27H,which
          has some limitations (only 64K of your program can remain
          resident, which shouldn't be too onerous), and which Microsoft
          does not recommend for anything except DOS 1.  The second is
          INT 21H function 31H, which allows up to a meg to remain
          resident (right) and allows you to send a return code back to
          the caller.
         
               The initialization code usually de-allocates itself upon
          exiting.
         
         
                          Keyboard Interrupt Interceptor
         
               This is only required for programs that wish to pop up
          when the hot key is pressed or wish to monitor the keyboard
          for some other reason.  Much of what they have to do was
          discussed last month, with two exceptions.
         
               The first is how to prevent a keystroke from reaching the
          BIOS code without leaving the keyboard locked up.  To do this,
          you have to tell the keyboard that you received the character,
          then reset the interrupt controller and exit (without chaining
          to the next interrupt.)  The keyboard is cleared by toggling
          bit 7 of port 61H on, then off.  The interrupt controller is
          cleared by sending an EOI(End Of Interrupt) code 20H to the
          8259 at port 20H (weird,huh?).  At that point you should do an
          IRET.
         
               The second is the necessity of monitoring the InDOS flag.
          Note that YOU ONLY HAVE TO DO THIS IF YOUR TSR USES DOS
          FUNCTIONS.  Also note that this flag is NOT documented by IBM
          OR Microsoft, and that it is not strictly "compatible."
         




                                        14





               The address of the InDOS flag can be acquired by a call
          to INT 21H function 34H.  The flag is non-zero if a DOS
          function is currently active.  You need this flag because DOS
          is not re-entrant.  That is, if you call DOS from your TSR,and
          DOS was active when the TSR gained control, the TSR will work
          fine, but when you return from it, the function in progress
          will have lost its entire stack and much of its data area.
          Nasty stuff.
         
               If the InDOS flag is set when the keyboard trap is
          activated, the keyboard trap should set a flag saying "I want
          to activate but I can't" and return.
         
         
                              Timer Tick Interceptor
         
               These are always fun.  18.2 times per second, you get
          control of the machine.  This is useful for print spoolers,
          resident screen clocks, and TSR'S that need to perform DOS
          functions.
         
               In the last case, the timer tick trap should check to see
          if the TSR wants to activate, and if so whether the InDOS flag
          is set.  If the InDOS flag is clear, then the TSR can be
          activated.
         
         
                             DOS Console Interceptor
         
               This interrupt (INT 28H) is called by DOS whenever a DOS
          console function is in progress.  This is useful to have
          because during a console input, the InDOS flag is set, but it
          is actually safe to use any DOS function ABOVE 0CH.
         
               This trap should check to see if the TSR wants to
          activate, and if so then activate it.
         
         
                               Main Body of the TSR
         
               The only requirement for this is that if you use more
          than two words (yes, this is an arbitrary measure that seems
          safe to me) of stack, you should use your internal stack
          instead of the one that you were called with.  This is because
          you have no idea how large the stack you're working on is, and
          no way of telling how far you can go before you start to
          overwrite data...
         
         
                           The Un-Installation routine
         
               This is a very nice thing to have.  The only problem is
          that it needs to use a DOS call to de-allocate its memory.




                                        15





          Unless, of course, you want to directly modify the memory
          control blocks... which could be very dangerous.
         
               The routine in the example TSR does check the memory
          control block immediately after it to make sure that there are
          no programs installed in memory after the TSR.  DOS gets upset
          when there are "holes" in memory.  At least, it's supposed to.
          The structure included for the MCB is complete as far as I
          know, but it is also *extremely* undocumented.  Microsoft
          calls it an "arena header" and tells programmers to keep their
          hands off of it.
               All vectors must be unhooked.
         
               The DOS calls to de-allocate the memory are necessary.
         
         
                           Neat tricks you can pull...
         
               The command line area in the PSP makes for a convenient
          40 word internal stack.  If you aren't using the FCBS, the FCB
          storage area can be commandeered as well.
         
               The environment segment's size can be checked (with a
          look at the MCB) and that can be used for stack, data or code
          as well.
         
         
          The Example TSR
         
               As far as actual use goes, the example TSR is a very
          simple beast.  When resident, press LSHIFT-RSHIFT-T (it'll
          beep).  Then press "Q" to return to normal processing, or
          press "N" to Nuke the TSR (remove it from memory).  If it
          cannot remove itself, it will beep three times.
         
               Well, that's about all there is to it.  With all these
          routines (or at least the ones you need) combined in one
          cohesive package, you have a full-fledged TSR skeleton. The
          example TSR includes most of these techniques.  Use and enjoy.
          Comments on this article, or expansions on the subject matter
          are greatly appreciated and will be published in later issues
          of the magazine.















                                        16





         
         
                          Book Reviews by Patrick O'Riva
         
         
         
          PROGRAMMER'S TECHNICAL REFERENCE FOR MSDOS AND THE IBM PC
               By Dave Williams P.O. box 181, Jacksonville, AR 72087
         
               This is a first glance review that I wanted to get into
          this month's issue.  It is a user supported book on disk.  I
          haven't had the time to read through it, but it appears to be
          one of the best available in any format.  In compressed form
          it is over 200k, and expands to over 500k.  It is very
          complete and includes some hard to find tables and version
          histories.  Requested $15 support includes 2 additional disks
          and updates.  Probably one of the best buys around.
         
               It is available on various BBS's (AsmLang included)
          though its 200k+ size makes for slow distribution.  The
          complete package direct from the author is probably best.
         
         
          IBM Technical Reference- Personal Computer XT
         
               This comes in the standard binder/box and is available
          from IBM corporation at a hefty $50. In addition to some
          information on port assignments and memory maps it contains
          two sets of information that I have found nowhere else.
         
               A complete listing of the ROM BIOS for the XT that is
          invaluable as both an example of programming each piece of
          hardware and clues as to how to optimize for a specific
          application.
         
               Complete schematics of the motherboard of the XT that can
          help to explain why something won't work if you are
          technically inclined.
         
               I have found it invaluable, but it is not for everyone.
               Similar publications are available for the other IBM
          products and for the PCDOS.
               For further information contact IBM at 1-800-426-7282














                                        17





         
         
                                Program Spotlight
                               Exceptional Programs
         
               This is really a nonexistent column this month as nothing
          new has come to my notice that meets the qualifications of
          high speed and small size.
         
               There is a nice piece of source code available under the
          name of CRC16 that calculates and verifies 16 bit CRC values.
          If this meets a need of yours keep a look out for it.
         
               Although I haven't tried it out yet, a program called the
          Brand X symbolic debugger has been highly recommended to me.
          Other comments would be welcomed.
         
               QFILE31G handles copying, deleting and moving files, as
          well as maintaining and listing ARC's and ZIP's. Nicely done,
          but too slow and too large to really fit here, and hangs up on
          some error conditions.
         
               WHIZ1 a file finding program certainly qualifies in speed
          as a multi disk search with wild card only takes a few
          seconds.  It is a bit larger than it might be, but at the
          least it is enhanced with assembly routines. It is a shareware
          offering and is widely available.






























                                        18



;Ed -This is the source code on FASTPRINT
        jmp     install ; This will be a .COM

db cr, '   ', cr, lf     ; On most displays, if this file is TYPEed,
               ; these 3 spaces will erase
               ; the 3 characters in the JMP instruction above.
message0:
     db   'FASTPRIN 0.0 Copyright 1989 by Dennis Yelle,'
     db   ' PO Box 62276, Sunnyvale CA 94088'
     db   cr, lf
message0_len = $ - message0
     db   'Last change:  Mar 4, 1989', cr, lf

db 26     ; This 26 is a control-Z, the DOS EOF character.
     ; I put it here so that if someone TYPEs this .COM file,
     ; only the characters before the 26 will be printed on the screen.

id_size = $ - 0100

;    To assemble this program, put the source in a file called
;    FASTPRIN.8 and then type
;    A86 FASTPRIN.8
;    This will produce a file called FASTPRIN.COM directly,
;    in about 2 seconds!  No need to run a linker!
;    The program A86.COM is available from many BBSs in an .ARC file
;    that starts with A86.
;    In particular, A86.COM is available from the "AsmLang and CFS" BBS
;    (Opus 1:143/37) 408-259-2223 in the file A86V319A.ZIP.
;    Or HomeBase 408-988-4004 in the file A86V309A.ARC.
;    Or PDSE     408-745-0880 in the file A86V314A.ARC.
;
;    FASTPRIN installs a TSR which speeds up the printing done by the
;    DOS PRINT command by calling INT 02FH with AX = 0080H whenever the
;    system is idle.  We know the system is idle whenever:
;
;    1. INT 016 is called with AH = 0 and there are no characters in
;       the keyboard buffer.  or
;    2. INT 015 is called with AH = 090.  This will only happen on an AT.
;
;    Termination codes:
;         0 - Successfully installed.
;         1 - Unable to determine if already installed, installed anyway.
;         2 - Already installed.
;
;    If this program has been helpful to you, then please send a
;    small gift to the author, Dennis Yelle, PO Box 62276,
;    Sunnyvale, CA  94088.  A gift of $10 is suggested.

cr = 0d
lf = 0a

     even
old_int_15 dw 2 dup (?)
old_int_16 dw 2 dup (?)

get_vect macro
     push es
#rx1l
     mov  ax, 03500 + 0#x


     int  021
     mov  old_int_#x, bx
     mov  old_int_#x[2], es
#er
     pop  es
#em

set_vect macro
#rx1l
     mov  dx, offset new_int_#x
     mov  ax, 02500 + 0#x
     int  021
#er
#em

new_int_16:
     pushf
     sti
     test ah,ah
     jz   wait_16
     popf
     jmp  cs: d old_int_16

wait_16_loop:
     mov  ax, 0080
     int  02f       ; Do some printing.
wait_16:
     mov  ah, 1
     int  016       ; Are any chars ready?
     jz   wait_16_loop   ; Jump if not.
     mov  ah, 0
     popf
     jmp  cs: d old_int_16

new_int_15:
     pushf
     sti
     cmp  ah, 090
     je   idle
     popf
     jmp  cs: d old_int_15

idle:
     push ax
     mov  ax, 0080
     int  02f       ; Do some printing.
     pop  ax
     popf
     jmp  cs:d old_int_15

end_of_resident:
;---------------------------------------------------------

install:
     mov  ah, 040
     mov  bx, 1          ; Write to stdout
     mov  dx, message0
     mov  cx, message0_len
     int  021
     mov  ah, 052


     int  021
     mov  ax, es:[bx-2]
     mov  dx, ds
     dec  dx
     cld
find:
     cmp  ax, dx
     je   install_it
     ja   mem_bad
     mov  es, ax
     mov  si, 0100
     mov  di, 0110
     mov  cx, id_size/2
     repe cmpsw
     je   already_installed
     stc
     adc  ax, es:[3]
     jnc  find
mem_bad: 
     mov  w installed_msg, mem_bad_msg
     inc  b term_code
install_it:
     get_vect 15, 16
     set_vect 15, 16

     mov  ah, 049
     mov  es, [02c]
     int  021       ; Free the ENV segment.

     mov  dx, installed_msg
     mov  ah, 9
     int  021       ; Print the INSTALLED message.

     mov  ah, 031
     mov  al, term_code
     mov  dx, (end_of_resident+15)/16
     int  021       ; Terminate and stay resident.
;-------------------------------------------------------------

already_installed:
     mov  dx, ai_msg
     mov  ah, 9
     int  021       ; Print the message.
     mov  ax, 04c02
     int  021

installed: db 'FASTPRIN is now installed.', cr, lf, '$'

mem_bad_msg:
db 'FASTPRIN was unable to determine if it was previously installed, or not,'
db cr, lf,
db 'so it installed itself anyway.', cr, lf, '$'

ai_msg: db 'FASTPRIN was already installed.', cr, lf, '$'

installed_msg dw installed
term_code     db 0


;THIS IS THE SOURCE CODE FOR THE EXEC FUNCTION ARTICLE
;
;THIS PROGRAM WITH FEW IF ANY SYNTAX CHANGES SHOULD BE COMPATIBLE WITH BOTH A86
;AND MASM.
;IT IS NOT DESIGNED TO BE A STAND ALONE PROGRAM OR EVEN USER FRIENDLY BUT A
;BARE SHELL WITH WHICH TO PLAY AROUND WITH IN LEARNING TO USE THE DOS EXEC
;FUNCTION
;THE PROGRAM NAME SHOULD BE ENTERED BETWEEN THE QUOTE MARKS AT THE VARIABLE
;-PROGRAM- AND ANY OTHER COMMAND LINE ARGUMENTS SHOULD BE ENTERED BETWEEN THE
;QUOTE MARKS AT THE VARIABLE -COMMAND- BEFORE ASSEMBLY. MANY IMPROVEMENTS ARE
;OBVIOUS, SUCH AS BEING ABLE TO ENTER THE NAMES AND ARGUMENTS FROM THE CONSOLE
;BUT THESE ARE LEFT TO EXPERIMENTER.
;THE ONE SOPHISTICATION IF YOU COULD CALL IT THAT IS THAT THE ERROR LEVEL OF
;THE EXEC'D PROGRAM IS FETCHED, BUT NOTHING IS DONE WITH IT.
CODE SEGMENT 'CODE'
ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
org     0
PROG_ORG        LABEL   BYTE
org     0100
ENTRY:          JMP     START


                db      32 DUP ('STACK   ')     ;THIS SETS ASIDE 256 BYTES-
                                                ;REQUIRED DOS STACK
STAK            LABEL   BYTE                    ;THIS MARKS TOP OF STACK

THIS_SEG        DW      0               ;STORAGE FOR ADDRESS OF THIS SEGMENT

CTL_LEN         DW      0               ;THIS IS THE START OF THE *****
PROGRAM         DB      'c:\dos\list.com',0           ;ASCIIZ STRING OF PROGRAM TO
EXEC

CMDL            LABEL   BYTE            ;BEG ADDRESS OF COMMAND TAIL
CMDLEN          DB      0               ;OFFSET CR - OFFSET COMMAND
COMMAND         DB      'exec.asm'             ;THE COMMAND TAIL ITSELF
CR              DB      0DH             ;TERMINATING CARRIAGE RETURN

PARMS           LABEL   BYTE            ;ADDRESS OF PARAMETER TABLE
 ENV            DW      0               ;POINTER TO ENVIRONMENT BLOCK
                                        ;0 DEFAULTS TO PARENT
 CMDLNLOW       DW      0               ;OFFSET OF COMMAND TAIL
 CMDLNHI        DW      0               ;SEGMENT OF COMMAND TAIL
 FCB11          DW      0               ;OFFSET  OF FCB1
 FCB12          DW      0               ;SEGMENT OF FCB1
 FCB21          DW      0               ;OFFSETT OF FCB2
 FCB22          DW      0               ;SEGMENT OF FCB2
MS1             DB      'DEALLOCATION ERROR',0DH,'$' ;MESSAGE #1
MS2             DB      'EXEC ERROR',0DH,'$'         ;MESSAGE #2
START:
                CLI                     ;TURN OFF INTERRUPTS WHILE SWITCHING
                                        ;STACK FRAMES
                MOV     SP,OFFSET STAK  ;POINT STACK WHERE WE WANT IT
                STI                     ;INTS OK NOW
                MOV     AX,DS           ;BEING A COM PROGRAM DS CONTAINS THIS
                                        ;SEGMENT
                MOV     THIS_SEG,AX     ;PUT IT WHERE WE CAN GET IT EASILY
RESIZE:
                MOV     BX,(OFFSET PROG_END - OFFSET PROG_ORG)  ;FIND OUT
                                        ;HOW BIG THE PROGRAM IS
                MOV     CL,4            ;TURN THIS VALUE INTO PARAGRAPHS


                SHR     BX,CL
                                        ;
                INC     BX              ;NEEDS 1 MORE TO CATCH OVERFLOW
                MOV     AH,04AH         ;ASK FOR DEALLOCATION OF ALL BUT THIS
                INT     021H
                JNC     S1              ;IF CARRY BAD PROBLEM
                MOV     AX,OFFSET MS1   ;POINT AX AT MESSAGE 1
                JMP     END_ERROR       ;NOW LEAVE
S1:
                                ;AN ASSUMPTION IS MADE AT THIS POINT, THAT
                                ;THERE IS ENOUGH MEMORY FOR THE PROGRAM TO BE
                                ;EXEC'D TO OPERATE IN. IF NOT AN EXEC ERROR
                                ;WILL BE RETURNED.

                MOV     AX,OFFSET CR    ;FIND LENGTH OF COMMAND TAIL
                SUB     AX,OFFSET CMDL  ;AND
                MOV     CMDLEN,AL       ;PUT IT IN CMDLEN
                MOV     DX,OFFSET CMDL  ;FILL IN THE COMMAND TAIL POINTER IN
                                        ;THE PARAMETER BLOCK
                MOV     CMDLNLOW,DX
                MOV     CMDLNHI,DS
                MOV     DX,OFFSET PROGRAM ;POINT DX AT PROGRAM NAME
                MOV     ES,THIS_SEG     ;MAKE SURE ES IS POINTING AT THIS SEG
                MOV     BX,OFFSET PARMS ;POINT BX AT PARAMETER BLOCK
                MOV     AX,05CH         ;THIS IS OFFSET OF PARENT FCB1 BUT
                                        ;COULD BE ANY INFO DESIRED TO PASS TO
                                        ;CHILD THAT WOULD BE LOOKED FOR AT PSP
                                        ;5CH
                MOV     FCB11,AX        ;PUT IT IN PARAMETER BLOCK
                MOV     FCB12,ES        ;DESIRED SEGMENT OF FCB1 DATA
                MOV     AX,06CH         ;FILL IN FCB2. ABOVE COMMENTS APPLY
                MOV     FCB21,AX
                MOV     FCB22,ES
                MOV     AH,04BH         ;THE EXEC FUNCTION
                MOV     AL,0            ;LOAD AND EXECUTE
PREX:
                INT     021H            ;DOS
                JNC     FINISHED        ;ALL ACCORDING TO PLAN
                MOV     AX,OFFSET MS2   ;SOMETHING WRONG IN EXEC
                JMP     SHORT END_ERROR
FINISHED:
                MOV     AH,04DH         ;TO REACH HERE THE CHILD MUST HAVE
                                        ;TERMINATED. THIS REQUESTS THE
                                        ;TERMINATION CODE
                INT     021H            ;DOS TERMINATION CODE RETURNED IN AH
                                        ;CHILD'S AL PASSED THROUGH
                MOV     AH,04CH         ;TERMINATE THIS PROG
                INT     021H
END_ERROR:
                MOV     DX,AX           ;SAVE THE MESSAGE ADDRESS TO DX
                MOV     BX,1            ;DEVICE HANDLE IS CONSOLE
                MOV     CX,20           ;20 BYTES IS ENOUGH FOR THE MESSAGE
                MOV     AH,040H         ;WRITE TO DEVICE (CONSOLE)
                INT     021H            ;DOS
                MOV     AH,04CH         ;TERMINATE THIS PROGRAM
                INT     021H

PROG_END        LABEL   BYTE
CODE            ENDS
                END     ENTRY


                PAGE    60,132
                TITLE   EXMPLTSR.ASM - An example of a TSR program

COMMENT~*********************************************************************
*        --++**> This file is Copyright 1989 by David O'Riva <**++--        *
*****************************************************************************
*                                                                           *
* Written for the Microsoft Macro Assembler version 5.1, DOS v2.0 - 3.3     *
*                                                                           *
* MUST BE CONVERTED INTO A .COM FILE BEFORE RUNNING!!!                      *
*                                                                           *
*       Anyone who wants to incorporate this code into their programs is    *
* welcome to, as long as they don't try to sell this file as it is or any   *
* unmodified piece of it, and leave this message in when distributing it.   *
* If you do not abide by the rules, poltergeists will invade your home      *
* and chain letters and junk mail will arrive by the ton.                   *
*                                                                           *
*                                                                           *
*                  Short advertisement - use QEdit!                         *
*           Available on your local friendly Bulletin Board                 *
*                                                                           *
****************************************************************************~
.XLIST
;
; Macros used by this program
;

?PLevel         =       0

PNPROC          MACRO   PNAME           ;;declare near public procedure
                IF2
                %OUT    Routine: &PNAME
                ENDIF
                PUBLIC  &PNAME
&PNAME          PROC    NEAR
?PLevel         =       ?PLevel+1       ;;next level of nesting
@@SAVE_NAME     &PNAME,%?PLevel
                ENDM

PFPROC          MACRO   PNAME           ;;declare near public procedure
                IF2
                %OUT    Routine: &PNAME
                ENDIF
                PUBLIC  &PNAME
&PNAME          PROC    FAR
?PLevel         =       ?PLevel+1       ;;next level of nesting
@@SAVE_NAME     &PNAME,%?PLevel
                ENDM

ENDPROC         MACRO
@@REC_NAME      %?PLevel
@@EP1           %@@TEMP
?PLevel         =       ?PLevel-1
                ENDM

@@SAVE_NAME     MACRO   PNAME,LVL
?PN&LVL         EQU     <&PNAME>
                ENDM



@@REC_NAME      MACRO   LVL
@@TEMP          EQU     <?PN&LVL>
                ENDM

@@EP1           MACRO   PNAME
&PNAME          ENDP
                ENDM

PUSHM           MACRO   LST
IRP             REG,<&LST&>
                PUSH    REG
                ENDM
                ENDM

POPM            MACRO   LST
IRP             REG,<&LST&>
                POP     REG
                ENDM
                ENDM

UPCASE          MACRO   REG
                LOCAL   NOUP
                CMP     REG,'a'
                JB      NOUP
                CMP     REG,'z'
                JA      NOUP
                SUB     REG,'a'-'A'
NOUP:
                ENDM

@CHANGE_VECT    MACRO   INUM,GARB,NEW,GARB2,SAVEAREA
                MOV     AX,0
                MOV     ES,AX
                MOV     AX,ES:[INUM*4]
                MOV     DX,ES:[INUM*4+2]
                MOV     WPTR CS:[SAVEAREA],AX
                MOV     WPTR CS:[SAVEAREA+2],DX
                MOV     AX,OFFSET CS:NEW
                CLI
                MOV     ES:[INUM*4],AX
                MOV     ES:[INUM*4+2],CS
                STI
                ENDM

@RESTORE_VECT   MACRO   INUM,GARB,SAVEAREA
                MOV     AX,WPTR CS:[SAVEAREA]
                MOV     DX,WPTR CS:[SAVEAREA+2]
                CLI
                MOV     DS:[INUM*4],AX
                MOV     DS:[INUM*4+2],DX
                STI
                ENDM

BPTR            EQU     <BYTE PTR>
WPTR            EQU     <WORD PTR>
DPTR            EQU     <DWORD PTR>
CR              EQU     <13>
LF              EQU     <10>
JR              EQU     <JMP     SHORT>


FALSE           EQU     <000H>
TRUE            EQU     <0FFH>

INT_CTRL        EQU     020H    ;Interrupt control port
EOI             EQU     020H    ;Reset interrupt controller command
KB_DATA         EQU     060H    ;Keyboard data port
KB_CTRL         EQU     061H    ;Keyboard control port
;
;****************************************************************************
;
BIOSDATA        SEGMENT AT 00040H

;----------------------------------------------------------------------------
;Keyboard Data Area
;----------------------------------------------------------------------------
                ORG     00017H
KB_FLAG         LABEL   BYTE

;----- Shift flag equates within KB_FLAG

        INS_STATE       EQU     80H     ;INSERT state is active
        CAPS_STATE      EQU     40H     ;CAPS LOCK state toggled
        NUM_STATE       EQU     20H     ;NUM LOCK state toggled
        SCROLL_STATE    EQU     10H     ;SCROLL LOCK state toggled
        ALT_SHIFT       EQU     08H     ;ALT key depressed
        CTRL_SHIFT      EQU     04H     ;CTRL key depressed
        LEFT_SHIFT      EQU     02H     ;left SHIFT key depressed
        RIGHT_SHIFT     EQU     01H     ;right SHIFT key depressed

                ORG     00018H
KB_FLAG_1       LABEL   BYTE

;----- Shift flag equates within KB_FLAG_1

        INS_SHIFT       EQU     80H     ;INSERT key depressed
        CAPS_SHIFT      EQU     40H     ;CAPS LOCK key depressed
        NUM_SHIFT       EQU     20H     ;NUM LOCK key depressed
        SCROLL_SHIFT    EQU     10H     ;SCROLL LOCK key depressed
        HOLD_STATE      EQU     08H     ;suspend key has been toggled

                ORG     00019H
ALT_INPUT       LABEL   BYTE            ;storage for alternate keypad entry

                ORG     0001AH
BUFFER_HEAD     LABEL   WORD            ;pointer to head of keyboard buffer

                ORG     0001CH
BUFFER_TAIL     LABEL   WORD            ;pointer to tail of keyboard buffer

                ORG     0001EH
KB_BUFFER       LABEL   WORD            ;keyboard buffer

                ORG     0003EH
KB_BUFFER_END   LABEL   WORD
                                       ;
;----- HEAD = TAIL indicates that the buffer is empty

        NUM_KEY         EQU     69      ;scan code for NUM LOCK
        SCROLL_KEY      EQU     70      ;sc for SCROLL LOCK


        ALT_KEY         EQU     56      ;sc for ALT key

BIOSDATA        ENDS

.list
.lall
;
;****************************************************************************
;
CODE            SEGMENT PARA PUBLIC 'CODE'
                ASSUME  CS:CODE,DS:CODE,ES:CODE,SS:CODE

                ORG     02CH
ENVIRONMENTSEG  LABEL   WORD

                ORG     100H
MAIN            PROC    FAR

STACKTOP:                               ;allow the stack to overwrite the
                                        ;command line in the PSP
ENTRY:          JMP     INSTALL

;============================================================================
;
; MY LOCAL DATA
;

MCBOVL          STRUC                   ;definition of DOS's memory control
;                                       ;block structure
MCB_KIND        DB      ' '
MCB_PSP_ADDR    DW      0
MCB_LENGTH      DW      0
MCB_UNDEFINED   DB      11 DUP(?)
;
MCBOVL          ENDS

  m@BLOCK       EQU     <'M'>           ;possible entries in the MCB_TYPE field
  m@LAST        EQU     <'Z'>

OLD9            DD      ?               ;old INT 09H vector
OLD08           DD      ?
OLD28           DD      ?
OLD69           DD      ?

InDOS           DD      ?               ;address of the InDOS flag
CODSEG          DW      ?               ;code segment

AllowPop        DB      FALSE           ;TRUE = the INT 09H server is allowed
                                        ;       to try to run the TSR.

TryPop          DB      FALSE           ;TRUE = The INT 09H server couldn't
                                        ;       run the TSR because DOS was
                                        ;       processing a command at the
                                        ;       time.
                                       ;
InPop           DB      FALSE           ;TRUE = the popped-up code is running
                                        ;       at the moment.

OLDSS           DW      ?               ;storage for stack frame information
OLDSP           DW      ?



PopShifts       DB      LEFT_SHIFT+RIGHT_SHIFT  ;shift state necessary for
                                                ;  pop-up

PopKey          DB      14H             ;key # to press to pop up ('T')

;============================================================================


                PAGE
;****************************************************************************
; START - main program loop
;
;
;     ENTRY:    from hot key
;
;      EXIT:    nothing
;
; DESTROYED:    none
;
;----------------------------------------------------------------------------
PNPROC          START

;------------------------------------------------------------------------------
; set up my stack frame
;------------------------------------------------------------------------------
                MOV     CS:OLDSS,SS
                MOV     CS:OLDSP,SP
                CLI
                MOV     SS,CS:CODSEG
                MOV     SP,OFFSET STACKTOP
                STI
                PUSH    AX

;------------------------------------------------------------------------------
; MAIN LOOP
;------------------------------------------------------------------------------
                CALL    BEEP
GETAKEY:
                MOV     AH,0            ;get a key
                INT     016H
                UPCASE  AL

                CMP     AL,'N'          ;'N' for NUKE THE TSR!
                JNE     NOT_NUKE

                CALL    UNLOAD          ;try to unload myself
                JNC     LEAVE
                CALL    BEEP            ;string of beeps if I can't
                CALL    BEEP
                CALL    BEEP
                JMP     GETAKEY

NOT_NUKE:       CMP     AL,'Q'          ;'Q' for quit TSR
                JE      LEAVE
                                       ;
                CALL    BEEP            ;unrecognized key, complain
                JMP     GETAKEY         ;... and get another

LEAVE:          POP     AX              ;recover * ALL * modified registers


                                        ;        -------
;------------------------------------------------------------------------------
; recover original stack frame
;------------------------------------------------------------------------------
                CLI
                MOV     SS,CS:OLDSS
                MOV     SP,CS:OLDSP
                STI

                RET
ENDPROC


                PAGE
;******************************************************************************
; BEEP - Beeps the speaker
;
;
;     ENTRY:    nothing
;
;      EXIT:    nothing
;
; DESTROYED:    none
;
;------------------------------------------------------------------------------
PNPROC          BEEP

                PUSH    AX
                PUSH    CX
                MOV     AL,10110110B
                OUT     043H,AL
                MOV     AX,1000
                OUT     042H,AL
                MOV     AL,AH
                OUT     042H,AL

                IN      AL,061H
                MOV     AH,AL
                OR      AL,3
                OUT     061H,AL
                SUB     CX,CX
                LOOP    $
                MOV     AL,AH
                OUT     061H,AL
                POP     CX
                POP     AX
                RET
ENDPROC


;                PAGE
;;****************************************************************************
;; REGISTERTOTEXT - Converts AL into ASCII hex digits in CS:[SI]
;;
;;       For debugging - uncomment this routine if you need it.
;;                                    ;
;;     ENTRY:    AL = register to translate
;;               SI = place to put translated digits
;;
;;      EXIT:    AX = hex digits


;;
;; DESTROYED:    AX
;;
;;----------------------------------------------------------------------------
;ASSUME ds:NOTHING,es:NOTHING
;PNPROC          REGISTERTOTEXT
;;----------------------------------------------------------------------------
;; split AL into two nibbles
;;----------------------------------------------------------------------------
;                MOV     AH,AL
;                SHR     AH,1
;                SHR     AH,1
;                SHR     AH,1
;                SHR     AH,1
;                AND     AL,0FH
;;----------------------------------------------------------------------------
;; convert AL into a hex digit
;;----------------------------------------------------------------------------
;                ADD     AL,'0'                  ;AL = actual digit
;                CMP     AL,'9'
;                JBE     R_1
;                ADD     AL,'A'-'0'-10
;;----------------------------------------------------------------------------
;; convert AH into a hex digit
;;----------------------------------------------------------------------------
;R_1:            ADD     AH,'0'                  ;AH = actual digit
;                CMP     AH,'9'
;                JBE     R_2
;                ADD     AH,'A'-'0'-10
;;----------------------------------------------------------------------------
;; store hex number in [SI]
;;----------------------------------------------------------------------------
;R_2:            MOV     CS:[SI],AH
;                MOV     CS:[SI+1],AL
;                RET
;ENDPROC
;

                PAGE
;****************************************************************************
; TRAPPER9 - Intercepts the incoming keyboard scan code
;
;       Looks for the hot key in the incoming scan codes.  If found, it
; check the InDOS flag to see if DOS is currently in the middle of something.
; If not, the TSR code (at START) is invoked.  Otherwise, a flag is set and
; control is passed back to DOS.
;
;     ENTRY:    from IRQ 1, machine state is ???
;
;      EXIT:    continues KB interrupt chain
;
; DESTROYED:    ALL PRESERVED
;
;----------------------------------------------------------------------------
ASSUME ds:BIOSDATA,es:NOTHING
PFPROC          TRAPPER9
                PUSHM   <AX,BX,DS,ES>   ;save everthing I use

                MOV     AX,SEG BIOSDATA ;DS-> BIOS's data seg
                MOV     DS,AX


;----------------------------------------------------------------------------
; are we in the correct shift state?
;----------------------------------------------------------------------------
                MOV     AL,KB_FLAG      ;get current shift states
                AND     AL,00FH         ;clean up the byte
                CMP     AL,CS:PopShifts ;is it the right shift?
                JNE     T_chainon       ;no, go to next handler

                IN      AL,KB_DATA      ;Poll keyboard controller
                MOV     BH,AL           ;save keypress
                AND     AL,07FH         ;strip off the MAKE/BREAK bit
                CMP     AL,CS:PopKey    ;is this our key?
                JNE     T_ChainOn       ;If it's not our code, ignore it...
;----------------------------------------------------------------------------
; reset the keyboard controller
;----------------------------------------------------------------------------
                IN      AL,KB_CTRL      ;get multi-purpose control byte
                MOV     AH,AL           ;save original value
                OR      AL,080H         ;set "character recieved" bit
                OUT     KB_CTRL,AL      ;send it
                MOV     AL,AH           ;get original value back
                OUT     KB_CTRL,AL      ;send it
;------------------------------------------------------------------------------
; what do we do with this key?
;------------------------------------------------------------------------------
                CMP     CS:AllowPop,FALSE ;Are we allowed to pop up now?
                JE      T_ResetLeave    ;if not, exit here...

                TEST    BH,080H         ;was it the BREAK code?
                JZ      T_WasMake       ;no, go run the pop-up
                JMP     T_ResetLeave    ;otherwise, ignore this code

T_WasMake:      MOV     CS:AllowPop,FALSE ;can't pop up again

                PUSHM   <ES,BX>         ;check the InDOS flag...
                LES     BX,CS:InDOS
                CMP     BPTR ES:[BX],0
                POPM    <BX,ES>

                JNZ     T_InDOSnow      ;if in DOS, don't invoke TSR

                MOV     AL,EOI          ;otherwise, set interrupts on...
                OUT     INT_CTRL,AL
                MOV     CS:InPop,TRUE   ;...set a flag...
                STI
                CALL    START           ;...and run the TSR.
                CLI
                MOV     CS:AllowPop,TRUE
                MOV     CS:InPop,FALSE
                JMP     T_Leave

T_InDOSnow:     MOV     CS:TryPop,TRUE  ;DOS call in progress, try later...
                                       ;
T_ResetLeave:   MOV     AL,EOI          ;enable the KB interrupt again
                OUT     020H,AL
T_Leave:        POPM    <ES,DS,BX,AX>   ;throw away this key code
                IRET
;----------------------------------------------------------------------------
; Continue down the KB handler chain...
;----------------------------------------------------------------------------


T_chainon:      POPM    <ES,DS,BX,AX>
                JMP     DWORD PTR CS:OLD9
ENDPROC



                PAGE
;******************************************************************************
; TRAPPER08 - Intercepts the timer tick to try to pop up the TSR
;
;       Upon being called, this routine determines whether:
;               a) the TSR wants to pop up, and
;               b) there is no DOS call in progress
;       If these are BOTH true, then the TSR is invoked from here.
;
;       NOTE: Technically, you are supposed to trap vector 1CH for timer
; ticks instead of INT 08, but some BIOSes do not issue an EOI for the timer
; until AFTER 1C is called, and you don't want to mess up the system clock...
;
;     ENTRY:    on timer tick
;
;      EXIT:    nothing
;
; DESTROYED:    ALL PRESERVED
;
;------------------------------------------------------------------------------
PFPROC          TRAPPER08
ASSUME ds:NOTHING,es:NOTHING

                PUSHF
                CALL    DWORD PTR CS:[OLD08]

                CLI

                CMP     CS:TryPop,FALSE ;Are we trying to pop up?
                JE      C_OUT           ;if not, leave now

                PUSHM   <ES,BX>         ;Is a DOS call in progress?
                LES     BX,CS:InDOS
                CMP     BPTR ES:[BX],0
                POPM    <BX,ES>

                JE      C_Invoke        ;if not, then fire it up...

C_OUT:          IRET

C_Invoke:       MOV     CS:TryPop,FALSE ;set the right flags...
                MOV     CS:InPop,TRUE
                STI
                CALL    START           ;run the TSR...
                MOV     CS:InPop,FALSE  ;set some more flags...
                MOV     CS:AllowPop,TRUE
                                       ;
                IRET                    ;and leave.
ENDPROC


                PAGE
;******************************************************************************
; TRAPPER28 - Intercepts the DOS "console wait" loop


;
;       This routine allows the TSR to be invoked during DOS console operations
; where the InDOS flag is set but it is actually safe to use any DOS function
; above 0CH.
;
;     ENTRY:    During DOS console operations
;
;      EXIT:    nothing
;
; DESTROYED:    ALL PRESERVED
;
;------------------------------------------------------------------------------
ASSUME ds:NOTHING,es:NOTHING
PFPROC          TRAPPER28

                CMP     CS:TryPop,FALSE ;does the TSR want to pop up?
                JE      C1_OUT          ;if not, get out of here now
                MOV     CS:TryPop,FALSE ;prevent re-entrant interrupts
                MOV     CS:InPop,TRUE   ;set the "in TSR" flag
                STI
                CALL    START           ;run it!
                CLI
                MOV     CS:AllowPop,TRUE;finished, we can pop up again
                MOV     CS:InPop,FALSE  ;no longer running the TSR
C1_OUT:         JMP     DWORD PTR CS:OLD28 ;continue down the console chain
ENDPROC


                PAGE
;******************************************************************************
; TRAPPER69 - Chains to INT 69H so we can determine if the TSR's already here
;
;       This routine provides a method of checking to see whether a copy of
; this TSR already exists in memory.  This entry could also be used to
; reconfigure the resident portion of the program (i.e. to reset a clock,
; to add a file to a print queue... etc.)
;
;     ENTRY:    AX = 0ABCDH
;
;      EXIT:    If the TSR is already resident:
;                       AX = 0DCBAH
;
;               If the TSR is NOT resident:
;                       AX = 0ABCDH
;
; DESTROYED:    AX if resident
;
;------------------------------------------------------------------------------
ASSUME ds:NOTHING,es:NOTHING
PFPROC          TRAPPER69
                                         ;
                CMP     AX,0ABCDH               ;Is it the correct function?
                JE      CK_OURS                 ;yes, respond to it
                JMP     DWORD PTR CS:OLD69
CK_OURS:        MOV     AX,0DCBAH               ;set return code
                IRET
ENDPROC


                PAGE


;****************************************************************************
; UNLOAD - Unhooks all vectors and exits
;
;       This routine removes the TSR from memory, if possible.  The sequence
; of events is:
;       a) a check is made to be sure that we are the LAST program in memory
;       b) all vectors are unhooked
;       c) the environment segment that DOS gave me is deallocated
;       d) the current code segment is deallocated
;       e) control is returned to whatever program was running before
;
;     ENTRY:    nothing
;
;      EXIT:    nothing
;
; DESTROYED:    this program, hopefully
;
;----------------------------------------------------------------------------
ASSUME ds:CODE,es:CODE
PNPROC          UNLOAD

;------------------------------------------------------------------------------
; see if there are active memory control blocks after mine
;------------------------------------------------------------------------------
                PUSH    AX
                PUSH    ES
                MOV     AX,CS                   ;my MCB starts 1 seg before
                DEC     AX                      ;  my code seg
                MOV     ES,AX
                ADD     AX,ES:[0].MCB_LENGTH    ;find out how long it is
                INC     AX                      ;fiddle the value
                MOV     ES,AX
                MOV     AL,ES:[0].MCB_KIND      ;what kind is the next MCB?
                CMP     AL,m@LAST               ;if it's not the last...
                POP     ES
                POP     AX
                JNZ     BAD_UNLOAD              ;...then leave now
;------------------------------------------------------------------------------
; unhook all the vectors
;------------------------------------------------------------------------------
                PUSH    AX
                PUSH    DX
                PUSH    ES
                PUSH    DS
                MOV     AX,0
                MOV     DS,AX
                @RESTORE_VECT 009H FROM OLD9    ;Restore keyboard vector
                @RESTORE_VECT 008H FROM OLD08   ;Restore timer vector
                @RESTORE_VECT 028H FROM OLD28   ;Restore console vector
                @RESTORE_VECT 069H FROM OLD69   ;Restore my TSR vector
;------------------------------------------------------------------------------
; deallocate everything
;------------------------------------------------------------------------------
                MOV     ES,CS:ENVIRONMENTSEG
                MOV     AH,049H                 ;de-allocate the environment
                INT     021H                    ;  block
                PUSH    CS
                POP     ES
                MOV     AH,049H                 ;de-allocate the code block
                INT     021H


                POP     DS
                POP     ES
                POP     DX
                POP     AX
                CLC
                RET
;------------------------------------------------------------------------------
;can't unload: memory control blocks after mine...
;------------------------------------------------------------------------------
BAD_UNLOAD:     STC
                RET

ENDPROC


                PAGE
;****************************************************************************
; INSTALL - Installs traps, then runs the program.
;
;     ENTRY:    called on entry to the program
;
;      EXIT:    TSR's the main program and exits to DOS
;
; DESTROYED:    ALL
;
;----------------------------------------------------------------------------
ASSUME ds:CODE,es:CODE
PNPROC          INSTALL
                PUSH    CS
                PUSH    CS
                POP     DS
                POP     ES
                MOV     CS:CODSEG,CS
;------------------------------------------------------------------------------
; see if this program is already in memory
;------------------------------------------------------------------------------
                MOV     AX,0ABCDH
                INT     069H
                CMP     AX,0DCBAH
                JNE     NOT_THERE
                JMP     ALREADY_THERE
;----------------------------------------------------------------------------
; install our keyboard hardware interrupt trap
;----------------------------------------------------------------------------
NOT_THERE:      MOV     AllowPop,FALSE
                MOV     TryPop,FALSE
                MOV     AX,03400H               ;get the InDOS flag's address
                INT     21H
                MOV     WPTR CS:InDOS,BX        ;...and save it
                MOV     WPTR CS:InDOS[2],ES
                @CHANGE_VECT 009H TO TRAPPER9 SAVEIN OLD9
                @CHANGE_VECT 008H TO TRAPPER08 SAVEIN OLD08
                @CHANGE_VECT 028H TO TRAPPER28 SAVEIN OLD28
                @CHANGE_VECT 069H TO TRAPPER69 SAVEIN OLD69
;----------------------------------------------------------------------------
; print copyright notice
;----------------------------------------------------------------------------
                MOV     AH,9
                MOV     DX,OFFSET NOTICE
                INT     021H


                MOV     CS:AllowPop,TRUE
;------------------------------------------------------------------------------
; calculate total program size and leave
;------------------------------------------------------------------------------
TSR_OUT:        MOV     AX,03100H
                MOV     DX,OFFSET INSTALL
                SHR     DX,1
                SHR     DX,1
                SHR     DX,1
                SHR     DX,1
                INC     DX
                INT     021H
;------------------------------------------------------------------------------
; ERROR: program is already resident!
;------------------------------------------------------------------------------
ALREADY_THERE:  MOV     AH,9
                MOV     DX,OFFSET ALREADY
                INT     021H
                MOV     AX,04C01H
                INT     021H
ENDPROC

;==============================================================================
; DATA THAT'S ONLY USED DURING INSTALLATION
;
;

NOTICE          LABEL   BYTE
DB CR,LF
DB 'Example TSR         v1.0  Sun  03-19-1989',CR,LF
DB 'Copyright (C) 1988 ORivation',CR,LF
DB CR,LF
DB 'Press LSHIFT-RSHIFT-T to execute',CR,LF,'$'
ALREADY         LABEL   BYTE
DB CR,LF,'The Example TSR is already installed!',7,CR,LF,'$'

MAIN            ENDP
;
;****************************************************************************
;
CODE            ENDS
                END     ENTRY

Comments

Popular posts from this blog

BOTTOM LIVE script

Evidence supporting quantum information processing in animals

ARMIES OF CHAOS