home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / ASMBAR.ZIP / AMAG0589.TXT < prev    next >
Text File  |  1989-05-21  |  47KB  |  1,170 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6. THE ASSEMBLY LANGUAGE "MAGAZINE"                  VOL 1 NUMBER 3
  7.                                                   May, 1989
  8.  
  9.  
  10.  
  11.  
  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.                          Table of Contents
  67.  
  68.         Table of Contents. . . . . . . . . . . . . . . . . . . . . . 2
  69.  
  70.         Editorial. . . . . . . . . . . . . . . . . . . . . . . . . . 3
  71.  
  72.         GUIDE LINES FOR CONTRIBUTORS . . . . . . . . . . . . . . . . 4
  73.  
  74.         Beginners'Corner . . . . . . . . . . . . . . . . . . . . . . 5
  75.           Segmentation . . . . . . . . . . . . . . . . . . . . . . . 5
  76.  
  77.         Keyboard driven TSR programs.. . . . . . . . . . . . . . . . 7
  78.  
  79.         Hex Conversion Routines . . . . . . . . . . . . . . . . . . 12
  80.  
  81.         Book Reviews. . . . . . . . . . . . . . . . . . . . . . . . 14
  82.  
  83.         Source Code for Keyboard TSR. . . . . . . . . . . . . . . . 15
  84.  
  85.         Source for Soft Breakout. . . . . . . . . . . . . . . . . . 18
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125. ;page 2
  126.  
  127.  
  128.  
  129.  
  130.                                       Editorial
  131.  
  132.                 This is the third issue of the Magazine, and the first with a
  133.         major article from an outside contributor.  Our thanks to Garrett
  134.         Nievin.
  135.  
  136.                 It is amazing how few programmers really appreciate
  137.         the benefits of assembly language programming.  Most of them under-
  138.         stand that for certain parts of programs it can increase performance,
  139.         but they have no real conception of the amount of improvement that it
  140.         can make.
  141.  
  142.                 As a common example of this-- The case of sprite
  143.         manipulation.  Some of the more speed conscious programmers are
  144.         aware that to do clean writes to the CGA screen you need to wait
  145.         for the retrace periods, but a C programmer cannot chase the
  146.         electron beam around the screen to update it in areas that will
  147.         not be affected until it again goes over it.  This multiplies the
  148.         time available to manipulate areas of the screen without flicker.
  149.  
  150.                 Much of the time in executing a higher level routine is
  151.         spent in calling it and returning from it.  The indexed with of-
  152.         fset stack operations are very costly in time.  This is why even
  153.         speedup assembly routines in high level code don't show the full
  154.         capabilities as they are still called using the same conventions.
  155.  
  156.                 One of the most touted buzz words today is "structured".
  157.         This translates into using small easily controlled and understood
  158.         subroutines with a single entry point and a single exit point
  159.         having sharply limited function. This makes for a program that is
  160.         quick and easy to write (regardless of the language) and quick to
  161.         debug. These are all valuable attributes in a program, and if
  162.         done right these same routines can be included in a large variety
  163.         of dissimilar programs.
  164.  
  165.                 There are those who say that any programmer who does not
  166.         keep to "structured" programming is a bad programmer.  At least in
  167.         assembly language programming there are times and reasons for
  168.         throwing this whole concept away.  In doing so you create a
  169.         program that is almost impossible to modify, totally unreadable,
  170.         insane to debug, and a nightmare to try and document----BUT----you
  171.         can also come close to cutting your size (already tiny compared to
  172.         anything else) in half and have a good chance of a thirty percent
  173.         increase in speed if you do it right.  A program like that is not
  174.         the product of a "bad" programmer, but of a very dedicated one.
  175.         In such a program you don't have the time to waste making a lot of
  176.         CALLS or doing variable storage or register adjustments.  The num-
  177.         ber of items that you must keep track of, mostly in your head,
  178.         while writing makes it a project for only the best of programmers.
  179.         I gave it up years ago, but still envy those who are able to make
  180.         use of a powerful tool.
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190. ;page 3
  191.  
  192.  
  193.  
  194.                   GUIDE LINES FOR CONTRIBUTORS AND 'ADVERTISERS'
  195.  
  196.  
  197.                  Name and address must be included with all articles and
  198.         files.  Executable file size and percent of assembly code (when
  199.         available) should be included when a program is mentioned and is re-
  200.         quired from an author or publisher.  Any article of interest to
  201.         Assembly language programmers will be considered for inclusion.
  202.         Quality of writing will not be a factor, but I reserve the right to
  203.         try and correct spelling errors and minor mistakes in grammar, and to
  204.         remove sections.
  205.  
  206.                 Non-exclusive copyright must be given.  No monetary compensa-
  207.         tion will be made.
  208.  
  209.                  Outlines of projects that might be undertaken jointly are
  210.         welcome.  For example:  One person who is capable with hardware needs
  211.         support from a user friendly programmer and a math whiz.
  212.  
  213.                  Advertisements as such are not acceptable.  Authors and
  214.         publishers wishing to contribute reviews of their own products will be
  215.         considered and included as space and time permit.  These must include
  216.         executable file size, percent of assembly code and time comparisons.
  217.  
  218.                  Your editor would like information on math libraries, and
  219.         reviews of such.
  220.  
  221.                  Articles must be submitted in pclone readable format or sent
  222.         E-mail.
  223.  
  224.  
  225.                  Money:  Your editor has none.  Therefore no compensation can
  226.         be made for articles included.  Subscription fees obviously don't ex-
  227.         ist.  Publication costs I expect to be nil (NUL).  Small contributions
  228.         will be accepted to support the BBS where back issues are available as
  229.         well as files and programs mentioned in articles(if PD or Shareware
  230.         ONLY).
  231.  
  232.                  Shareware-- Many of the programs mentioned in the "Magazine"
  233.         are Shareware. Most of the readers are prospective authors of programs
  234.         that can be successfully marketed as Shareware.  If you make significant
  235.         use of these programs the author is entitled to his registration fee or
  236.         donation.  Please help Shareware to continue to be a viable marketing
  237.         method for all of us by urging everyone to register and by helping to
  238.         distribute quality programs.
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251. ;page 4
  252.  
  253.  
  254.  
  255.         Beginners'Corner
  256.  
  257.                                   Segmentation
  258.  
  259.                  Segments are largely a carry over from the days when
  260.         processors were all limited to a 16 bit address buss, but we still
  261.         live with them today.  They are not without some benefits however.
  262.         The way they are treated in most of the books I am familiar with
  263.         can leave the novice fear struck over the complexities and this is
  264.         not necessary.  They are nothing more ( to the assembly program-
  265.         mer) than a tool that can either be used or discarded almost at
  266.         will.
  267.  
  268.                 The 8088 has 4 segment registers; CS, DS, ES, and SS.  The
  269.         complete address of a memory reference is the sum of the segment
  270.         register (shifted 1 hex place to the left) and another register.
  271.         Thus each location in memory can be accessed by many (up to 4096)
  272.         combinations of segment and offset.  For example segment 1000h,
  273.         offset 1000 (generally written as 1000:1000) can also be addressed
  274.         as 1001:0ff0, as the sum of both of these add up to 11000h.  Each
  275.         of the segment registers has another register that is hardware as-
  276.         sociated with it but that can sometimes be overridden in the in-
  277.         struction.  The IP (instruction pointer) is firmly attached to the
  278.         CS segment.  The SP (stack pointer) always points to a location in
  279.         the SS (stack segment).  DI refers mainly to a location in ES
  280.         as SI does to DS.
  281.                 In standard programming parlance there is the code
  282.         segment, the stack segment, and the data segment written in
  283.         various ways such as code_seg. High level language compilers
  284.         insist on this division and MASM forces you to at least define
  285.         them, but you should keep in mind that they are only conveniences
  286.         and should be discarded when they cease to be convenient.
  287.                 In the following discussion I want to make a distinction
  288.         between two types of data. The first is data that the program
  289.         contains or uses as intermediate storage. This would include
  290.         variables addressed in the code, messages to the user, and data
  291.         buffers that operated on. The second type is external to the
  292.         program. An example of this is a text file that your program will
  293.         edit. Let me call the first type program data and the second type
  294.         external data. The dividing line is very loose and often ceases
  295.         to exist but it is a convenient fiction for now.
  296.                 The one unchangeable fact that we have to deal with is the
  297.         way DOS loads the programs. There are two formats it can
  298.         follow: the .COM  format and the .EXE format. The COM format loads
  299.         quickly because it is simply an image of the machine code and
  300.         needs no processing by DOS in order to execute. It is limited in
  301.         size to 64k, but I have never seen an assembly language program
  302.         that was that large so it is really not much of a limit. All
  303.         segment registers are set to the same value on loading (this
  304.         value is the address of the PSP) and the IP
  305.         is set at 100h.
  306.                 The EXE format is not limited to size but it requires post
  307.         processing by DOS in order to work. This makes it slower to begin
  308.         execution. This is also the format that is compatible with the
  309.         source level debuggers. During linking the linker assigns segment
  310.         offset values to each of the segments you define in your code.
  311.         After loading DOS adds this offset value to each location in your
  312.  
  313.  ;page 5
  314.  
  315.  
  316.         code that addresses a segment. This information is contained in a
  317.         relocation table that the linker prepends to the file. Then DOS
  318.         sets the CS register to the start of your code segment and the SS
  319.         register to the start of your stack segment, and DS and ES to the
  320.         start of the PSP. The IP is set to the offset specified in the END
  321.         statement as the start of execution.
  322.                 Using either format you are still left with a mess to
  323.         attend to. Your program data area is not defined or addressed,
  324.         your stack is out of control (if .COM), and your program owns the entire
  325.         address space in the computer from the start of your program to
  326.         the end of memory. The first responsibility of any program is to
  327.         clean this up. The methods of doing this are very simple and can
  328.         be s standard header to all of your programs. I won't go into them
  329.         now, but will try to cover them next issue. For now let's assume
  330.         that you have attended to that and your whole program with code,
  331.         stack and program data occupy a few thousand bytes above the
  332.         PSP,and you have returned everything else to DOS. This is the
  333.         ideal starting point for any program. Whatever other memory you
  334.         need for external data can be requested from DOS and it knows how
  335.         much is there and unused which your program doesn't. It will
  336.         return to you the segment address of the block you requested. This
  337.         then you can subdivide into as many segments as you like. For
  338.         example: you are keeping a database of 10,000 names. Each name
  339.         could be considered to be 2 segments long (32 characters) so you
  340.         could move from name to name by adding 2 to the segment register
  341.         you are using to address this space. Doing it this way frees you
  342.         from the 64k limit you would have if instead you used one of the
  343.         index registers and added 32 to it.
  344.                 This is a complex subject to try and explain, especially
  345.         in a short column. More techniques will be discussed next issue.
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374. ;page 6
  375.  
  376.  
  377.  
  378.                 A fool rambles about Keyboard driven TSR programs.
  379.                                      by
  380.         Garrett P.  Nievin 4518 Valley Brook Dr.  San Antonio, TX 78238
  381.  
  382.                                 o Introduction
  383.  
  384.             First of all, let me describe exactly how a keyboard driven TSR
  385.         SHOULD work, to be a friendly inhabitant of your system.  To me,
  386.         there are two kinds of such programs:  those which modify keyboard
  387.         functioning (as in the case of Superkey), and those which merely
  388.         check for keystrokes to activate a resident function (such as
  389.         Sidekick).  I will focus my discussion on the latter, but the
  390.         basic principles apply to any keyboard TSR.
  391.  
  392.            o Narrative of how a friendly TSR handles the keyboard.
  393.  
  394.             To reliably and safely monitor the keyboard for a keypress, a
  395.         program must install an interrupt handler for interrupt 9, which
  396.         is hardware generated every time a key is pressed or released.
  397.         For now let's assume we have a routine in memory and is the active
  398.         interrupt 9 handler.  Every time a key is pressed or released, our
  399.         program automagically wakes up.  The only affected registers are
  400.         CS:IP, which point to where our program is executing of course.
  401.         Our program should IN a byte from the keyboard port; this is the
  402.         scancode which we have been summoned to service.  Since the TSR
  403.         program is only checking for a certain keyboard condition (such as
  404.         an Alt-Q being hit), all other conditions should be ignored.  If
  405.         it is not "our" key, then we want to do nothing more.  To relin-
  406.         quish control, we do a long JMP to the old interrupt 9 handler
  407.         (which may be BIOS ROM, or it may be another TSR.  In this friend-
  408.         ly manner, any number of TSR's may happily coexist).  If it IS our
  409.         key, we perform whatever action is appropriate, and terminate by
  410.         one of two methods:  jump to the old int handler, which allows the
  411.         rest of the TSR's and/or BIOS to get at the same keypress; or,
  412.         terminate the interrupt ourselves.  This second method involves 3
  413.         basic steps:  1) Tell the keyboard we have serviced his keypress
  414.         2) Tell the hardware interrupt controller we have serviced the
  415.         hardware interrupt to completion and 3) perform and IRET (return
  416.         from interrupt) instruction to continue with system processing.
  417.  
  418.                           o How to read the keyboard
  419.  
  420.             The keyboard is driven by an 8048 chip, which is tied logically to
  421.         the 8259A Peripheral Interrupt Controller (as level 1; only the
  422.         timer interrupt at level 0 has more priority) and to the port A
  423.         and port B of the 8255A-5 Programmable Peripheral Interface chip.
  424.         I only give you these numbers to impress people with; that, and to
  425.         get a little better understanding of what all happens.  The scan
  426.         code of a keypress gets placed in port A of the 8255, which is
  427.         mapped to I/O port 60h of the CPU.  All keypress scancodes will be
  428.         in the range 01 (Escape) to 53h (Delete).  If the high bit is set
  429.         on, then it is not a keypress scancode, but a key release scan-
  430.         code.  These are usually ignored, but must be processed non-
  431.         etheless.
  432.  
  433.  
  434.  
  435.         ;page 7
  436.         
  437.  
  438.             Port A can be safely IN'd from any number of times before the
  439.         keyboard is cleared; this is done by getting port B (IN AL,61h),
  440.         set the hi bit on (OR AL,80h) and outing it back to port B.  Once
  441.         the keyboard is cleared, you usually want to tell the 8259 PIC
  442.         that the interrupt you've been servicing has been completed by
  443.         outing 20h to port 20h.  The 8259 prioritizes all interrupts, and
  444.         this command tells it that the highest priority interrupt is
  445.         finished; this is neat because all the interrupt handlers don't
  446.         have to know what level interrupt they are.
  447.  
  448.             Now comes the obvious question:  How are we going to check for 2
  449.         keys, as in the case of say Alt Q?  BIOS makes this one easy.  In
  450.         the BIOS/DOS data area (segment 40), at bytes 17h and 18h, we find
  451.         information on which special keys are being pressed.  The sig-
  452.         nificant bits are:
  453.  
  454.            17h xxxxXXXX 18h XXXXxxxx 1 Alt is being pressed 1 Insert
  455.            is being pressed 1 Ctrl 1 Caps Lock 1 Left shift 1 Num
  456.            Lock 1 Right shift 1 Scroll Lock
  457.  
  458.             All we do is wait for the scancode of Q to come up.  Then we check
  459.         the appropriate bit in the appropriate flag byte (in the case of
  460.         alt, we would test 0040:0017h for 08h).  If the bit is on, we do
  461.         our thing.  Otherwise we just pass control on to the next in-
  462.         terrupt handler in the string with our long JMP.  NOTE:  always
  463.         use a "normal" key as a "wakeup call"; that is, don't check for
  464.         combos like ALT-Rshift.  There are too many programs already that
  465.         do this, and programs employing these keys are difficult to chan-
  466.         ge, thereby ensuring incompatibilities.  In fact, if you dis-
  467.         tribute your program and don't offer some means of "hot key" con-
  468.         figuration, you may want to tell your users where your scan codes
  469.         are located in the program so they may patch them themselves to
  470.         avoid incompatibilities.  Hint:  use a CMP and not a TEST to check
  471.         this byte, or if you are looking for ctrl-A then ctrl-alt-A,
  472.         ctrl-shift-A, etc.  will all mistakenly trigger your interrupt.
  473.  
  474.                            o How to install the TSR
  475.  
  476.             The installation program will consist of 3 parts really:  the jump
  477.         around the interrupt handler code to the install code, and the in-
  478.         terrupt and install code areas.  The install code should do basi-
  479.         cally two things:  install the interrupt handler using service 25h
  480.         of interrupt 21h (DOS call), and of course
  481.         terminate and-stay-resident.  To do the install, load AX with 2509h
  482.         (AL has the interrupt number) and DS:DX with the address of the
  483.         interrupt handler code, and do an int 21h.  Your program is RIGHT
  484.         NOW the new interrupt 9 handler.  Then, load AX with 3100h and do
  485.         an int 21h again (Terminate and stay res and return an err code of
  486.         00 to parent).  At this point the handler is working, in memory,
  487.         and control is released back to the parent program (in most cases
  488.         Command.com).
  489.  
  490.             Here is our opportunity to start getting fancy.  To keep memory
  491.         usage to a minimum, we should do a DOS service 4Ah to release all
  492.         unneeded memory.
  493.  
  494.  
  495.  
  496.         ;page 8
  497.         
  498.  
  499.            /* UPDATE:  I don't know what I was thinking here, but
  500.            that's wrong.  You don't use service 4Ah in a TSR; it
  501.            would do nothing.  What you DO do is load the number of
  502.            paragraphs you need to keep into the DX register when you do
  503.            your service 31h call.  The way I get that is to use:
  504.            ((last_address-first_address)/16)+1 (to div by 16 just shift
  505.            right 4 bits) And don't forget to allow room for your PSP!  */
  506.  
  507.             To REALLY cut down on the memory, we can relocate our program
  508.         backwards into the unused PSP area, saving something like 164
  509.         bytes.  Also, we can leave a memory signature so that the user is
  510.         not allowed to install the TSR more than once.  My usual method of
  511.         this is pretty simplistic.  I put 4 unique bytes into the TSR it-
  512.         self, and then upon installation check if those bytes are there.
  513.         If so, the installation aborts and the user is told.  The flaw
  514.         here is that it only prevents the same program being installed
  515.         after itself.  If such a TSR is loaded and takes int 9, another
  516.         one is later loaded and takes int 9 also, the program could then
  517.         be installed for the second time.  I know how my system is con-
  518.         figured, so this is no problem.  To a novice user getting hold of
  519.         one of my programs, this will at best just waste a little memory.
  520.         At worst, the system can get a little weird.  To more securely
  521.         guard against re-installation, you may take another interrupt vec-
  522.         tor (there are 256, after all, and only a couple dozen are used in
  523.         a basic PC).  The way that works is:  search for an empty in-
  524.         terrupt vector (one which has all zeros), and take one when you
  525.         find it.  Save a memory signature there.  When the program in-
  526.         stalls the TSR code, search the interrupt vectors for your memory
  527.         signature.  If you find it, you know your program is there al-
  528.         ready.  Much safer.  (Aside:  For my personal use, I combine all
  529.         my TSR's into one program.  This saves memory, time, and trouble.
  530.         It also keeps me from installing TSR's in between one another!)
  531.  
  532.                     o What you can get away with in a TSR
  533.  
  534.             If you have read this far, I assume you don't already know all
  535.         this.  So, I will not go into all the undocumented MS-DOS services
  536.         for TSR writers.  If you are interested in them, I suggest you
  537.         check back issues of magazines like Programmer's Journal and Dr.
  538.         Dobb's.  Anyway, you are restricted as to what can happen inside a
  539.         TSR.  It all boils down to one thing:  MS-DOS is not reentrant.
  540.         It is not meant to be multitasking (under programs like DoubleDos,
  541.         there are copies of DOS for each task running), and so a routine
  542.         can not be called while it is already executing for somebody else.
  543.         Here is a scenario:  You are saving a document from your word
  544.         processor, and during the wait call up a TSR to find a phone num-
  545.         ber or something.  The TSR does a disk read of your phone # file.
  546.             The TSR finishes and exits back to the word processor.  Now, the
  547.         WP's disk write has been interrupted, losing vital information
  548.         like where on the disk he was writing, etc.  MS-DOS goes awry.  It
  549.         is time for the big red switch, and kiss your document adios.
  550.         Hope your disk is not messed up as well.
  551.  
  552.             There is the why of all this, now here is the what.  A TSR may not
  553.         use any DOS int 21h services higher than 0Ch.  It is restricted to
  554.         console and printer I/O services.  (Now, this is of course not
  555.         TOTALLY true, but how to do disk I/O etc.  are beyond the scope of
  556.         this little rambling.  Maybe some other time.)
  557.  
  558.         ;page 9
  559.         
  560.  
  561.            /* UPDATE Okay, here's how to do anything you please from
  562.            within a TSR, including disk I/O.  The BEST way is to install
  563.            interrupt "front-end" handlers for int 13h (BIOS disk I/O),
  564.            int 21h (DOS), int 25h (absolute disk read), int 26h (absolute
  565.            disk write), and I think that's all.  In these front-end hand-
  566.            lers, set a flag (or semaphore or TS byte or whatever you want
  567.            to call it) whenever anyone is in the middle of a disk I/O.
  568.            Then, in your TSR, don't do a disk I/O if any of these flags
  569.            are set.  You will also need to steal the user timer tick in-
  570.            terrupt (1Ch) to periodically check for when those interrupts
  571.            are free for use.  Or, you can use the cheater way (which is
  572.            used by DOS itself):  Whenever DOS is waiting for a keypress,
  573.            it calls int 28h (undocumented).  The only program I know of
  574.            "legally" using this is the PRINT command.  Whenever int 28h
  575.            is called, you should be free to do whatever you want.  If you
  576.            want more immediate access to the disk, though, you'll need to
  577.            use the timer int (1Ch) again.  ONCE, at initialization time,
  578.            do an int 21h ah=34h.  In ES:BX, you will have the address of
  579.            a byte called INDOS by most folks.  This is an undocumented
  580.            function which has been officially declared off-limits by
  581.            Microsoft, but nobody pays attention to them anyway.  As far
  582.            as I know, it works fine in all versions of MS-DOS as of today
  583.            (April 1988).  In your timer interrupt servicer, read the byte
  584.            at the address you got from service 34h.  If it's not zero,
  585.            don't do anything over service 0ch; if it's zero, go crazy.
  586.            What this byte is (I'm told) is a count of how many calls deep
  587.            DOS is into itself.  The actual value is of no relevance to
  588.            us, just if it is zero or not.  Now, I don't see this helping
  589.            much if the program is doing BIOS I/O, but I don't use any
  590.            software I know of which uses BIOS for disk I/O.  Also, if the
  591.            application is doing direct-to-the-hardware disk I/O, I don't
  592.            think you probably want to be messing with this stuff.  Again,
  593.            I don't use anything that I know of doing this.
  594.  
  595.                 I've written several programs using the int 28h/service 34h combo
  596.         to do TSR disk I/O and have never had a single problem, and I
  597.            tested them in the middle of all kinds of disk accesses.  This
  598.         does not mean it's always cool, though.  If you can help it, al-
  599.         ways avoid undocumented stuff.  In my opinion, Microsoft won't
  600.         change it because so much software relies on it now, but I've
  601.         learned not to trust them.
  602.  
  603.                   o Example program complete with flimsy excuses
  604.  
  605.                 The Sperry PC has a high-res graphics screen which is treated as a
  606.         logically different display from the normal text screen, and uses
  607.         different display memory banks.  The text bank, called screen A,
  608.         can be superimposed over the graphics (called screen B) on the
  609.         screen simultaneously.  This program switches between screen A on-
  610.         ly, screen B only, and screen A superimposed on screen B.  This
  611.         program is for example only, and you should not attempt to run it
  612.         on a CGA.  If something gets fried, it's not my fault.  It looks
  613.         for a keypress of Alt-Esc, goes into action, and then quits.
  614.  
  615.  
  616.                 I hope this has been helped you understand how a basic keyboard
  617.         driven TSR works.  If you have any more questions, feel free to
  618.         contact me with them, and I will find you an answer.  Most ad-
  619.         vanced TSR functions (almost all are undocumented by Microsoft and
  620.  
  621.         ;page 10
  622.         
  623.  
  624.         IBM!) have been discussed in Byte, PC Tech Journal, and Dr.
  625.         Dobb's Journal, but have been thoroughly discussed in Programmer's
  626.         Journal.  I highly recommend this publication, and hope more
  627.         people will subscribe, so it does not fold up and deprive me of
  628.         all the information it provides.
  629.  
  630.  
  631.         Call the Telstar BBS:  (512)822-8882 for a good time
  632.  
  633.  
  634.  
  635.  
  636.         Garrett P.  Nievin  has also contributed a piece of code to service a
  637.         soft breakout switch for Symdeb and Debug. Please see the listing in
  638.         the source code section. Both of these are extremely well commented
  639.         and should be quite useful.
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664.  
  665.  
  666.  
  667.  
  668.  
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675.  
  676.  
  677.  
  678.  
  679.  
  680.  
  681.  
  682. ;page 11
  683.  
  684.  
  685.  
  686.                               Hex Conversion Routines
  687.  
  688.                 Just a little "quicky" to fill out this issue. These are a
  689.         couple of routines that I use regularly in a variety of ways. They are
  690.         both fast and fairly tightly coded and they work. I hope you find them
  691.         of some use.
  692.  
  693.                 The first, DECHEX, takes an ASCII number pointed to by SI and
  694.         returns a hex number in AX. The other just reverses the process, and
  695.         when used with the little MOV_ASCII puts it where you tell it to.
  696.  
  697. ;~
  698.  DECHEX:                         ;THIS ROUTINE WILL TAKE A [CL] (MAX 5) DIGIT
  699.                                 ;ASCII DECIMAL NUMBER POINTED TO BY SI AND
  700.                                 ;RETURN A 4 DIGIT HEX NUMBER IN AX.*
  701.                 XOR     DH,DH
  702.                 XOR     AX,AX
  703. TRY:            CMP     CL,1
  704.                 JBE     LASTA
  705.                 MOV     DL,[SI]
  706.                 SUB     DL,"0"
  707.                 ADD     AX,DX
  708.                 MOV     BX,AX
  709.                 SHL     AX,1
  710.                 SHL     AX,1
  711.                 SHL     AX,1
  712.                 ADD     AX,BX
  713.                 ADD     AX,BX
  714.                 INC     SI
  715.                 LOOP    TRY
  716. LASTA:           MOV     DL,[SI]
  717.                 SUB     DX,"0"
  718.                 ADD     AX,DX
  719.                 RET
  720.  
  721.  
  722. HEXDEC:         ;THIS ROUTINE WILL TAKE A 4DIGIT HEXADECIMAL NUMBER IN AX AND
  723.                 ;RETURNS A 5 DIGIT ASCII IN BH,BL,DH,DL,AL.
  724.                 ;TIME AVERAGES ABOUT 140 CLOCKS PER DIGIT
  725.                 ;LEADING 0'S ARE SUPRESSED
  726.                 MOV     BX,0
  727.                 MOV     CX,0
  728.                 MOV     DX,0
  729. A10K:           CMP     AX,10000
  730.                 JB      A1K
  731.                 SUB     AX,10000
  732.                 INC     BH
  733.                 JMP     A10K
  734. A1K:            CMP     AX,1000
  735.                 JB      HUNDREDS
  736.                 SUB     AX,1000
  737.                 INC     BL
  738.                 JMP     A1K
  739. HUNDREDS:       CMP     AX,100
  740.                 JB      TENS
  741.                 SUB     AX,100
  742.                 INC     DH
  743.                 JMP     HUNDREDS
  744. ;page 12
  745.  
  746.  
  747. TENS:           CMP     AX,10
  748.                 JB      UNITS
  749.                 SUB     AX,10
  750.                 INC     DL
  751.                 JMP     TENS
  752. UNITS:
  753.                 MOV     AH,'0'
  754.                 ADD     BH,AH
  755.                 ADD     BL,AH
  756.                 ADD     DH,AH
  757.                 ADD     DL,AH
  758.                 ADD     AL,AH
  759.                 CMP     BH,AH
  760.                 JNZ     UEND
  761.                 MOV     BH,020H
  762. U1:
  763.                 CMP     BL,AH
  764.                 JNZ     UEND
  765.                 CMP     BH,020H
  766.                 JNZ     UEND
  767.                 MOV     BL,020H
  768.                 CMP     DH,AH
  769.                 JNZ     UEND
  770.                 CMP     BL,020
  771.                 JNZ     UEND
  772.                 MOV     DH,020H
  773.                 CMP     DL,AH
  774.                 JNZ     UEND
  775.                 CMP     DH,020
  776.                 JNZ     UEND
  777.                 MOV     DL,020H
  778. UEND:
  779.                 RET
  780.  
  781. MOV_ASCII:                              ;THIS TAKES THE DIGITS PRODUCED BY
  782.                                         ;HEXDEC AND PUTS THEM AT DS:SI
  783.                 MOV     [SI],BH
  784.                 INC     SI
  785.                 MOV     [SI],BL
  786.                 INC     SI
  787.                 MOV     [SI],DH
  788.                 INC     SI
  789.                 MOV     [SI],DL
  790.                 INC     SI
  791.                 MOV     [SI],AL
  792.                 RET
  793. ;~
  794.  
  795.  
  796.  
  797.  
  798.  
  799.  
  800.  
  801.  
  802.  
  803.  
  804.  
  805. ;page 13
  806.  
  807.  
  808.                           Book Reviews
  809.  
  810.         The Programmers' Reference
  811.  
  812.                 I made a quick review of this last month, but I have since
  813.         gone over it thoroughly and received the extended package from the
  814.         author.  This is NOT an instruction book for beginners.  It is
  815.         just what it names itself- a reference manual.
  816.                 The shareware version is 10 chapters (about 600k bytes) of
  817.         solid information and a table of contents. Much of the information
  818.         is very difficult to find elsewhere. The first chapter is a quick
  819.         history of DOS from 1.0 to 4.0. Chapter 2 has the Port addresses
  820.         and the Interrupts up to 0fh.  Chapter 3 has the true Bios
  821.         interrupts 10h to 1fh and it throws in INT 20h for some strange
  822.         reason. This isn't just a listing that you might find in many
  823.         places, but a detailed description with calling conventions and
  824.         special things to watch out for. It includes semi-documented
  825.         functions such as all of the Desqview and Topview int patches that
  826.         go into this area. Each interrupt lists what machines it is
  827.         included in from Tandy to PCjr to PS-2 model 80. I haven't counted
  828.         them, but there must be thousands.
  829.                 The DOS interrupts 20h through 4fh are covered in similar
  830.         detail, with many notes and application information.
  831.                 Further chapters contain information on file structures,
  832.         EMS memory, and many other topics.
  833.                 The registered version gives another disk full of
  834.         miscellaneous data that is rare and useful.
  835.                 The $15 price is one of the greatest bargains to be found.
  836.         Available on many BBS's as ####ref.??? such as 1029ref.zip. This
  837.         says that it is the October 29th release, and the extension is up
  838.         to the Sysop.
  839.  
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865.  
  866. ;page 14
  867.  
  868.  
  869.                         Source Code for Keyboard TSR
  870.  
  871.  
  872. ; High Res screen A/B toggler for Sperry PC, the best PC around
  873. ; Written for MASM 4.0
  874. code    segment para public 'code'
  875.         assume cs:code,ds:code,es:code
  876.         org     0100h           ; .COM format
  877. start   proc    far
  878.  
  879. ; Equates - ports, locations, values
  880. ; Using equates makes the program much easier to change later;
  881. ; to use a different scancode here, for example, you would just
  882. ; change the equate for "esc".
  883.          if1                    ; only assemble equates on pass 1
  884. portB    equ    61h             ; 8259 port B - used to clear scancode 
  885. keyport  equ    60h             ; 8259 port A - keyboard scan codes
  886. esc      equ    01h             ; scan code for Escape key
  887. hibiton  equ    80h             ; hi bit on for keybreak scan code & reset
  888. hibitof  equ    7fh             ; hi bit off for keybd reset
  889. DOS_area equ    40h             ; segment of BIOS/DOS data area
  890. shftstat equ    17h             ; keybd shft status flag in DOS area
  891. shift    equ    00000011b       ; value for shftstat meaning either shift is on
  892. eoi      equ    20h             ; end of interrupt flag
  893. comdport equ    20h             ; 8259 command port
  894.          endif
  895.  
  896. begcode:
  897.         jmp     implant         ; jump around interrupt handler code
  898. begres:         ; area to remain core resident
  899.  
  900. rescode proc                    ; keystroke causes jump to resident code here
  901.  
  902.         jmp     oversign        ; jump over memory signature
  903.         db      'abGN'          ; program signature in memory
  904. ; I use my initials in uppercase and a 2-byte program ID in lowercase
  905.  
  906. ; Variables
  907.  
  908. mode    db      0               ; superimpose mode: 0-A,1-B,2-Both,3-None
  909. oldint9 dw      0,0             ; doubleword value of old int9 vector
  910.  
  911. oversign:       ; start of code for new interrupt 09h handler
  912.  
  913.         push    ax              ; save that register
  914.         push    ds              ; save DS.
  915.         mov     ax,DOS_area     ; DOS data segment
  916.         mov     ds,ax           ;   now covered by DS
  917.         test    byte ptr ds:[shftstat],shift ; is a shift being held now?
  918.         jz      normal          ; nope, not a hot key, pass it on to old int
  919.         in      al,keyport      ; yes, get keyboard scan code
  920.         cmp     al,esc+hibiton  ; was it release of escape?
  921.         je      abnorm          ; yes, lose that scan code
  922.         cmp     al,esc          ; was it an escape?
  923.         jne     normal          ; nope, skip the important stuff
  924. ;
  925.         mov     al,mode         ; get mode
  926.         cmp     al,2h           ; both screens on?
  927.  
  928. ;page 15
  929.  
  930.  
  931.         je      aonly           ; yes, go back to first
  932.         add     al,1h           ; add 1 to hi nybble to go  B to A to AB
  933.         jmp     nextmode        ; and go put it back
  934. aonly:                  ; start back with screen A only
  935.         xor     al,al           ; turn off
  936. nextmode:               ; put in new mode and quit
  937.         mov     mode,al         ; move in new mode
  938.         mov     ah,15h          ; set superimpose mode function of int 10h
  939.         int     10h             ; and go change mode
  940.         jmp     abnorm          ; lose scan code
  941. ;
  942.  
  943. abnorm:         ; abnormal handling of scan code.  to the bit bucket with it.
  944.         in      al,portB        ; get portB
  945.         or      al,hibiton      ; set acknowledge / clear keyboard bit
  946.         out     portB,al        ; and out it again
  947.         and     al,hibitof      ; clear ack bit
  948.         out     portB,al        ; out that, enabling keyboard again
  949.         cli                     ; no interruptions please, Mrs. a-Whiggins
  950.         mov     al,eoi          ; end-of-interrupt command
  951.         out     comdport,al     ; send it to the 8259
  952.         pop     ds              ; restore
  953.         pop     ax              ;   registers
  954.         sti                     ; interruptable again
  955.         iret                    ; quit without performing normal interrupt
  956.  
  957. normal:         ; not hot key, pass scan code on to normal (maybe) int9
  958.         pop     ds              ; restore all
  959.         pop     ax              ;   registers I messed with
  960.         jmp     dword ptr cs:oldint9    ; goto old int9 handler
  961.  
  962.  
  963. ; all code from here out is based on Norton's guide, and I use it in
  964. ; all my TSR's.
  965.  
  966. reslen  equ     endres - begres         ; length of new resident code
  967. strtres equ     begres - begcode + 100h ; start of resident code
  968. psplen  equ     5ch                     ; length of necessary PSP
  969.  
  970. implant:        ; code to put new int 9 front end in core
  971.         mov     ax,3509h        ; get int vector function
  972.         int     21h             ; get vector of interrupt 9 handler
  973.         cmp     es:[bx+3],'ba'  ; am I already loaded?
  974.         jne     fresh           ; nope, go install
  975.         cmp     es:[bx+5],'NG'  ; make sure I'm not already in
  976.         jne     fresh           ; naaah, go install
  977.         lea     dx,cs:stalemsg  ; DX points to already installed message
  978.         mov     ah,09h          ; DOS display string func       
  979.         int     21h             ; go display message
  980.         int     20h             ; and quit
  981.         
  982. fresh:
  983.         lea     dx,cs:instlmsg  ; DX points to installation message 
  984.         mov     ah,09h          ; display string function
  985.         int     21h             ; give the user the poop
  986.         mov     ax,3509h        ; get int vector function
  987.         int     21h             ; get vector of old interrupt 9 handler
  988.         mov     oldint9,bx      ; int location in ES:BX, save it
  989. ;page 16
  990.  
  991.  
  992.         mov     oldint9+2,es    ; "
  993.         mov     ax,2509h        ; set new interrupt 9 vector to me
  994.         mov     dx,offset rescode       ; address of which is in DX
  995.         int     21h             ; go do it
  996.         push    cs              ; DS and ES both end
  997.         pop     es              ; up pointing at
  998.         push    cs              ; code area
  999.         pop     ds              ; "
  1000.         mov     di,psplen       ; where program will end up
  1001.         mov     si,strtres      ; start of resident code
  1002.         mov     cx,reslen       ; amount of resident code to move
  1003.         cld                     ; go forward in move
  1004.         rep movsb               ; move code back in mem
  1005.         mov     dx,psplen + reslen      ; DX pointing to next free paragraph
  1006.         mov     ax,3100h        ; keep, return code of 0
  1007.         int     21h             ; terminate
  1008.  
  1009. stalemsg db     'Screen A/B toggle is already installed and active!',13,10,7,7
  1010. instlmsg db      'High Res Screen A/B toggle',13,10
  1011.         db      'Shift/Escape toggles screen A only, then B only, then A/B.'
  1012.         db      13,10,'$'
  1013.                 
  1014. start   endp
  1015. code    ends
  1016.         end     start
  1017.  
  1018.  
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048. ;page 17
  1049.  
  1050.  
  1051.                              Source for Soft Breakout
  1052.  
  1053.  
  1054. ; BUGOUT.COM
  1055. ; Program to add wimpy "soft" breakout key to DEBUG and SYMDEB
  1056. ;
  1057. ; MASM compatible source code
  1058. ;
  1059. ; Hitting the '5' on keypad forces an int 3 (debug breakpoint)
  1060. ; After breakpoint, add 1 to IP register and trace through IRET
  1061. ;
  1062. ; By Garrett P. Nievin
  1063. ;
  1064. ; (BTW, to add a hardware breakout switch just put a switch between
  1065. ; pins 17 (NMI) and 40 (+5V) on your 8088 chip, and a switch between
  1066. ; pins 21 (RESET) and 40 will do a system reset/reboot.)
  1067.  
  1068.  
  1069. code    segment para public 'code'
  1070.         assume cs:code,ds:nothing,es:nothing
  1071.         org     0100h
  1072.  
  1073. hotkey  equ     4ch         ; scan code for hot key = "5" on keypad
  1074. portA   equ     60h         ; 8255A port A, usually keybd scan code
  1075. portB   equ     61h         ; 8255A port B, various switches
  1076. release equ     80h         ; hi bit in scan code means key release
  1077. hibiton equ     80h         ; hi bit in byte for or'ing in
  1078. hbitoff equ     7fh         ; hi bit in byte for and'ing out
  1079.  
  1080. start   proc    far
  1081. begcode:
  1082.     jmp  implant            ; jump around interrupt handler code
  1083. begres:                     ; area to remain core resident
  1084. rescode  proc               ; keystroke causes jump to here
  1085.     jmp  over               ; jump over memory signature
  1086.     db  'bcGN'              ; program signature in memory
  1087. over:                       ;
  1088.     sti                     ; allow interrupts
  1089.     push ax                 ; save that register
  1090.     in   al,portA           ; get keyboard scan code
  1091.     cmp  al,hotkey          ; hotkey?
  1092.     jne  normal             ; yes, go hanlit
  1093.     push dx                 ; save register
  1094.     mov  dx,0020h           ; port 20h = PIC port to send EOI to
  1095.     mov  al,dl              ; 20h turns on EOI bit
  1096.     out  dx,al              ; tell interrupt controller we be done
  1097.     pop  dx                 ; restore register
  1098.     in   al,portB           ; get portB
  1099.     or   al,hibiton         ; set acknowledge / clear keyboard bit
  1100.     out  portB,al           ; and out it again
  1101.     and  al,hbitoff         ; clear ack bit
  1102.     out  portB,al           ; out that, enabling keyboard again
  1103.     pop  ax                 ; restore original register
  1104.     int  3                  ;
  1105.     iret                    ;
  1106.  
  1107. ;page 18
  1108.  
  1109.  
  1110. normal:                     ;
  1111.     pop  ax                 ; restore that register
  1112.     jmp  dword ptr cs:oldint9    ; goto old int9 handler
  1113. oldint9  dw  0,0            ; doubleword value of old int9 vector
  1114. rescode  endp
  1115.  
  1116. endres:                     ; end of core res area
  1117.  
  1118. reslen  equ endres - begres           ; length of new resident code
  1119. strtres equ begres - begcode + 100h   ; start of resident code
  1120. psplen  equ 5ch                       ; length of necessary PSP
  1121.  
  1122. implant:                    ; code to put new int 9 front end in core
  1123.     mov  ax,3509h           ; get int vector function
  1124.     int  21h                ; get vector of interrupt 9 handler
  1125.     cmp  es:[bx+3],'cb'     ; already loaded?
  1126.     jne  fresh              ; nope, go install
  1127.     cmp  es:[bx+5],'NG'     ; make sure
  1128.     jne  fresh              ; naaah, go install
  1129.     lea  dx,cs:stalemsg     ; DX points to already installed message
  1130.     mov  ah,09h             ; DOS display string func
  1131.     int  21h                ; go display message
  1132.     mov  ax,4cffh           ; terminate with code = 0xff
  1133.     int  21h                ;
  1134.         
  1135. fresh:
  1136.     lea  dx,cs:instlmsg     ; DX points to installation message
  1137.     mov  ah,09h             ; display string function
  1138.     int  21h                ; give the user the poop
  1139.     mov  ax,3509h           ; get int vector function
  1140.     int  21h                ; get vector of old interrupt 9 handler
  1141.     mov  oldint9,bx         ; int location in ES:BX, save it
  1142.     mov  oldint9+2,es       ; "
  1143.     mov  ax,2509h           ; set new interrupt 9 vector to me
  1144.     mov  dx,offset rescode  ; address of which is in DX
  1145.     int  21h                ; go do it
  1146.     push cs                 ; DS and ES both end
  1147.     pop  es                 ; up pointing at
  1148.     push cs                 ; code area
  1149.     pop  ds                 ; "
  1150.     mov  di,psplen          ; where program will end up
  1151.     mov  si,strtres         ; start of resident code
  1152.     mov  cx,reslen          ; amount of resident code to move
  1153.     cld                     ; go forward in move
  1154.     rep  movsb              ; move code back in mem
  1155.     mov  dx,psplen + reslen ; DX pointing to next free paragraph
  1156.     mov  ax,3100h           ; keep, return code of 0
  1157.     int  21h                ; terminate
  1158. stalemsg db 'Bugout already resident.',10,13,7,'$'
  1159. instlmsg db 'Bugout loaded and active, keypad-5 is break key.',10,13,'$'
  1160. start    endp
  1161. code     ends
  1162.     end  start
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168. ;page 19
  1169.  
  1170.