Copy Link
Add to Bookmark
Report

The Assembly Language Magazine 3

VOL 1 NUMBER 3
May, 1989

Written by and for assembly language programmers.

Table of Contents

  • Editorial
  • GUIDE LINES FOR CONTRIBUTORS
  • Beginners'Corner: Segmentation
  • Keyboard driven TSR programs
  • Hex Conversion Routines
  • Book Reviews
  • Source Code for Keyboard TSR
  • Source for Soft Breakout

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 offset 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 number 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.

GUIDE LINES FOR CONTRIBUTORS AND 'ADVERTISERS'

Name and address must be included with all articles and files. Executable file size and percent of assembly code (when available) should be included when a program is mentioned and is required from an author or publisher. Any article of interest to Assembly language programmers will be considered for inclusion. Quality of writing will not be a factor, but I reserve the right to try and correct spelling errors and minor mistakes in grammar, and to remove sections.

Non-exclusive copyright must be given. No monetary compensation will be made.

Outlines of projects that might be undertaken jointly are welcome. For example: One person who is capable with hardware needs support from a user friendly programmer and a math whiz.

Advertisements as such are not acceptable. Authors and publishers wishing to contribute reviews of their own products will be considered and included as space and time permit. These must include executable file size, percent of assembly code and time comparisons.

Your editor would like information on math libraries, and reviews of such.

Articles must be submitted in pclone readable format or sent E-mail.


Money: Your editor has none. Therefore no compensation can be made for articles included. Subscription fees obviously don't exist. Publication costs I expect to be nil (NUL). Small contributions will be accepted to support the BBS where back issues are available as well as files and programs mentioned in articles(if PD or Shareware ONLY).

Shareware-- Many of the programs mentioned in the "Magazine" are Shareware. Most of the readers are prospective authors of programs that can be successfully marketed as Shareware. If you make significant use of these programs the author is entitled to his registration fee or donation. Please help Shareware to continue to be a viable marketing method for all of us by urging everyone to register and by helping to distribute quality programs.

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 associated with it but that can sometimes be overridden in the instruction. 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 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.

A fool rambles about Keyboard driven TSR programs

by Garrett P. Nievin 4518 Valley Brook Dr. San Antonio, TX 78238


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.


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 relinquish 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 friendly 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.


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 nonetheless.

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 significant 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 interrupt 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 change, thereby ensuring incompatibilities. In fact, if you dis- tribute your program and don't offer some means of "hot key" configuration, 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.


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 interrupt and install code areas. The install code should do basically 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.


/* 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 vector (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 interrupt vector (one which has all zeros), and take one when you find it. Save a memory signature there. When the program installs 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!)


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 number 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.)


/* 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 handlers, 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 interrupt (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.


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 advanced TSR functions (almost all are undocumented by Microsoft and 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.

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
;~

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.

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

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

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT