VALARROW ASSEMBLER HIGHLIGHTS

In this highlights section I will combine a few things. First of all I have to finish the description of basic valarrow specifications with the macro language in valarrow. While doing that we will be more and more stressing reusability and maintainability. Logically that ends up with using a asm librarie. Implementing the stdlibrarie in valarrow is also a crash course in creative use of macros, since the normally distrubuted include files will generate a memory error in valarrow( and other assemblers). But don't be afraid, thats fixed up without losing anything at all by just reordering macros in the standard libraries include files. Lastly I said I will give a few examples of the use of DOS/BIOS interrupts. The interrupt examples section will handle the execute function, the bound(.286) instruction and a file lister. In the process it will handle how you can implement some .286/. 386 features in valarrow, LFN use, and even basically hooking an interrupts.

VALARROW MACRO EXAMPLES

Macros are one of the most unused possibilities of valarrow.
It turnes out that valarrow supports most of masm 5 's macro features.
To list what I found out would be a start I guess:

SUPPORTED		NOT SUPPORTED MASM 6.1
===========================================================
if/else/endif		vararg,req,initializing arguments
exitm			stringdirectives(sizestr,substr,etc)
ifb/ifnb		local( generates erroronues labels!)
ifdef/ifndef		for, while, repeat etc.
errb/errnb
&,%
rept(repeat)
ipc( for)
irpc(forc)

Well probably its time to show a little bit what might be useful.

How about the following macro which I call exit ?

exit macro	errorcode
	ifnb	
		mov al, errorcode
	endif
	mov	ah, 04ch
	int	21h
endm

How about that ? The nicest thing about this is that you can call this 
macro with or without an argument! If you call this macro 
without an argument then the errorcode from AL will automatically 
be transferred to DOS.

So this is giving the following possibilities for use in programs:

1)   exit     	; exit to dos with current error
2)   exit 0	; exit to dos without error(in case of no errorcode in al)
3)   exit 1	; exit to dos with error set to 1

A second example of a macro which doesn't even use any advanced macro
feature might in fact be even more useful. I noticed that in my asm 
programs I was typing over and over again the following codes for all my 
exe-targetted programs:

startup	macro	

dgroup group Data_seg, Const_seg, Stack_seg

Code_seg segment word public 'code'
assume CS:Code_seg,DS:dgroup,ES:dgroup,SS:stack_seg
	mov	ax,	dgroup
	mov	ds,	ax
	mov	es,	ax
Code_seg ends

Data_seg segment word public 'data'
Data_seg ends
Const_seg segment word public 'const'
Const_seg ends
Stack_seg segment para stack 'stack'
	stackjes	db	256 dup(?)
Stack_seg ends
	
endm


What this macro is doing is a lot in fact:

- Since segments in your source code are defined according to their first 
  appearance this macro is assuring that you have dosseg ordered segments 
  with always the code_seg then dgroup, with the stack_seg as the last 
  segment.

- Since both the aligning and the identifier are noticed by valarrow in
  the first full definitions you can leave them out in later segment 
  definitions( but NOT the public keyword!)

- The group with the name dgroup is formed precisaly according to current
  microshit rules,  and a (far) stack is formatted. Usually this stacksize
  will suffice and that is why I did leave the param stacksize out of this
  macro. However if you have a lot of calls in your program you should
  adjust the stacksize.

- The last feature I always use is to point both ds and es to my 
  data_segment, so I included that one into this startupcode.

This will greatly simplify programming since you can just use :

startup 

In the later program which tests some error_handling we will see how that
brings back our code to readable and short program. At this point however
I want to shortly tell you what this macro is not doing and why:

- In a lot of my programs I deallocate the memory given by the dos_loader
  to the precise amount that I need. That size being offset stack_seg-/-
  offset PSPseg+size of the stack. Since sometimes this seems to much 
  overhead for a simple program however I do not use it always. It is 
  however very well possible to put this kind of reallocation in another 
  startup macro, for instance with an argument deallocate. With the 
  demonstrated IFB functionality you could simply add the deallocating
  code to the startup.

- Although the stack_segment is in dgroup I do not put the code in the 
  startup macro to make a near stack. Same arguments and solutions as
  above. 

In short it seemed to me nice to have some clean, easy and nearly always
usable startup code handy. For (debugging (small parts of )) programs the
question for a more encompassing macro is not that strong. Before going
into one further step in making debugging code easier, I will shortly 
touch upon some other use of macros. 

Macros have the nice feature of allowing for arguments, while simple calls don't. Thats why the use of indirect calling of procedures via macros was so attractive. That is how microsoft designed the invoke operation in masm 6.1. (But the invoke operation is not something deserving a macro because its way of passing arguments is far from optimized.). And also it is the reason why the standard library makes such a big use of macros instead of direct calls.
Take for instance the write file or device macro which started the macro discussion. Lets further suppose that our program does have to call the code in the macro a lot of times at different places in our code. In that case we are going to develop the write_string macro: write_string macro where,what,lengte mov cx, lengte mov bx, where lea dx, what call write_file_device endm

And we are going to add to that the code for the write_file_device procedure: write_file_device procedure push ax push bx push cx push dx mov ah, 40h int 21h pop dx pop cx pop bx pop ax ret write_file_device endp

This is the way that we can have our cake and eat it too. We have the maximum readibility and also the maximum reusability( keeping the code size tight). When we want to write to file or device in our code we can simply put a message in like:

write_string 1, hallo, 5

At that moment we have two advantages in one hand. We have a simple way of invoking the produre through a macro, without having lost the advantages of a reusable procedure that is. The direct consequence of this kind of mixed procedure and macro use is that we need two files. One is containing the important macros( the inc file), and another one is containing the important procedures( the procs file) which have to be linked in. At the end of this page you will have a link to both files, which contain a few useful macros and procedures among which the ones mentioned on this page.

PUTTING SOME TOGETHER

I will round this macro things off with the promised error_handling. I don't know how it is with you, but I think that one of the things that put me back in QBASIC mode time and again( blowing me away from real asm programming), is that it is do darned difficult to debug programs in asm. I think that debugging in asm is maybe another big arrea of specialized knowledge. I am thinking of debugging TSRs, debugging windows programs, pmode etc. Closely related might be unassembling BIOS code, windows code and understanding all kinds of specialized file formats like COFF/PE, LIB,LIB( yes windows redefines that too..), DLL etc..etc.. However difficult that all might be, I found myself a lot of times even stuck on much more elementair things. For simple test programs I could sometimes not see the tree between the woods of startup and exit code, particularly when I wanted a message about occurred errors. So that is why I concentrated on developing the above mentioned startup and exitcode. But on top of that I needed a generalized error message, without the need of defining the data for that in my test programs. With the help ot stdlib sources and the exit macro I managed to put together the procedure printerr_dbg which does that all, without expecting any parameters or data. Of course I designed a full fledged error_handling proc at the same time for release purposes, but printerr_dbg will most of the times satisfie the needs of the developer I think. To test the program I could use quite a few macro things from above, so that the whole program was accounted for in this lines: ;simple program just to test if the debug procedure ;error_handling works allright include macro.inc extrn errorhandling_dbg: near startup code_seg segment ;code statements( this ones likely to give an error) mov bx, 0ffffh mov ah, 48h int 21h jc errors ;here is the rest of your code ; ..... code statements errors: call error_handling exit code_seg ends end I hope that you agree that this kind of shortness and readability will help you as it does me. Of course you have to link this program once assembled with the file that contains printerr_dbg, and also have to include macro.inc. That is why I include both files here as promised: include file with macros, and file with debug procedures, and last but not least a few programs which test the errorhandling

Soon, very soon we will see that all this errorhandling is kind of useless because we will make use of the much more powerful features of a librarie, but it deserved attention both as a step on the road and as some sort of example rounding of the macro discussions.

VALARROW and USING STDLIB

With the consideration of macros we have made one step into making maintainable and readable assembly language programs with valarrow, but we are going to make another giant step to that with the consideration of libraries. Since I consider the stdlibrarie a good, wellknown, c compatible, documented, en even very well explained librarie, the stdlibrarie was my choice for a librarie. Looking through all the possibilities in the functions I set out for some real programming. So imagine my disappointment when It turned out that the standard libraries macros turned out to be to big for expansion with valarrow.. (a trouble which valarrow seems to share with a few other older assemblers). Not only that but valarrow barks at the redefinition of the stdgrp in every include file too. Looking into the macro files stdlib.a, stdin.a etc soon learned however that we could greatly reduce the overhead with two simple 'header' macros:

  • slcall addrs
  • slmacro routine
Those header files are called for about 50% of all stdlib routines, making there actual macros a lot lighter. I transferred those macros to a superseding stdlib.inc file. Of course I had to update all .a include files to use those macros. The result is in the linked package of .ar include files. Because we want to be sure to include the stdgrp definition only once I also transferred this definition to the stdlib.inc file. Since the stdlibrarie requires the use of some standard setup, which is defined in shell.asm, I thought it would be a nice idea to reduce overhead still further by including the essential features of shell.asm ( for valarrow that is)into this stdlib.inc file too. The netto result is that you have one major include file stdlibVA.inc which handles the inclusion of all macros, the setup of segregs, the memory initialization, the assume statements, the stdgrp setup, in a valarrow approved way.

Since it is very clear that sometimes you do not want to go the long way of including all stdlibrarie include files, and doing segreg setup and memory initialization, I also prepared the same file without that features in stdlibV2.inc

The result of this rather simple efforts using nested macros, is that a stdlibrarie calling routine can be like this:
include stdlibVA.inc cseg segment ;code example mov bx, 0ffffh mov ah, 48h int 21h jc errors ;more code errors: print db 'There was a DOS error ',0 putw exitPgm cseg ends dseg segment .....; data dseg ends Even the follow up of the segments does not matter any more, since both there parameters and follow are already defined... In the next section I will give a few examples of coding with the use of the stdlibrarie in valarrow. But before that I should shortly note that there is still another way then the above for using the standard librarie. When you are going to look in the sources and the include files you will notice that all procs are defined as far procedures. That is most usefull for other then tiny( 64 KB model) programs, but since valarrow is limited to tiny you might as well put the routines as near in your code segment. Just copy the routines you use into your programs( do not forget to define procedures as near), or grab together a large stdlibNR.asm file with all the routines, but thistime inside your cseg.

USING DOS/BIOS INTERRUPTS( EXAMPLES)

One of the most difficult functions of DOS is the exec function( 4bh).
Therefore I thought it would be nice to start the examples with some
attention for this function. 
The purpose of this function is that you can design a program which calls
another- so called child-, program. This might sound simple enough, but it
turns out that in this process a lot of actions have to be taken.

1. Since exe programs allocate all available memory if possible by default
   ( indeed like .com programs), that would not leave any memory left for
   the child program. So we have to do free some memory from our parent
   program first.
2. The exec function accepts two inputs:
   a) One block pointed to by ds[dx] which specifies the programname
   b) One block pointed to by es[bx] which specifies the parameterblock  
3. The exec function has two sub functions:
   a) function 4b00 is the normal execute
   b) function 4b01 is the load but don't execute
   c) function 4b02 is the load only 

Even with this we have far from reached the ultimate control over executing 
a child program. The actions the OS( DOS/Windoze) takes when it executes
our child program are still covered. And when we make asm programs we 
want full control won't we ?  That would however require loader programs
which simulates the OS actions. Although thats quite specialized stuff it
turns out, as often in asm programs, we can heavily built on available 
sources from other people to finish that job.

However let us first start with the most simple exec program we can design.
The program execR.asm does not asks for any input, but instead execute 
a hard coded program, with hardcode parameters. Not very execiting, but 
good exercise. 

A few comments:
1) In later version of masm or tasm you can define pointers by some 
   ptr keyword, and far pointers by a  far ptr keyword.
   In valarrow you can do exactly the same. When you look at the  
   parameter block in es[bx] (which I gave the name params), then
   you will see that the paramblock is like:

0	dw	segment of environment( or 0 for parent environment use)
2	dd	far pointer to commandline
6	dd	far pointer to fcb1
a	dd	far pointer to fcb2 

In valarrow( like in masm/tasm) the size of the pointer determins the 
distance of the pointer. You should note too that unlike high level 
languages, when you use declarations using the names of other variables, 
those variables are considered pointers( not values). When you come to 
think of it, that can't be otherwise since the value of the variable is 
unknown at assemble time! 
So this all comes down to the fact that the statement
	dd	commandtail
is the same as 
	farptr	commandtail
And the same holds for the FCB dummy's which are pointed to in the param
block.

2) The commandline has the format:

     len,commandline,cr

For determining the lenght of a string assemblers have the 'ici' macro '$'. So that 
is why the statement:
commandtail	db	dummy-'$'-2,/d /p,cr
dummy		etc...

can be resolved to:
commandtail	db	offset(dummy)-offset(commandtail)-2, etc...

which in turn will be resolved by the assembler to:
commandtail	db	5,/d /p, cr

3) Before calling the execute function of DOS we have to free memory.

Although not necessary a DOS executable allocates all available memory
as a rule. Since we need memory for our child program we have to
reallocate the memory devoted to our program to the minimum. 

On entrance of a DOS executable es points to the PSP which is exactly
one paragraph( 16 bytes) before the entrance point. Since we are always
defining stack_seg as our last program that would make the required
lenght in bytes equal to:

	stack_seg+stack_size-es

Since the reallocate memory function accepts only paragraphs we have to
divide that the above number of bytes by 16. Although maybe not always
necessary it is good habit to do this kind of realocation for every exe.
That is why the exe_modifymem macro is included in the macro.inc file.
If you are using a com file then memory reallocation often involves either
a dummy end_segment which you can use to refer to the end of the program
with a user defined stack inside the code segment, or the reallocation
involves the setting up of a near stack too( setting ss=cs and sp=cseg
relative in both cases ).

example 2: commandline arguments

Until now we had a fixed commandline, but of course our program would be more fun if we could use commandline and input, wouldn't it ? The commandline information is something you are using a lot of times inside whatever program. The default commandline is stored inside the PSP at offset 81h, where at offset 80h the length of the commandline without the CR byte is counted: PSP:80h db len(commandline) ; count of characters EXCLUDING CR. PSP:81h db 126 dup(?) ; commandline INCLUDING the trailing CR Returning to our program which spawns a child process, we need at least one argument which represents the name of the child process. It is however possible that the user runs our execute program without an argument. In that case we have two choices. One being to abort the program while presenting the required syntax to the user. The other one being to present the user with a question for the required input. This last option is chosen, and requires a flexible routine for getting the exec arguments. You are referred to the procedure get_childnr_and_stdcmdnline in execargs.asm. The procedure first tries to get the needed arguments from the PSP, but when it doesn't find the arguments there it calls get_exec_args to get the arguments from userinput. The commandline when found in the PSP is cut in two pieces, the first being the childname, and the second part representing the arguments passed to the childprocess. There are 6 delimiters that DOS normally recognizes, and the same delimiters are scanned for in this program: space, tab , semicolon, equalsign, colon, cr Notice that the routines scanning for arguments are copied from the stdlibrarie but,1) Used as near procedures 2) Adjusted for specific userinput on an empty commandline Well thats about whats new about this second example of the exec function. As you can see the program is now almost like a real shell program which handles programnames and arguments.

example 3: Getting lower and lower

While you might think that we are already at a pretty low level with our shell program, we still leave the loading of the program up to DOS. Nowwhere in the previous examples did we gained any insight in what DOS does when it loads a program. I am quite happy to tell you that we still know what DOS does because of a lot of work from a lot of programmers. They discovered piece by piece the inner workings of DOS ( as we are at this moment discovering windows internals..), and it turns out the the DOS loader takes the following actions: DOS *.COM LOADER: 1) Allocates an environment for our child process. 2) Allocates all memory thats left to the child *.com program 3) Set up a valid PSP for our *.com program to spawn 4) Reset the MCB pointers of both the environment and the PSP of the loader program to point to the childs PSP. 5) Load the program starting at offset 100h from our PSP seg 6) Free our loader program environment 7) Free our loader program PSP 8) Inform DOS about the new active PSP(the child's) 9) Set up the child's stack and jump to 100h in child(start code). While this might seem difficult in fact all steps are logically chained. And we will be so lucky to have a great example program by DOSloader by David Lindayer. This is maybe the time to tell you a thing you might already have discovered. Most things in asm programming have already been done, or at least the biggest part of what you want is already done. We are all learning from each other. For instance the DOS loader did not have commandline support, a feature which I added myself, but ofcourse the biggest accomplishment was the DOS loader itself, a program that the author could not have made without information and programs from still other people....... The DOS loader program makes use of a bundle of knowledge from which I will make only a few comments: - *.com programs always allocate all available memory, although they can be not bigger then 64 KB( at least without relocations). - When you allocate memory with DOS function 48h then DOS allocates the number of paragraphs +1. This extra para is called the MCB(Memory control block) which is linked in a chain( so that all MCB's are pointing to each other) and stores some information about the size of the memory block and the owner of the memory block - When you allocate memory for a program then the program should start directly after the PSP, which in turn starts directly after the MCB. Thats kind of making it impossible to allocate memory for only the PSP( since then DOS searches for 1 free para only). - Freeing the memory from a program will only work if you update the information in the MCB's too.( thats what David calls the arena_switch) There is a lot more to say about the program, but most of it you should be able to find out yourself with the use of some very good online sources. The two most used sources for information about interrupts are: HelpPc(short reference) InterruptList(extensive) As a closing word I think it is fair to say that a exe loader is a little bit more difficult then the com loader, but on the other hand that difference is only gradual.

example 4: Getting fileinfo from a directorie

In the above examples we discovered only two levels beneath the surface so to speak, but in this example we will notice no less then four levels , from which this example will access three (the direct hardware solution is left unnoticed here). The topic is another routine that is widely used. Its a routine to get the filenames( and other fileinformation) from a directorie to the screen or to a file. Before getting into the actual coding lets for a moment attent to disks. Both directories and files are things that DOS or any other OS makes to handle diskstorage. It is important to understand that at the lowest level(BIOS) there are no files or directories, there are only bytes on a disk. The BIOS views a disk as cylinders, heads, and (fysical) sectors. Bios disk handling is done through int 13h. Examples of int 13h disk handling: int13a.asm displays info about your partition int13b.asm TSR displaying message of int 13 usage. DOS view on a disk is called the "logical" point of view. If we are speaking about sectors on a disk from the DOS point of view then we are always referring to logical sectors. The first sector of a DOS partition is called sector 0 and the sectors are viewed by DOS as just a chain. DOS has nothing to do with the actual cylinder, head and fysical sector where you can find the logical sector. That last information is the information that BIOS handles for DOS. DOS makes use of a system that is called FAT(File allocation table) which can be summarized : 1)Sector 0 of a partition is the bootsector 2)Sector 1 of a partition is the start of the FAT table. Among other things the bootsector has information about the number of sectors the FAT takes, and about the sector length. 3)At the first sector after the FAT the ROOT dir starts. In the bootsector is info about the number of entrances in the ROOT(32 bytes per entrance) 4)After the ROOTdirectorie starts the DATA sectors which are all the subdirectories and file data. The most crucial element here is "ENTRANCE". When you are viewing a directorie/subdirectorie then you will see that that directorie is divided in 32 byte parts called entrances. Those entrances have a fixed structure : filename db 8 dup(?) ;asciZ ext db 3 dup(?) attribute db ? startcluster dw The most crucial element is the startcluster. At that point the filedata/subdirectorie data starts. A clusternumber can be translated to a sector number with information in the boot sector, but for know its enough to know that a cluster in general consist of several sectors. It is however possible that not all the data are fitting into one cluster. Thats were the FAT table comes in. In the FAT every cluster has one entrance. In a FAT12 table this entrance is 12 byte, and in a FAT16 table this entrance is 16 bits. The FAT entrance can point either to the next cluster in the chain( which doesn't have to be the next cluster!) or it signals that its the last in the chain. While oversimplified, this is basically what a FAT system is all about. When you are using the function int 25h(read sector) and int 26h (write sector), you should be concerned with the above DOS interface. An example program mediaid.zip which resets the floppy disk's media id, makes use of this "low" DOS interface. But as you might have been suspecting there is still another level of DOS interfacing with the DISK. That is the level of all file functions. While they are making use of the low DOS interface(mostly) and certainly of the BIOS int 13h interface( you can control that with the TSR given), they do so from another interface. If you want to know if a file can be found inside a directorie. there are two( for LFN three) functions which you should care about: Findfirst( 04Eh), resp. (714Eh) Findnext( 04Fh), resp. (714Fh) Findclose , (710Ah) The interface is really easy: you start up a search with findfirst, and if you want more files with the same specification you should call findnext until done. You can search for wildcards like "*.*" It should not be very difficult to find numerous sources for this simple file search. Instead I made a few examples which concern themselves with recursive filesearches. Thats a little bit more difficult as you might suspect. The basic idea is that you call the directorie scanner which works like above for every subdirectorie, while saving enough information to return to the former search topic when the subdir(s) are done. When you have understood the information above( especially the entrance stuff) then you should not wonder to much about what info you have to save: 1) the entrancenr 2) the cluster read 3) some stringpointer inside the searchstring Implementing that we will also be using stdlib code( although not already the librarie itself). For the sake of examplyfing I choose another frequently used sort of code to show commandline support. That is the files listing program. A file listing from a directorie can be obtained from the operating system using the findfirst/findnext algorithm. The OS searches first for the startcluster of the directorie and then lists all entrances with the findnext function. If the cluster is done, the OS searches for the next fatentry of this directorie. If one is found the listing continues from that cluster. If not then that directorie is done. You can search in another directorie after that. When long filenames are supported then the algorithm is slightly different because a searchhandle is opened on executing a findfirst, which searchhandle is used for the next files to find. If the directorie is fully listed then you have to close the searchhandle with a function called findclose, before you can call findfirst on another directorie. The information about the file that is on disk gets stored in a disk transfer arrea( DTA). That is a fixed structure( outlined in the program) which differs slightly for LFN supporting. The OS uses a default DTA which is shared with the commandline in the PSP( at es:81h on entrance). Using this default dta for actual disk transfers is in general not so good an idea since you overwrite the commandline then. That is why the redir.asm program starts with setting up a DTA. For getting all files on a path( that is with recursing all subdirectories) you have to use a recursive algorithm, that is to say you call the directorie listing routine from the directorie listing routine, while saving essential information to use on return from the subdir listing. That is why you see the pushes and pops around the recursing calls. Notice that you have to store the end of the search$ too! Also it is important that you notice that every recursement uses 2+pushes*2 stackbytes. So you might want to adjust you stack if you got really deep nested directories( f.i for 12 deep nesting in a dos tree you already need 8*12=96 bytes of stackspace, that is without all the other calls). As example programs two code fragments that list all files on your current disk. redir2.asm list it in lfn format, and redir2do.asm lists all files in short aliased format.

example 5: Getting the bounds of an array with INT 5

The last topic in this introduction to interrupts calling with valarrow we will (again) turn to the hooking of an interrupt. All interrupts are vectorized in the first KB of lowmemory( from 0:0 to 0:256*4). When an interrupt is triggered then the CPU fetches the adress of the handler to jump to from this table. If we change the tables vector to point to our own routine we have a way to "intercept" or "hook" an interrupt. There are ISR( Interrupt Service Routines) and TSR( Terminate stay Resident Routines), where the main difference is that a TSR stays patched in the interrupt vector pointing to your routine which also stays in memory when the initiating program ends. An ISR only temporary hooks the vector and restores it before exiting.. As an example of making an ISR I present a program used as example program in "The art of Assembly language"( chapter 17), which is interesting for more reasons. It hooks the bounds violation exception ( INT 5). This exception normally returns to the instruction that provoked the violation, thus getting into an infinite loop when youre handler did not changed a value..What the handlers developed does is really simple: they change the bounds to the values encountered( If Moses is not coming to the Mountain....;). This way the infitive loop is broken because the bounds are adjusted! Its easy to see that when we walk through a large array with this method that at the end of the proces we have received the global maximum and global minimum in a relative cheap way( since bound violations will not happen so often..) . The bounds violation is invoked from a bound instruction. This is a .286 instruction which conditionally calls the bound violation INT 5 if the value is outside the bounds, otherwise it is effectivaly a nop. Look for the explanations in bound.asm. Two things you should note: - Although this is not a standard ISR its rather interesting. All the more so because INTEL redesigned things so that INT 5 points to the printscreen interrupt. If you are willing to make a full fledged bounds handler from the code then you should determine if the handler is invoked from a bound intruction or from an INT 5. You can read more about this and about a lot more in the "Art of Assembly Language" (linked at the asmlinks pages) - Secondly the bound instruction is an .286 instruction and Valarrow does not support such. What I did instead was just putting in the opcode for the bound instruction (with db 62h,06h) like I did in the loader simulator. Just remember that in a lot of cases assembly language programs require only a few instructions that have to be simulated like this to make a .286 or .386 or .486 real mode program with Valarrow. At this point however seems to be a nice point to finish this valarrow specifications and examples pages. Not only because I think I am running out of say the valarrow bounds( ;) ) but also because protected mode programming and windows programming in assembly, which are my main interests at the moment, are already that difficult and MS-ed that even with the use of MS product MASM I have my hands full. I simply am not good enough to make the "extra" translation to valarrow sources in a reasonable time too. I am sorry. But I hoped you enjoyed so far... Rick 1