LIBRARY DEVELOPMENT The following is an extended discussion of topics discussed in chapter 5 of the User Guide. This is for users with experience in machine code wanting to take advantage of the powerful Blitz 2 library system. All the constants and macros used are defined in the libmaps file found in the blitzlibs: volume. A lot of this reference material is complex, we will endeavour to publish examples of most pf this material in the next issue of BlitzUser. We are confident that the way we have engineered the Blitz 2 library system will mean Blitz will continue to grow in leaps and bounds. THE LIBRARY HEADER #mylib=50 ilibheader {#mylib,init,1 ,finit,0} !dumtoke{"MyModuleName"," M ,_toke} I * !astatement !args {#word,#string} !libs (#medlib,$1380,#doslib,#la6} !subs {_loadmyobject+ 1,0,0} !name{ , toadMyObjectYMyObject#,FileName$''} ; more statements and functions go here load:lnullsub{0,0,0} save:!nullsub{0,0,0} use:!nullsub{0,0,0} free:!nullsub{freemyobject,0,0} init: !nullsub{initmylib,0,0} finit:!nullsub{_closemylib,0,0} !libfin{_toke,_load,_save,_use,_free,8,5} INIT/FINIT When Blitz2 first runs a program it calls all the init routines of the libraries required by the program. Any code to initialise tables and allocate memory for the libraries' routines would be pointed to by the init nullsub in this instance a routine called jnitmylib. The 1 after init in libheader means our init routine returns a long word for use by other libraries (must be lower priority). This is useful for sharing large tables or a common data structure between two related libraries. size of obj The finit routine is called when a program ends, it is useful for any clean up procedures, for example the med library uses a finit routine to make sure all audio channels are silent, it could also be used to make sure specific opened files are closed etc. ERROR CHECKING When error checking is enabled Blitz 2 calls any specified error routines before calling commands. The last parameter of libheader should point to the start of these routines. When error checking is not enabled Blitz 2 will not load this section of the library saving memory. If any commands require an optional error checking routine that is enabled/disabled from the compiler options the location of the error checking routine should be passed in the second parameter of the !subs macro of that command. The error routine should be located at the end of the library after the errorroutines pointer in libheader. An error routine usually comprises of code that checks parameters are in range, if it fails the location of a message is placed in register dO followed by a Trap#0 instruction which will bring up the familiar Blitz 2 error requester, if parameter checking succeeds the error routine should return making sure not to corrupt any vital registers. LIBRARY OBJECTS The optional parameters of the !libfin macro are used to define a libraries' own object type. Examples of Blitz objects are listed in Appendix 1 of the reference manual. The first parameter of !libfin points to the !dumtoke confining the objects name. This dumtoke should be positioned directly after libinit as in the above example. The "Load" and "Save" routines are not implemented and should point to nullsub macros as listed. The "used" nullsub can point to a routine which will be called when the Use MyObjectName command is used. An example of this is Use Palette 3, not only does Palette Object number 3 become the currently used object but is also displayed on the current Slice or Screen. The "free" nullsub can be used to de-allocate memory that the object used. The last two parameters of llibfin are the default number of objects that will be allocated (can be changed by the user in the compiler options requester) and the size of each object. The size is computed by 2 A sizeparameter so the 5 in the above example represents 32 bytes allocated for each object. OBJECT PARAMETERS The Blitz 2 library system has a wide range of features in the parameters (arguments) department. The !args macro can contain up to 15 argument definitions. To specify an argument use the constants #byte, #word, #long, #quick and #float. Blitz 2 will convert the type the user passed to the correct type. The parameters will be passed in registers d0-d5, extra parameters will be passed to your routine on the stack and can be recovered by move(.l)-(a2),register. The following argument definitions can sometimes be used in combination, for instance the sort command uses #array+#arrayend+ #unknown so it can operate on any type of single dimension array of any type. The array base arrives in dO, an the routine pulls the array end location of the stack first and then the type. #string specifies a string argument, the location is passed in the proper register and its length will be pushed on a stack, recovered by a move.l -(a2), register. All Blitz strings are null terminated. #usesize must be the first parameter definition (if required) and will return the type of command in register dO. i.e. poke.w returns the constant #word in dO. #unknown will pass the type of variable the user passed to the routine on the stack and can be recovered by move.w -(a2),register. The print statement uses this form to evaluate what type each of the paramters passed to it are. #array will pass the location of the array/list base to your routine. #arrayend will pass the location of the end of the array on the stack, used by the sort() command to calculate number of items in the array #push will place the parameter on the stack and not in the relevant data register (useful for calling C routines). #varptr returns the location of the variable passed (not its value). Variable specification of parameters are possible with the !repargs macro. The format is similar to the standard !args macro however two parameters are inserted at the start of the code, first_repeat and size_repeat. Blitz 2 will treat the next argument definitions as usual until the first repeat parameter is reached and then parameter definitions apply to extraneous parameters in groups of size_repeat. The following examples should make things clearer... myroutine a.w.b.q [,cn.w...l => !repargs{2,1,#word,#quick,#word) myroutine a.w [[,t1n.q,t2.w]...] => !repargs{1,2,#word,#quick,#word} The second example expects a word then any number of pairs of quick.word. Blitz 2 will pass your routine the number of parameters in register d7. PROCESSING LISTS The #array parameter definition also enables the base of a ListArray to be passed to your routines. The characters "llsT" ($6c497354) are located at -12(arraybase) if the array is a link list. The following code example demonstrates processing the contents of a linked list, presuming its base is passed in dO.... MOVE.l dO,aO ;aO=list base MOVE.l -28(a0),a0 ;a0 points to first item (-32= "current item) nxt:TST.l (aO) .empty node? BEQ finished ;yes exit LEA 8(a0),a1 ;a1 points to item data BSR processjtem MOVE.l (aO),aO ;go to next item in list (4(a0)= "previous item) BRA nxitem dun:RTS THE LIBS MACRO Often your routines will require a library base (value returned by that libraries init routine) or pointers to library objects (be it your own libraries objects or other libraries). The following constants are for use in the libs macro and define what information you require passed in which register, reg is restricted to d0-d7/a0-a3/a6. A library number should follow each constant be it your own libraries or another. #l,libnum load the specific register with libnum's base #lpush,libnum push the libnum's base onto the stack #used,libnum loads reg with location of currently used library object #base,libnum loads reg with location of base item (item 0) #mrax,libnum returns the maximum number of objects set in compiler options #\reg\ #preg,libnum loads the reg with location of object(#prep), tipreg being a parameter passed in args. Examples: !libs{#la1,#chipbaselib, #la6,#doslib} Location $dff000 is passed in a1,_DOSBASE in a6 (ready for dos calls) !libs{#la0 | #ud0,#shapeslib,#ua1 ,#bitmaplib) The location of the shape with number specified by the first argument is passed in aO, the currently used bitmap is passed in a1. BLITZ/AMIGA MODES If a1 is added to the first parameter of a !subs macro Blitz will only let the user use the command in Amiga mode as in the above example. If a 1 is added to the second parameter (error routine) then the command is BlitzMode only. Of course any 1 is stripped by Blitz when it evaluates the labels! If the command has two routines one for Blitz mode and one for Amiga mode the following convention should be used at the routines labelled location: routine: dew SaOOO 1 ;cail blitz 2 line 10 10 emulator del blitz_routine amigajoutine: ; ;amiga version here its blitz_routine: iblitz version here rts If your command uses the blitter the Amiga version of the command should call Own_Blitter, bsr the BlitzMode version then DisOwn_Blitter. Before poking Blitter registers in your routine always do a BlitWait. The following code should be used: myblit: dc.w SaOOl : dc.l _domyblit ;in blitz mode, go straight there ALibJSR $c203 ;own blitter bsr _domyblit ALibJSR $c204 .disown blitter rts domyblit: INLINE CODE Pp Relative code can be inserted directly into the object code by the Blitz 2 compiler. Note the rts is not included in the size of the code. The code must be completely self contained with no absolute addressing. corfimandlabel: dc $a000,'f-'s 's ; code goes here (no absolute adressing!) * its CALLING OTHER LIBRARIES i .■ The memory allocate and free routines have already been described in the Libraries chapter of the User Guide. The following is a list of useful System calls for use with the ALipJsr command (the BLibJsr command is for accessing the BlitzMode version of certain commands). All of the following routines will only alter the registers supplied and preserve all registers not listed. Command: #globalalioc=$c002 (memlib) Syntax: memoryblock dO.I ■ globalalloc (bytesize dO.I, memtype dl.l) Despription: Standard memory allocate routine, automatically cleared by Blitz when program ends, see also globalfree. Command: #globalfree=$c003 (memlib) Syntax: globalfree memorylocation a1 .1, bytesize dO.I Description: Standard memory deallocate routine. Command: #newlocalmem=$c004 (memlib) Description: Creates a new local memory node, which will link subsequent calls to localalloc together, useful for recursive type operations, for advanced users only. Command: #freelocalmem=$c005 (memlib) Description: Frees all memory attatched to current local memory node. Command: #localalloc=$c000 (memlib) Syntax: memoryblock dO.I = localalloc (bytesize dO.I, memtype dl.l) Description: Local memory allocate routine, for use after newlocalmem call. Command: #localfree=$c001 (memlib) Syntax: localfree (memorylocation al.l, bytesize dO.I) Description: Local memory deallocate routine. Command: #addanint=$c100 (intlib) Syntax: addanint level+ID+$8000 dO.w, code d1 .1 Description: Adds an interupt at the level specified, low 4 bits of dO should contain interupt level, high bit must be set, other bits can be used for ID. Interupt code should be pointed to by register d1. It is up to the programmer to determine whether ALibJSR of BLibJSR is appropriate by determining which mode their command is being called in. Amiga mode interupt code MUST preserve d2-d7/a2-a4 and end with moveq #0,dO, Blitz mode interupts should preserve registers d5-d7/a4. Command: #clranint=:$c10t (intlib) Syntax: clranint level+ID+$8Q00 dO.w Description: Removes the interupt(s) with specified ID from the interupt list. Reserved Interupt ID'S are: Level 3: $8003-BlitzKeys (strobe) Level 5: $8005-FadeLib $8015-Mouse $8025-TrackerLib $8035-BlitzKeys (repeat function) Commands: #goblitz=$c200, #goamiga=$c201, #goqamiga=$c202 (switchlib) Description: Changes operating mode for compiler and program. Commands: #ownblit=$c203, #dtsownblit=$c204 (switchlib) Description: Must be used before and after routines that use the blitter in Amiga mode. Command:' #progend=$c800 (exitslib) Description: same as the Blitz command End. Command: #getffpbase=$c900 (ffplib) Description: returns library base of mathffp.library in a6. Commands: #quickmult=$caOO, #iongmult=$ca01 (Imulllib) Syntax: d0.q=quickmult(d0.q,d1.q) and d0.l=longmult(d0.l,d1.l) Description: Functions that multiply two quicks and two longs. Commands: #quickdiv=$cbOO, #!ongdiv=$cb01 (Idivlib) Syntax: d0.q=quickdiv(d0.q/d1.q) and d0.l=longdiv(d0.l/d1.l) Description: Functions that divide two quicks and two longs. Command: #allocstring=$cf01 (maxslib) Syntax: string dO.I=allocstring(location of text dO.I, length d1 .1) Description: A null terminated copy of the string is created, a pointer to which is returned in DO. This is mainly used to create copies of string parameters for such things as screen or window titles. Command: #freestring=$cf02 (maxslib) Descriptioh: frees up the string pointed to the register dO. Commands: #qu!Cktofloat=$d300, #floattoquick=$d301 (floatquicklib) Syntax: d0.f=quicktofloat(d0.q) d0.q=lloattoquick(d0.f) Description: Functions to converts between quick and long types.