THE ASSEMBLY LANGUAGE "MAGAZINE" #3 1989






THE ASSEMBLY LANGUAGE "MAGAZINE"                  VOL 1 NUMBER 3
                                                  May, 1989

















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



















Written by and for assembly language programmers.






                         Table of Contents

        Table of Contents. . . . . . . . . . . . . . . . . . . . . . 2

        Editorial. . . . . . . . . . . . . . . . . . . . . . . . . . 3

        GUIDE LINES FOR CONTRIBUTORS . . . . . . . . . . . . . . . . 4

        Beginners'Corner . . . . . . . . . . . . . . . . . . . . . . 5
          Segmentation . . . . . . . . . . . . . . . . . . . . . . . 5

        Keyboard driven TSR programs.. . . . . . . . . . . . . . . . 7

        Hex Conversion Routines . . . . . . . . . . . . . . . . . . 12

        Book Reviews. . . . . . . . . . . . . . . . . . . . . . . . 14

        Source Code for Keyboard TSR. . . . . . . . . . . . . . . . 15

        Source for Soft Breakout. . . . . . . . . . . . . . . . . . 18







































;page 2




                                      Editorial

                This is the third issue of the Magazine, and the first with a
        major article from an outside contributor.  Our thanks to Garrett
        Nievin.

                It is amazing how few programmers really appreciate
        the benefits of assembly language programming.  Most of them under-
        stand that for certain parts of programs it can increase performance,
        but they have no real conception of the amount of improvement that it
        can make.

                As a common example of this-- The case of sprite
        manipulation.  Some of the more speed conscious programmers are
        aware that to do clean writes to the CGA screen you need to wait
        for the retrace periods, but a C programmer cannot chase the
        electron beam around the screen to update it in areas that will
        not be affected until it again goes over it.  This multiplies the
        time available to manipulate areas of the screen without flicker.

                Much of the time in executing a higher level routine is
        spent in calling it and returning from it.  The indexed with of-
        fset stack operations are very costly in time.  This is why even
        speedup assembly routines in high level code don't show the full
        capabilities as they are still called using the same conventions.

                One of the most touted buzz words today is "structured".
        This translates into using small easily controlled and understood
        subroutines with a single entry point and a single exit point
        having sharply limited function. This makes for a program that is
        quick and easy to write (regardless of the language) and quick to
        debug. These are all valuable attributes in a program, and if
        done right these same routines can be included in a large variety
        of dissimilar programs.

                There are those who say that any programmer who does not
        keep to "structured" programming is a bad programmer.  At least in
        assembly language programming there are times and reasons for
        throwing this whole concept away.  In doing so you create a
        program that is almost impossible to modify, totally unreadable,
        insane to debug, and a nightmare to try and document----BUT----you
        can also come close to cutting your size (already tiny compared to
        anything else) in half and have a good chance of a thirty percent
        increase in speed if you do it right.  A program like that is not
        the product of a "bad" programmer, but of a very dedicated one.
        In such a program you don't have the time to waste making a lot of
        CALLS or doing variable storage or register adjustments.  The num-
        ber of items that you must keep track of, mostly in your head,
        while writing makes it a project for only the best of programmers.
        I gave it up years ago, but still envy those who are able to make
        use of a powerful tool.









;page 3



                  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 re-
        quired 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, and to
        remove sections.

                Non-exclusive copyright must be given.  No monetary compensa-
        tion 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 ex-
        ist.  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.












;page 4



        Beginners'Corner

                                  Segmentation

                 Segments are largely a carry over from the days when
        processors were all limited to a 16 bit address buss, but we still
        live with them today.  They are not without some benefits however.
        The way they are treated in most of the books I am familiar with
        can leave the novice fear struck over the complexities and this is
        not necessary.  They are nothing more ( to the assembly program-
        mer) than a tool that can either be used or discarded almost at
        will.

                The 8088 has 4 segment registers; CS, DS, ES, and SS.  The
        complete address of a memory reference is the sum of the segment
        register (shifted 1 hex place to the left) and another register.
        Thus each location in memory can be accessed by many (up to 4096)
        combinations of segment and offset.  For example segment 1000h,
        offset 1000 (generally written as 1000:1000) can also be addressed
        as 1001:0ff0, as the sum of both of these add up to 11000h.  Each
        of the segment registers has another register that is hardware as-
        sociated with it but that can sometimes be overridden in the in-
        struction.  The IP (instruction pointer) is firmly attached to the
        CS segment.  The SP (stack pointer) always points to a location in
        the SS (stack segment).  DI refers mainly to a location in ES
        as SI does to DS.
                In standard programming parlance there is the code
        segment, the stack segment, and the data segment written in
        various ways such as code_seg. High level language compilers
        insist on this division and MASM forces you to at least define
        them, but you should keep in mind that they are only conveniences
        and should be discarded when they cease to be convenient.
                In the following discussion I want to make a distinction
        between two types of data. The first is data that the program
        contains or uses as intermediate storage. This would include
        variables addressed in the code, messages to the user, and data
        buffers that operated on. The second type is external to the
        program. An example of this is a text file that your program will
        edit. Let me call the first type program data and the second type
        external data. The dividing line is very loose and often ceases
        to exist but it is a convenient fiction for now.
                The one unchangeable fact that we have to deal with is the
        way DOS loads the programs. There are two formats it can
        follow: the .COM  format and the .EXE format. The COM format loads
        quickly because it is simply an image of the machine code and
        needs no processing by DOS in order to execute. It is limited in
        size to 64k, but I have never seen an assembly language program
        that was that large so it is really not much of a limit. All
        segment registers are set to the same value on loading (this
        value is the address of the PSP) and the IP
        is set at 100h.
                The EXE format is not limited to size but it requires post
        processing by DOS in order to work. This makes it slower to begin
        execution. This is also the format that is compatible with the
        source level debuggers. During linking the linker assigns segment
        offset values to each of the segments you define in your code.
        After loading DOS adds this offset value to each location in your

 ;page 5


        code that addresses a segment. This information is contained in a
        relocation table that the linker prepends to the file. Then DOS
        sets the CS register to the start of your code segment and the SS
        register to the start of your stack segment, and DS and ES to the
        start of the PSP. The IP is set to the offset specified in the END
        statement as the start of execution.
                Using either format you are still left with a mess to
        attend to. Your program data area is not defined or addressed,
        your stack is out of control (if .COM), and your program owns the entire
        address space in the computer from the start of your program to
        the end of memory. The first responsibility of any program is to
        clean this up. The methods of doing this are very simple and can
        be s standard header to all of your programs. I won't go into them
        now, but will try to cover them next issue. For now let's assume
        that you have attended to that and your whole program with code,
        stack and program data occupy a few thousand bytes above the
        PSP,and you have returned everything else to DOS. This is the
        ideal starting point for any program. Whatever other memory you
        need for external data can be requested from DOS and it knows how
        much is there and unused which your program doesn't. It will
        return to you the segment address of the block you requested. This
        then you can subdivide into as many segments as you like. For
        example: you are keeping a database of 10,000 names. Each name
        could be considered to be 2 segments long (32 characters) so you
        could move from name to name by adding 2 to the segment register
        you are using to address this space. Doing it this way frees you
        from the 64k limit you would have if instead you used one of the
        index registers and added 32 to it.
                This is a complex subject to try and explain, especially
        in a short column. More techniques will be discussed next issue.




























;page 6



                A fool rambles about Keyboard driven TSR programs.
                                     by
        Garrett P.  Nievin 4518 Valley Brook Dr.  San Antonio, TX 78238

                                o Introduction

            First of all, let me describe exactly how a keyboard driven TSR
        SHOULD work, to be a friendly inhabitant of your system.  To me,
        there are two kinds of such programs:  those which modify keyboard
        functioning (as in the case of Superkey), and those which merely
        check for keystrokes to activate a resident function (such as
        Sidekick).  I will focus my discussion on the latter, but the
        basic principles apply to any keyboard TSR.

           o Narrative of how a friendly TSR handles the keyboard.

            To reliably and safely monitor the keyboard for a keypress, a
        program must install an interrupt handler for interrupt 9, which
        is hardware generated every time a key is pressed or released.
        For now let's assume we have a routine in memory and is the active
        interrupt 9 handler.  Every time a key is pressed or released, our
        program automagically wakes up.  The only affected registers are
        CS:IP, which point to where our program is executing of course.
        Our program should IN a byte from the keyboard port; this is the
        scancode which we have been summoned to service.  Since the TSR
        program is only checking for a certain keyboard condition (such as
        an Alt-Q being hit), all other conditions should be ignored.  If
        it is not "our" key, then we want to do nothing more.  To relin-
        quish control, we do a long JMP to the old interrupt 9 handler
        (which may be BIOS ROM, or it may be another TSR.  In this friend-
        ly manner, any number of TSR's may happily coexist).  If it IS our
        key, we perform whatever action is appropriate, and terminate by
        one of two methods:  jump to the old int handler, which allows the
        rest of the TSR's and/or BIOS to get at the same keypress; or,
        terminate the interrupt ourselves.  This second method involves 3
        basic steps:  1) Tell the keyboard we have serviced his keypress
        2) Tell the hardware interrupt controller we have serviced the
        hardware interrupt to completion and 3) perform and IRET (return
        from interrupt) instruction to continue with system processing.

                          o How to read the keyboard

            The keyboard is driven by an 8048 chip, which is tied logically to
        the 8259A Peripheral Interrupt Controller (as level 1; only the
        timer interrupt at level 0 has more priority) and to the port A
        and port B of the 8255A-5 Programmable Peripheral Interface chip.
        I only give you these numbers to impress people with; that, and to
        get a little better understanding of what all happens.  The scan
        code of a keypress gets placed in port A of the 8255, which is
        mapped to I/O port 60h of the CPU.  All keypress scancodes will be
        in the range 01 (Escape) to 53h (Delete).  If the high bit is set
        on, then it is not a keypress scancode, but a key release scan-
        code.  These are usually ignored, but must be processed non-
        etheless.



        ;page 7
       

            Port A can be safely IN'd from any number of times before the
        keyboard is cleared; this is done by getting port B (IN AL,61h),
        set the hi bit on (OR AL,80h) and outing it back to port B.  Once
        the keyboard is cleared, you usually want to tell the 8259 PIC
        that the interrupt you've been servicing has been completed by
        outing 20h to port 20h.  The 8259 prioritizes all interrupts, and
        this command tells it that the highest priority interrupt is
        finished; this is neat because all the interrupt handlers don't
        have to know what level interrupt they are.

            Now comes the obvious question:  How are we going to check for 2
        keys, as in the case of say Alt Q?  BIOS makes this one easy.  In
        the BIOS/DOS data area (segment 40), at bytes 17h and 18h, we find
        information on which special keys are being pressed.  The sig-
        nificant bits are:

           17h xxxxXXXX 18h XXXXxxxx 1 Alt is being pressed 1 Insert
           is being pressed 1 Ctrl 1 Caps Lock 1 Left shift 1 Num
           Lock 1 Right shift 1 Scroll Lock

            All we do is wait for the scancode of Q to come up.  Then we check
        the appropriate bit in the appropriate flag byte (in the case of
        alt, we would test 0040:0017h for 08h).  If the bit is on, we do
        our thing.  Otherwise we just pass control on to the next in-
        terrupt handler in the string with our long JMP.  NOTE:  always
        use a "normal" key as a "wakeup call"; that is, don't check for
        combos like ALT-Rshift.  There are too many programs already that
        do this, and programs employing these keys are difficult to chan-
        ge, thereby ensuring incompatibilities.  In fact, if you dis-
        tribute your program and don't offer some means of "hot key" con-
        figuration, you may want to tell your users where your scan codes
        are located in the program so they may patch them themselves to
        avoid incompatibilities.  Hint:  use a CMP and not a TEST to check
        this byte, or if you are looking for ctrl-A then ctrl-alt-A,
        ctrl-shift-A, etc.  will all mistakenly trigger your interrupt.

                           o How to install the TSR

            The installation program will consist of 3 parts really:  the jump
        around the interrupt handler code to the install code, and the in-
        terrupt and install code areas.  The install code should do basi-
        cally two things:  install the interrupt handler using service 25h
        of interrupt 21h (DOS call), and of course
        terminate and-stay-resident.  To do the install, load AX with 2509h
        (AL has the interrupt number) and DS:DX with the address of the
        interrupt handler code, and do an int 21h.  Your program is RIGHT
        NOW the new interrupt 9 handler.  Then, load AX with 3100h and do
        an int 21h again (Terminate and stay res and return an err code of
        00 to parent).  At this point the handler is working, in memory,
        and control is released back to the parent program (in most cases
        Command.com).

            Here is our opportunity to start getting fancy.  To keep memory
        usage to a minimum, we should do a DOS service 4Ah to release all
        unneeded memory.



        ;page 8
       

           /* UPDATE:  I don't know what I was thinking here, but
           that's wrong.  You don't use service 4Ah in a TSR; it
           would do nothing.  What you DO do is load the number of
           paragraphs you need to keep into the DX register when you do
           your service 31h call.  The way I get that is to use:
           ((last_address-first_address)/16)+1 (to div by 16 just shift
           right 4 bits) And don't forget to allow room for your PSP!  */

            To REALLY cut down on the memory, we can relocate our program
        backwards into the unused PSP area, saving something like 164
        bytes.  Also, we can leave a memory signature so that the user is
        not allowed to install the TSR more than once.  My usual method of
        this is pretty simplistic.  I put 4 unique bytes into the TSR it-
        self, and then upon installation check if those bytes are there.
        If so, the installation aborts and the user is told.  The flaw
        here is that it only prevents the same program being installed
        after itself.  If such a TSR is loaded and takes int 9, another
        one is later loaded and takes int 9 also, the program could then
        be installed for the second time.  I know how my system is con-
        figured, so this is no problem.  To a novice user getting hold of
        one of my programs, this will at best just waste a little memory.
        At worst, the system can get a little weird.  To more securely
        guard against re-installation, you may take another interrupt vec-
        tor (there are 256, after all, and only a couple dozen are used in
        a basic PC).  The way that works is:  search for an empty in-
        terrupt vector (one which has all zeros), and take one when you
        find it.  Save a memory signature there.  When the program in-
        stalls the TSR code, search the interrupt vectors for your memory
        signature.  If you find it, you know your program is there al-
        ready.  Much safer.  (Aside:  For my personal use, I combine all
        my TSR's into one program.  This saves memory, time, and trouble.
        It also keeps me from installing TSR's in between one another!)

                    o What you can get away with in a TSR

            If you have read this far, I assume you don't already know all
        this.  So, I will not go into all the undocumented MS-DOS services
        for TSR writers.  If you are interested in them, I suggest you
        check back issues of magazines like Programmer's Journal and Dr.
        Dobb's.  Anyway, you are restricted as to what can happen inside a
        TSR.  It all boils down to one thing:  MS-DOS is not reentrant.
        It is not meant to be multitasking (under programs like DoubleDos,
        there are copies of DOS for each task running), and so a routine
        can not be called while it is already executing for somebody else.
        Here is a scenario:  You are saving a document from your word
        processor, and during the wait call up a TSR to find a phone num-
        ber or something.  The TSR does a disk read of your phone # file.
            The TSR finishes and exits back to the word processor.  Now, the
        WP's disk write has been interrupted, losing vital information
        like where on the disk he was writing, etc.  MS-DOS goes awry.  It
        is time for the big red switch, and kiss your document adios.
        Hope your disk is not messed up as well.

            There is the why of all this, now here is the what.  A TSR may not
        use any DOS int 21h services higher than 0Ch.  It is restricted to
        console and printer I/O services.  (Now, this is of course not
        TOTALLY true, but how to do disk I/O etc.  are beyond the scope of
        this little rambling.  Maybe some other time.)

        ;page 9
       

           /* UPDATE Okay, here's how to do anything you please from
           within a TSR, including disk I/O.  The BEST way is to install
           interrupt "front-end" handlers for int 13h (BIOS disk I/O),
           int 21h (DOS), int 25h (absolute disk read), int 26h (absolute
           disk write), and I think that's all.  In these front-end hand-
           lers, set a flag (or semaphore or TS byte or whatever you want
           to call it) whenever anyone is in the middle of a disk I/O.
           Then, in your TSR, don't do a disk I/O if any of these flags
           are set.  You will also need to steal the user timer tick in-
           terrupt (1Ch) to periodically check for when those interrupts
           are free for use.  Or, you can use the cheater way (which is
           used by DOS itself):  Whenever DOS is waiting for a keypress,
           it calls int 28h (undocumented).  The only program I know of
           "legally" using this is the PRINT command.  Whenever int 28h
           is called, you should be free to do whatever you want.  If you
           want more immediate access to the disk, though, you'll need to
           use the timer int (1Ch) again.  ONCE, at initialization time,
           do an int 21h ah=34h.  In ES:BX, you will have the address of
           a byte called INDOS by most folks.  This is an undocumented
           function which has been officially declared off-limits by
           Microsoft, but nobody pays attention to them anyway.  As far
           as I know, it works fine in all versions of MS-DOS as of today
           (April 1988).  In your timer interrupt servicer, read the byte
           at the address you got from service 34h.  If it's not zero,
           don't do anything over service 0ch; if it's zero, go crazy.
           What this byte is (I'm told) is a count of how many calls deep
           DOS is into itself.  The actual value is of no relevance to
           us, just if it is zero or not.  Now, I don't see this helping
           much if the program is doing BIOS I/O, but I don't use any
           software I know of which uses BIOS for disk I/O.  Also, if the
           application is doing direct-to-the-hardware disk I/O, I don't
           think you probably want to be messing with this stuff.  Again,
           I don't use anything that I know of doing this.

                I've written several programs using the int 28h/service 34h combo
        to do TSR disk I/O and have never had a single problem, and I
           tested them in the middle of all kinds of disk accesses.  This
        does not mean it's always cool, though.  If you can help it, al-
        ways avoid undocumented stuff.  In my opinion, Microsoft won't
        change it because so much software relies on it now, but I've
        learned not to trust them.

                  o Example program complete with flimsy excuses

                The Sperry PC has a high-res graphics screen which is treated as a
        logically different display from the normal text screen, and uses
        different display memory banks.  The text bank, called screen A,
        can be superimposed over the graphics (called screen B) on the
        screen simultaneously.  This program switches between screen A on-
        ly, screen B only, and screen A superimposed on screen B.  This
        program is for example only, and you should not attempt to run it
        on a CGA.  If something gets fried, it's not my fault.  It looks
        for a keypress of Alt-Esc, goes into action, and then quits.


                I hope this has been helped you understand how a basic keyboard
        driven TSR works.  If you have any more questions, feel free to
        contact me with them, and I will find you an answer.  Most ad-
        vanced TSR functions (almost all are undocumented by Microsoft and

        ;page 10
       

        IBM!) have been discussed in Byte, PC Tech Journal, and Dr.
        Dobb's Journal, but have been thoroughly discussed in Programmer's
        Journal.  I highly recommend this publication, and hope more
        people will subscribe, so it does not fold up and deprive me of
        all the information it provides.


        Call the Telstar BBS:  (512)822-8882 for a good time




        Garrett P.  Nievin  has also contributed a piece of code to service a
        soft breakout switch for Symdeb and Debug. Please see the listing in
        the source code section. Both of these are extremely well commented
        and should be quite useful.










































;page 11



                              Hex Conversion Routines

                Just a little "quicky" to fill out this issue. These are a
        couple of routines that I use regularly in a variety of ways. They are
        both fast and fairly tightly coded and they work. I hope you find them
        of some use.

                The first, DECHEX, takes an ASCII number pointed to by SI and
        returns a hex number in AX. The other just reverses the process, and
        when used with the little MOV_ASCII puts it where you tell it to.

;~
 DECHEX:                         ;THIS ROUTINE WILL TAKE A [CL] (MAX 5) DIGIT
                                ;ASCII DECIMAL NUMBER POINTED TO BY SI AND
                                ;RETURN A 4 DIGIT HEX NUMBER IN AX.*
                XOR     DH,DH
                XOR     AX,AX
TRY:            CMP     CL,1
                JBE     LASTA
                MOV     DL,[SI]
                SUB     DL,"0"
                ADD     AX,DX
                MOV     BX,AX
                SHL     AX,1
                SHL     AX,1
                SHL     AX,1
                ADD     AX,BX
                ADD     AX,BX
                INC     SI
                LOOP    TRY
LASTA:           MOV     DL,[SI]
                SUB     DX,"0"
                ADD     AX,DX
                RET


HEXDEC:         ;THIS ROUTINE WILL TAKE A 4DIGIT HEXADECIMAL NUMBER IN AX AND
                ;RETURNS A 5 DIGIT ASCII IN BH,BL,DH,DL,AL.
                ;TIME AVERAGES ABOUT 140 CLOCKS PER DIGIT
                ;LEADING 0'S ARE SUPRESSED
                MOV     BX,0
                MOV     CX,0
                MOV     DX,0
A10K:           CMP     AX,10000
                JB      A1K
                SUB     AX,10000
                INC     BH
                JMP     A10K
A1K:            CMP     AX,1000
                JB      HUNDREDS
                SUB     AX,1000
                INC     BL
                JMP     A1K
HUNDREDS:       CMP     AX,100
                JB      TENS
                SUB     AX,100
                INC     DH
                JMP     HUNDREDS
;page 12


TENS:           CMP     AX,10
                JB      UNITS
                SUB     AX,10
                INC     DL
                JMP     TENS
UNITS:
                MOV     AH,'0'
                ADD     BH,AH
                ADD     BL,AH
                ADD     DH,AH
                ADD     DL,AH
                ADD     AL,AH
                CMP     BH,AH
                JNZ     UEND
                MOV     BH,020H
U1:
                CMP     BL,AH
                JNZ     UEND
                CMP     BH,020H
                JNZ     UEND
                MOV     BL,020H
                CMP     DH,AH
                JNZ     UEND
                CMP     BL,020
                JNZ     UEND
                MOV     DH,020H
                CMP     DL,AH
                JNZ     UEND
                CMP     DH,020
                JNZ     UEND
                MOV     DL,020H
UEND:
                RET

MOV_ASCII:                              ;THIS TAKES THE DIGITS PRODUCED BY
                                        ;HEXDEC AND PUTS THEM AT DS:SI
                MOV     [SI],BH
                INC     SI
                MOV     [SI],BL
                INC     SI
                MOV     [SI],DH
                INC     SI
                MOV     [SI],DL
                INC     SI
                MOV     [SI],AL
                RET
;~











;page 13


                          Book Reviews

        The Programmers' Reference

                I made a quick review of this last month, but I have since
        gone over it thoroughly and received the extended package from the
        author.  This is NOT an instruction book for beginners.  It is
        just what it names itself- a reference manual.
                The shareware version is 10 chapters (about 600k bytes) of
        solid information and a table of contents. Much of the information
        is very difficult to find elsewhere. The first chapter is a quick
        history of DOS from 1.0 to 4.0. Chapter 2 has the Port addresses
        and the Interrupts up to 0fh.  Chapter 3 has the true Bios
        interrupts 10h to 1fh and it throws in INT 20h for some strange
        reason. This isn't just a listing that you might find in many
        places, but a detailed description with calling conventions and
        special things to watch out for. It includes semi-documented
        functions such as all of the Desqview and Topview int patches that
        go into this area. Each interrupt lists what machines it is
        included in from Tandy to PCjr to PS-2 model 80. I haven't counted
        them, but there must be thousands.
                The DOS interrupts 20h through 4fh are covered in similar
        detail, with many notes and application information.
                Further chapters contain information on file structures,
        EMS memory, and many other topics.
                The registered version gives another disk full of
        miscellaneous data that is rare and useful.
                The $15 price is one of the greatest bargains to be found.
        Available on many BBS's as ####ref.??? such as 1029ref.zip. This
        says that it is the October 29th release, and the extension is up
        to the Sysop.



























;page 14


                        Source Code for Keyboard TSR


; High Res screen A/B toggler for Sperry PC, the best PC around
; Written for MASM 4.0
code    segment para public 'code'
        assume cs:code,ds:code,es:code
        org     0100h           ; .COM format
start   proc    far

; Equates - ports, locations, values
; Using equates makes the program much easier to change later;
; to use a different scancode here, for example, you would just
; change the equate for "esc".
         if1                    ; only assemble equates on pass 1
portB    equ    61h             ; 8259 port B - used to clear scancode
keyport  equ    60h             ; 8259 port A - keyboard scan codes
esc      equ    01h             ; scan code for Escape key
hibiton  equ    80h             ; hi bit on for keybreak scan code & reset
hibitof  equ    7fh             ; hi bit off for keybd reset
DOS_area equ    40h             ; segment of BIOS/DOS data area
shftstat equ    17h             ; keybd shft status flag in DOS area
shift    equ    00000011b       ; value for shftstat meaning either shift is on
eoi      equ    20h             ; end of interrupt flag
comdport equ    20h             ; 8259 command port
         endif

begcode:
        jmp     implant         ; jump around interrupt handler code
begres:         ; area to remain core resident

rescode proc                    ; keystroke causes jump to resident code here

        jmp     oversign        ; jump over memory signature
        db      'abGN'          ; program signature in memory
; I use my initials in uppercase and a 2-byte program ID in lowercase

; Variables

mode    db      0               ; superimpose mode: 0-A,1-B,2-Both,3-None
oldint9 dw      0,0             ; doubleword value of old int9 vector

oversign:       ; start of code for new interrupt 09h handler

        push    ax              ; save that register
        push    ds              ; save DS.
        mov     ax,DOS_area     ; DOS data segment
        mov     ds,ax           ;   now covered by DS
        test    byte ptr ds:[shftstat],shift ; is a shift being held now?
        jz      normal          ; nope, not a hot key, pass it on to old int
        in      al,keyport      ; yes, get keyboard scan code
        cmp     al,esc+hibiton  ; was it release of escape?
        je      abnorm          ; yes, lose that scan code
        cmp     al,esc          ; was it an escape?
        jne     normal          ; nope, skip the important stuff
;
        mov     al,mode         ; get mode
        cmp     al,2h           ; both screens on?

;page 15


        je      aonly           ; yes, go back to first
        add     al,1h           ; add 1 to hi nybble to go  B to A to AB
        jmp     nextmode        ; and go put it back
aonly:                  ; start back with screen A only
        xor     al,al           ; turn off
nextmode:               ; put in new mode and quit
        mov     mode,al         ; move in new mode
        mov     ah,15h          ; set superimpose mode function of int 10h
        int     10h             ; and go change mode
        jmp     abnorm          ; lose scan code
;

abnorm:         ; abnormal handling of scan code.  to the bit bucket with it.
        in      al,portB        ; get portB
        or      al,hibiton      ; set acknowledge / clear keyboard bit
        out     portB,al        ; and out it again
        and     al,hibitof      ; clear ack bit
        out     portB,al        ; out that, enabling keyboard again
        cli                     ; no interruptions please, Mrs. a-Whiggins
        mov     al,eoi          ; end-of-interrupt command
        out     comdport,al     ; send it to the 8259
        pop     ds              ; restore
        pop     ax              ;   registers
        sti                     ; interruptable again
        iret                    ; quit without performing normal interrupt

normal:         ; not hot key, pass scan code on to normal (maybe) int9
        pop     ds              ; restore all
        pop     ax              ;   registers I messed with
        jmp     dword ptr cs:oldint9    ; goto old int9 handler


; all code from here out is based on Norton's guide, and I use it in
; all my TSR's.

reslen  equ     endres - begres         ; length of new resident code
strtres equ     begres - begcode + 100h ; start of resident code
psplen  equ     5ch                     ; length of necessary PSP

implant:        ; code to put new int 9 front end in core
        mov     ax,3509h        ; get int vector function
        int     21h             ; get vector of interrupt 9 handler
        cmp     es:[bx+3],'ba'  ; am I already loaded?
        jne     fresh           ; nope, go install
        cmp     es:[bx+5],'NG'  ; make sure I'm not already in
        jne     fresh           ; naaah, go install
        lea     dx,cs:stalemsg  ; DX points to already installed message
        mov     ah,09h          ; DOS display string func     
        int     21h             ; go display message
        int     20h             ; and quit
       
fresh:
        lea     dx,cs:instlmsg  ; DX points to installation message
        mov     ah,09h          ; display string function
        int     21h             ; give the user the poop
        mov     ax,3509h        ; get int vector function
        int     21h             ; get vector of old interrupt 9 handler
        mov     oldint9,bx      ; int location in ES:BX, save it
;page 16


        mov     oldint9+2,es    ; "
        mov     ax,2509h        ; set new interrupt 9 vector to me
        mov     dx,offset rescode       ; address of which is in DX
        int     21h             ; go do it
        push    cs              ; DS and ES both end
        pop     es              ; up pointing at
        push    cs              ; code area
        pop     ds              ; "
        mov     di,psplen       ; where program will end up
        mov     si,strtres      ; start of resident code
        mov     cx,reslen       ; amount of resident code to move
        cld                     ; go forward in move
        rep movsb               ; move code back in mem
        mov     dx,psplen + reslen      ; DX pointing to next free paragraph
        mov     ax,3100h        ; keep, return code of 0
        int     21h             ; terminate

stalemsg db     'Screen A/B toggle is already installed and active!',13,10,7,7
instlmsg db      'High Res Screen A/B toggle',13,10
        db      'Shift/Escape toggles screen A only, then B only, then A/B.'
        db      13,10,'$'
               
start   endp
code    ends
        end     start































;page 17


                             Source for Soft Breakout


; BUGOUT.COM
; Program to add wimpy "soft" breakout key to DEBUG and SYMDEB
;
; MASM compatible source code
;
; Hitting the '5' on keypad forces an int 3 (debug breakpoint)
; After breakpoint, add 1 to IP register and trace through IRET
;
; By Garrett P. Nievin
;
; (BTW, to add a hardware breakout switch just put a switch between
; pins 17 (NMI) and 40 (+5V) on your 8088 chip, and a switch between
; pins 21 (RESET) and 40 will do a system reset/reboot.)


code    segment para public 'code'
        assume cs:code,ds:nothing,es:nothing
        org     0100h

hotkey  equ     4ch         ; scan code for hot key = "5" on keypad
portA   equ     60h         ; 8255A port A, usually keybd scan code
portB   equ     61h         ; 8255A port B, various switches
release equ     80h         ; hi bit in scan code means key release
hibiton equ     80h         ; hi bit in byte for or'ing in
hbitoff equ     7fh         ; hi bit in byte for and'ing out

start   proc    far
begcode:
    jmp  implant            ; jump around interrupt handler code
begres:                     ; area to remain core resident
rescode  proc               ; keystroke causes jump to here
    jmp  over               ; jump over memory signature
    db  'bcGN'              ; program signature in memory
over:                       ;
    sti                     ; allow interrupts
    push ax                 ; save that register
    in   al,portA           ; get keyboard scan code
    cmp  al,hotkey          ; hotkey?
    jne  normal             ; yes, go hanlit
    push dx                 ; save register
    mov  dx,0020h           ; port 20h = PIC port to send EOI to
    mov  al,dl              ; 20h turns on EOI bit
    out  dx,al              ; tell interrupt controller we be done
    pop  dx                 ; restore register
    in   al,portB           ; get portB
    or   al,hibiton         ; set acknowledge / clear keyboard bit
    out  portB,al           ; and out it again
    and  al,hbitoff         ; clear ack bit
    out  portB,al           ; out that, enabling keyboard again
    pop  ax                 ; restore original register
    int  3                  ;
    iret                    ;

;page 18


normal:                     ;
    pop  ax                 ; restore that register
    jmp  dword ptr cs:oldint9    ; goto old int9 handler
oldint9  dw  0,0            ; doubleword value of old int9 vector
rescode  endp

endres:                     ; end of core res area

reslen  equ endres - begres           ; length of new resident code
strtres equ begres - begcode + 100h   ; start of resident code
psplen  equ 5ch                       ; length of necessary PSP

implant:                    ; code to put new int 9 front end in core
    mov  ax,3509h           ; get int vector function
    int  21h                ; get vector of interrupt 9 handler
    cmp  es:[bx+3],'cb'     ; already loaded?
    jne  fresh              ; nope, go install
    cmp  es:[bx+5],'NG'     ; make sure
    jne  fresh              ; naaah, go install
    lea  dx,cs:stalemsg     ; DX points to already installed message
    mov  ah,09h             ; DOS display string func
    int  21h                ; go display message
    mov  ax,4cffh           ; terminate with code = 0xff
    int  21h                ;
       
fresh:
    lea  dx,cs:instlmsg     ; DX points to installation message
    mov  ah,09h             ; display string function
    int  21h                ; give the user the poop
    mov  ax,3509h           ; get int vector function
    int  21h                ; get vector of old interrupt 9 handler
    mov  oldint9,bx         ; int location in ES:BX, save it
    mov  oldint9+2,es       ; "
    mov  ax,2509h           ; set new interrupt 9 vector to me
    mov  dx,offset rescode  ; address of which is in DX
    int  21h                ; go do it
    push cs                 ; DS and ES both end
    pop  es                 ; up pointing at
    push cs                 ; code area
    pop  ds                 ; "
    mov  di,psplen          ; where program will end up
    mov  si,strtres         ; start of resident code
    mov  cx,reslen          ; amount of resident code to move
    cld                     ; go forward in move
    rep  movsb              ; move code back in mem
    mov  dx,psplen + reslen ; DX pointing to next free paragraph
    mov  ax,3100h           ; keep, return code of 0
    int  21h                ; terminate
stalemsg db 'Bugout already resident.',10,13,7,'$'
instlmsg db 'Bugout loaded and active, keypad-5 is break key.',10,13,'$'
start    endp
code     ends
    end  start








;page 19

Comments

Popular posts from this blog

BOTTOM LIVE script

Evidence supporting quantum information processing in animals

ARMIES OF CHAOS