home *** CD-ROM | disk | FTP | other *** search
- Blitz2 Library Developers Documents
- September 1994
- Mark Sibly and Simon Armstrong
-
-
-
- INTRODUCTIONS
-
- The following is a collection of articles, docs and so forth for those
- wanting to develop command libraries for Blitz2. Only those experienced
- in the ways of assembly programming will be interested.
-
-
- COPYRIGHT NOTICE
-
- To help those wanting to develop libraries a large number of source codes
- have been included in this archive. All code include is copyright and
- hence should not be duplicated in other files without the author's
- express permission. Authors can be contacted via the address given in
- the documentation for each library published in BUM7.
-
- Acid Software can be contacted either via email: at acid@iconz.co.nz or
- via fax on +649 358 1658.
-
-
- TOOLS OF THE TRADE
-
- Before starting on your own libraries several programs and files will
- need to be setup in their correct position. First the blitzlibs: volume
- which includes the userlibs, amigalibs, basic and system directories
- should be installed on harddisk with an "ASSIGN BLITZLIBS: pathname"
- added to the your system's startup-sequence.
-
- Along with the 4 directories in blitzlibs: (do NOT add any others)
- copy the res files included in this archive, in particular make
- sure the file blitzlibs:libmacs.res is able to be found by Blitz2.
-
- You will also want to create executable versions of the libsdev tools,
- the src has been included in the toolssrc directory of this archive.
- It is probably easiest to compile them to your c: directory.
-
-
- OVERVIEW
-
- Blitz2 has an expandable command set. When you startup Blitz2 it attempts
- to load the command set from the file Blitz2:DefLibs. If it cannot find
- this file it will load the command set from the Blitzlibs: directories.
-
- Users are able to create new command libraries and add them to the
- userlibs directory of blitzlibs:. While developing a library remove
- the deflibs file from the Blitz2: drawer so that Blitz will always
- load it's commands from the BlitzLibs: volume. You can also override
- the DefLibs commands by select ReLoadLibs from the compiler menu.
-
- After creating a new .obj file in your blitzlibs:userlibs drawer you
- can test your library select ReloadLibs and create a test program to
- use your new commands. If Blitz2 crashes with an "Out Of Memory" or
- some such error during loading of libs, you have obviously created
- an illegal library file and will have to remove it from Blitzlibs:userlibs
- before restarting Blitz2.
-
- Other things to make sure of when creating library .obj files is to
- never have runtime errors enabled and never include any BASIC tokens
- (the END statement in particular), both these will create illegal
- library files.
-
- Once your library is complete you can use the makedeflibs command to
- create a new Blitz2:DefLibs file so you can return to the fast loading
- Blitz2 you once new (Blitz2 is much quicker at loading DefLibs than
- scanning the entire BlitzLibs: volume).
-
-
- CONVERTING STANDARD AMIGA LIBRARIES...
-
- If you just wish to access an unsupported standard amiga library (such
- as those that hang out in your libs: drawer) you will need to convert
- it's corresponding .fd file. You will notice the .fd file contains
- parameter and syntax information for all the commands in the .library
- file. By running the fdconvert tool, you can add a corresponding
- Blitz library in the BlitzLibs:AmigaLibs drawer which will let you
- access these commands from Blitz2. Make sure the .fd library specifies
- the name of the actual library in the top line (same as DOS3 standard
- .fd files).
-
- The fdconvert program should assign a suitable library number for your
- new amigalib. Check the libnums.bb file in the ressrc file for
- what library number assigns have been made for amigalibs upto
- now (first available should be #217).
-
- After running fdconvert either create a new deflibs file with the
- makedeflibs tools or use ReloadLibs in the Compiler menu of Blitz2.
- All the commands that were listed in the fd file should now be
- part of Blitz2, the only difference is that they are all succeeded
- by an underscore character to avoid clashes with Blitz2 tokens.
-
-
-
- ---------------------------------------------------------------------------------
- Text file taken from BUM7's readme directory by Simon Armstrong
- ---------------------------------------------------------------------------------
-
-
- Notes for Library Developers
-
- Well, I've been a bit bamboozled by all the userlibs that have been
- arriving in the mail. The following are a few notes I've jotted down
- after spending a lot of time trying to tidy up what you guys have
- been sending in.
-
- 1. LibNums and general naming conventions.
-
- OK, first up, library numbers. Not a big deal as we are probably
- going to get rid of tokenising in Blitz3 so that 1. we don't get
- all the clashing that has been going on and 2. users can use what
- ever ascii editor they please. However in the mean time (and for
- ever more if the Amiga is still out of production by XMas)....
-
- Do NOT use library numbers above 40. Especially do NOT go sticking
- your libraries in between Acid ones (ELMORE!!!) we left the odd
- numbers for our own expansion not yours! To be generous I have
- allocated the following for those that feature on BUM7 and are working
- on new libraries:
-
- Elmore - 99 97 95, RI - 63 58 51, Neil - 50 49 48, Romulus- 47 46 45
-
-
- Secondly, do not use words like len, start and so forth (RI!!!). As
- BASIC programmers like to use such words for variables it is a bit
- rude to find that someone has gone and called a command after your
- favourite variable name (don't don't don't add a command called i!),
-
- To be really snazzy you should try and use the library name (make it
- concise) in all your tokens like I have done in the display library,
- this makes things a lot easier to read, avoids token clashes (Elmore,
- any chance of a tokenclash tool?) and possibly keeps you on the straight
- and narrow.
-
-
- 2. Syntax and library content.
-
- Avoid extraneous commands at all costs. If you can use different forms
- of the same command DOIT. If the command is the same as using two or
- three commands don't bother. Rule of thumb I suppose is add parameters
- to make key commands more powerful rather than adding more commands.
-
- If you are just implementing small pieces of machine code to do miscellaneous
- jobs don't bother. Just stick the machine code in a statement and publish
- the statement. Commands added to Blitz2 should not be the sort that you
- can acheive in a few lines of code, they just make Blitz2 a more obese
- rather than ultra powerful language.
-
- With the advent of the ASMEXIT command machinecode routines can now
- be placed in functions and statements in a stable manner. To use
- ASMEXIT do not use UNLK A4 but simply replace any RTS commands
- with ASMEXIT, ensure that registers a4-a6 are restored before
- ASMEXITting.
-
- If you are adding commands that belong in Acid libraries, please ask me
- for the source for that particular library, and add them there, it makes
- my job a hell of a lot easier and means with new documentation users will
- know about your command cos they are looking in the correct section ot
- the manual.
-
-
- 3. A few other pointers...
-
- * OS2/3 specific commands should check the version of exec and exit
- cleanly if too old:
-
- MOVE.l 4,a0:CMP #36,20(a0):BCS doexit ;wo older than v36!!!
-
- * Use Blitz2 objects if they are suitable, best place to work out
- how they work is in the source code the acidlibs I have included
- in the libsdev archive. Hmmm, a quick lesson on this follows below.
-
- * always use ALibJSR $c002 and $c003 for allocating and freeing
- memory, never use the exec calls...
-
-
- 4. And please please please...
-
- Prefix the name of you library with your handle or name, those finding
- to their horror the source of their libraries published here please
- update your own source codes with the changes I've made.
-
- Keep a history file at the top of your library source, it makes keeping
- the documentation uptodate so much easier.
-
- Test your commands with bad parameters to make sure your error checking
- is cool, save a .test file with your library when you submit it so others
- can see how to use your commands, and try and follow the documentation
- style that I've been using in BUM7. IE, list all the commands at the
- top then describe them one by one.
-
- Keep your .res files in the root of blitzlibs:, reference all resident
- files in compiler options as blitzlibs:filename.res and use
- blitzlibs:userlibs as the path when creating object files. Getting a
- bit picky here I think. Oh DO take notice of the new keyboard shortcuts
- in the compiler menu.
-
-
- 5. And very importantly...
-
- Make sure you return A4 how you found it, it is the local variable
- base and if you stuff it you will not be able to use your commands
- inside functions and procedures (yes I know I am guilty of this
- often).
-
- Keep your library .obj files as small as possible. If you need a hunk
- of memory allocate it in the init routine, DON'T USE ds.l big. If you
- have a look up table try and generate it from allocated memory during
- initialisation rather than INCBIN the thing, DefLibs is too bloody
- big as it is, don't push it! Anything over 4K is no go unless it is
- major cool.
-
- Use moveq whenever possible. It is fast and sign extends to a
- long word. Use pc relative adressing as much as possible as Blitz2
- does not optimise this. Use addq and subq also whenever possible.
-
- Anyway, thanks for everyone who has been adding commands, please don't
- take the above personally just trying to keep things tidy...
-
- Blitz2 Library Objects.
-
-
- Yes, bloody wonderful things. OK, say your library is based around a
- particular object or structure, hopefully something useful that will
- make Blitz2 programmers want to give you their girlfriends...
-
- First up I define a NewType similar to the other Blitz2 objects as listed
- in an appendix of the Blitz2 manual, and define a macro to make my assembly
- code much more readable:
-
- Macro s
- {SizeOf.sound\`1}(a3)
- End Macro
-
- NEWTYPE .sound
- data.l
- size.l
- period.w
- volume.w
- priority.w
- etc etc
- End NEWTYPE
-
- Of course I call my library acidsoundlib so it doesn't get mixed up with
- everyone else's sound libraries, assign it a number (see above) and define
- the name of my sound object in the dumtoke, This allows the programmer to
- use the free object, addr object() etc. on my object.
-
- #acidsoundlib=40 ;library number at top as constant
-
- !libheader {#acidsoundlib,init,1,0,0} ;header with init routine if needed
-
- !dumtoke{"Sound","",_toke} ;wo clash, only example ok?
-
- !astatement
- !args {#word,#long,#word}
- !libs {#acidsoundlib,$1380}
- !subs {_initsound,0,0}
- !name {"InitSound","Sound#,length,flags"}
-
- init:!nullsub {_initlib,0,0}
-
- _load:!nullsub{0,0,0}
- _save:!nullsub{0,0,0}
- _use:!nullsub{0,0,0}
- _free:!nullsub{0,0,0}
-
- !libfin{_toke,_load,_save,_use,_free,4,5}
-
- OK, we don't worry about the nullsubs this week. the last two numbers in the
- libfin macro define the default number of objects (before the user increases
- them via the compiler options) and the size of the object which is 2^n so
- Blitz2 can do a shift to calculate the location of the object any parameter
- is referencing. The 5 means our object can take up to 32 bytes.
-
- Hmmm, the !libs macro has the number $1380. There are some macros in libmacs for
- this but I always forget them. The high byte says which address register you
- want to point to the object, the low byte defines which parameter to use:
-
- #a0=$1000:#a1=$1100:#a2=$1200:#a3=$1300:#a4=$1400:#a5=$1500:#a6=$1600
- #p0=$80:#p1=$81:#p2=$82:#p3=$83:#p4=$85:#p5=$85
-
- So if I want the adress register a3 to point to the object# defined by the
- first parameter I use the code #a3+#p0 = $1380
-
- If I had a copy sound command that needed source in a2 and destination in
- a3 I'd use the following setup:
-
- !astatement
- !args {#word,#word}
- !libs {#acidsoundlib,$1280,#acidsoundlib,$1381}
- !subs {_copysound,0,0}
- !name {"CopySound","SrcSound#,DestSound#"}
-
- And, gosh it's exciting... yes a2 and a3 will be preloaded all ready to go
- at the start of your routine. Use #word in !args for all parameters that
- refer to objects.
-
- OK, thats about it, oh the macro and newtype stuff, basically if you always
- pass the object number in say a3 set up the macro as I have done and whenever
- you want to reference a field in the object you can use it's name e.g.
-
- move.l !s{size},d1:move.l !s{data},d2
-
- which is the same as
-
- move.l 4(a3),d1:move.l 0(a3),d2
-
- Hmmm, other things:
-
-
- 1. Objects are always initialised with zero's on program startup
-
- 2. The free subroutine if you provide one will be called for all
- objects on program exit.
-
- 3. See banklib source for basic memory management.
-
- 4. Use other libraries objects, but always check if they are initialised.
-
-
- ---------------------------------------------------------------------------------
- Following republished from AmigaDownUnder article by Mark Sibly
- ---------------------------------------------------------------------------------
-
-
- HOW TO WRITE BLITZ BASIC 2 LIBRARIES
- ************************************
-
- The Blitz 2 compiler is heavily library orientated. What this means is
- that many of the routines and functions used by the compiler are not actually
- stored in the compiler itself, but in completely separate library files.
-
- This set up allows new commands and features to be easily added to the Blitz 2
- system, simply by creating a new library file.
-
- Libraries in Blitz 2 are usually written in Blitz 2 itself, and must be
- TOTALLY in machine code.
-
- Before we get into actually writing a library, let's first have a look at
- the basic layout of libraries in Blitz 2.
-
- Varieties of Blitz 2 Libraries
- ******************************
-
- Blitz 2 makes use of 3 types of libraries - system libraries, Amiga libraries
- and command libraries. Let's have a closer look at these:
-
- * System libraries - These libraries are used internally by the Blitz 2
- compiler and include such mundane operations as memory allocation, string
- manipulation and so on. System libraries will only ever be modified by Acid
- software, as they work in connection with Blitz 2 at a very low level.
-
- * Amiga libraries - These libraries allow Blitz 2 programmers access to any
- of the operating system libraries (eg: intuition.library,exec.library).
-
- * Command libraries - These libraries form the bulk of the Blitz 2 system, as
- they contain all the BASIC commands and functions available to Blitz 2
- programmers. All of the Window, Screen, Blitting etc. commands are held in
- command libraries. To add new commands to Blitz 2, a command library should
- be created containing these new commands, and this is just what we'll be
- doing...soon...
-
- Where ARE the Blitz 2 Libraries to be found?
- ********************************************
-
- When Blitz 2 starts up, it needs to be able to locate all the libraries
- available. It does this by first looking for a file called 'Blitz2:Deflibs'
- (for 'default libraries'). If this file is not found, Blitz 2 then goes and
- looks for a directory called 'Blitzlibs:'. If neither Deflibs or Blitzlibs:
- can be found, then Blitz 2 gives up and politely (?) exits.
-
- If Blitz 2 can find Deflibs, then it uses the contents of Deflibs as it's
- libraries. If Blitz 2 can only find Blitzlibs:, it then proceeds to scan any
- sub-directories of Blitzlibs:, and uses any files found as it's libraries.
- At the moment, there are 4 sub-directories set up within blitzlibs: - 'System',
- 'Amigalibs', 'Basic' and 'Userlibs'.
-
- It's worth pointing out here that Deflibs is simply all the separate Blitzlibs:
- libraries joined together as one continuous file. This was done to speed up
- the library loading process, and to make the whole system more user-friendly.
- A program called 'Makedeflibs' can be used to create the Deflibs file from
- the individual Blitzlibs: libraries.
-
- Getting started
- ***************
-
- First, you'll need to unarchive the 'blitzlibs.lha' file into a blitzlibs
- directory, and add yet another assign to your startup-sequence (eg: assign
- blitzlibs: blitzlibs). Next, get rid of 'Blitz2:deflibs' to prevent Blitz 2
- from looking for it instead of blitzlibs:. This can be done simply by moving
- Deflibs from the Blitz2: directory to a different directory, or by renaming
- it.
-
- Next, crank up Blitz 2 to make sure everything's still going OK. You should
- notice Blitz 2 takes longer to startup, due to it having to load in the
- individual library files from blitzlibs:.
-
- Writing a Blitz 2 Library
- *************************
-
- Before you can go ahead with writing your library, you'll have to first
- choose a 'number' for your library. Each library in Blitz 2 has it's own unique
- identifying number, so you must make sure the number you choose for your library
- does not clash with any other libraries.
-
- Acid software has decided, in it's infinite wisdom, that any libraries under
- development should be given a library number from 10...50. So, you'll probably
- choose 10 for your first library, 11 for your second, and so on...
-
- If you finish a library and are pretty proud of it and feel it would be of
- benefit to Blitz users in general, Acid software can be contacted to obtain
- a permanent library number.
-
- One more thing you'll need to write your library is the 'libmacs.res'
- resident file. This file contains a set of macros and constants necessary
- for writing libraries. If you're not familiar with resident files, refer to
- the Blitz 2 User guide section 10-1.
-
- Libmacs.res can be found in the Blitzlibs: directory, and before starting
- work on a library you'll need to load it in via the 'Compiler/Options'
- menu.
-
- OK, so you've got libmacs.res loaded and you've decided upon your library
- number. It's now time to get coding!...
-
- We'll start of with a quick example library that doesn't do all that much
- but should give you an idea of what's going on:
-
-
- ;
- ;examplelib
- ;
- ;An example of library writing in Blitz 2
- ;
- ;A decidedly useless command to blink your LED on/off
- ;
- ;we're going to give our library the number 10...
-
- #mylib=10
-
- ;***** First up, a header for the library... *****
-
- !libheader{#mylib,0,0,0,0}
-
- ;***** now, the actual commands in the library *****
-
- !astatement
- !args{#word}
- !libs{#graphicslib,#la6}
- !subs{doblink,0,0}
- !name{"Blink","number of blinks"}
-
- ;That's it!
-
- !libfin
-
- ;***** Now comes the code for the library *****
-
- doblink
- ;
- MOVE d0,d2:BEQ 'skip:SUBQ #1,d2
- 'loop
- BCHG #1,$bfe001:JSR -270(a6) ;call graphics library 'Wait top of frame'
- DBF d2,'loop
- 'skip:RTS
-
- ;***** That's all for our library! *****
-
-
- Once you've typed this in, save it, then create an executable by the name of
- 'Blitzlibs:userlibs/examplelib.obj'.
-
- To test out your library, use the 'Compiler/Reload Libs' menu item. This
- will force Blitz 2 to re-load all it's libraries from Blitzlibs:. Following
- this, your awesomely useful 'Blink' command should now be available to
- Blitz 2...
-
- ;
- ;Test of the new 'Blink' command...
- ;
- Blink 10 ;blink ten frames....
- ;
-
- Now, let's go through the examplelib a line at a time:
-
- !libheader{#mylib,0,0,0,0}
-
- The !libheader macro should always appear at the start of a library.
- The libheader macro looks like this:
-
- !libheader{library number,initialize,return,cleanup,runerrs}
-
- The 'initialize' parameter allows you to specify a routine which gets
- executed when a Blitz 2 program is run. Likewise, 'finish' may specify
- a clean up routine when the program ends. If either of these is set to 0,
- then they are ignored.
-
- The 'return' parameter allows the library's initialise routine to return
- a value, in d0, which other libraries may access. If this parameter is 0,
- then this means the libraries initialization returns nothing. If this parameter
- is 1, this means the initialization routine returns a value in d0 which other
- libraries may access. We'll have a closer look at this when we get to the
- !libs bit...
-
- 'Cleanup' is similar to 'initialize', allowing the library to doing any
- tidying up when the program ends.
-
- The 'runerrs' parameter informs Blitz2 of where any runtime error checking
- code is located. We'll go into this later as well.
-
- After the libheader, the library then goes on to specify the actual commands
- in the library - in this case, there is only one command...
-
- !astatement
- !args{#word}
- !libs{#graphicslib,#la6}
- !subs{doblink,0,0}
- !name{"Blink","number of blinks"}
-
- The !astatement macro specifies that this command is a statement, as
- opposed to a function. In other words, Blink doesn't return any value.
-
- The !args macro gives the arguement template for our command. In this case,
- !args{#word} means that the Blink command takes only 1 parameter - a 16 bit
- word. We can specify as many parameters as we want here, and they may be any
- of the following types:
-
- #byte
- #word
- #long
- #quick
- #float
- #string
-
- Parameters are passed to library routines through the 68000 data registers
- D0 through D6 - the first parameter being passed in d0, the second in D1 and so
- on. If there are more than 7 parameters, extra parameters get passed on the
- stack. Also, string variables are passed through the use of a data register
- as a pointer to the string, and the length of the string on the stack. We'll
- cover stack usage in more detail a bit later on.
-
- Onto the !libs macro. This macro allows us to 'grab' data from other
- Blitz 2 libraries for use by our command...
-
- !libs{#graphicslib,#la6}
-
- In this case, we are asking for the 'graphics.library' library base to be
- placed in A6 before our blink routine is called. Remember the 'initialise'
- and 'return' parameters of the !libheader macro? Well, the Blitz 2 library
- 'graphicslib' uses these parameters to open the graphics library and return
- the library base in d0 for other libraries to use.
-
- We can also specify multiple libraries using the !libs macro. For example:
-
- !libs{#graphicslib,#la6,#intuitionlib,#ld6}
-
- Will give us graphics base in a6, and intuition base in d6.
-
- Now we get to the !subs macro:
-
- !subs{doblink,0,0}
-
- This simply contains a pointer to the actual code to execute once all
- parameters and library values have been placed in appropriate registers.
-
- The 2 '0' parameters here are used for runtime error checking purposes.
- More on this later.
-
- Finally, we get to name our new command:
-
- !name{"Blink","number of blinks"}
-
- The !name macro takes at least 2 text parameters. The first gives the
- actual name of the command, while the second specifies the 'help' text for
- the command. A third parameter may be given allowing a label to be associated
- with the text - this is of use when creating Blitz 2 objects (see below).
-
- Once we've finished specifying the format of our libraries commands, we
- use the !libfin macro:
-
- !libfin
-
- The rest of the program contains the actual machine code to perform the
- Blink command.
-
- FUNCTIONS
- *********
-
- Blitz 2 functions are created almost identically to statements, except we use
- the !afunction macro instead of !astatement. The !afunction macro must
- be supplied with a single parameter indicating what type of result is returned
- by the function. Then, it's up to the actual function code to return the
- appropriate type of value in D0.
- Let's expand our library to demonstrate writing a function...
-
-
- ;
- ;examplelib
- ;
- ;An example of library writing in Blitz 2
- ;
- ;A decidedly useless command to blink your LED on/off
- ;
- ;we're going to give our library the number 10...
-
- #mylib=10
-
- ;***** First up, a header for the library... *****
-
- !libheader{#mylib,0,0,0,0}
-
- ;***** now, the actual commands in the library *****
-
- !astatement
- !args{#word}
- !libs{#graphicslib,#la6}
- !subs{doblink,0,0}
- !name{"Blink","number of blinks"}
-
- !afunction{#word} ;inidcates that this function returns a word.
- !args
- !libs
- !subs{doledstatus,0,0}
- !name{"LEDStatus",""}
-
- ;That's it!
-
- !libfin
-
- ;***** Now comes the code for the library *****
-
- doblink
- ;
- MOVE d0,d2:BEQ 'skip:SUBQ #1,d2
- 'loop
- BCHG #1,$bfe001:JSR -270(a6) ;call graphics library 'Wait top of frame'
- DBF d2,'loop
- 'skip:RTS
-
- doledstatus
- ;
- BTST #1,$bfe001:SNE d0:EXT d0:RTS
-
- ;***** That's all for our library! *****
-
-
- LIBRARY INITIALIZATION AND CLEAN UP
- ***********************************
-
- If your library needs to perform some kind of initialization or cleaning up,
- the 'initialize' or 'cleanup' parameters of the !libheader macro may be used.
- However, instead of simply pointing to some code, these parameters should
- point to a !nullsub macro. A WHAT!?!? Well, !nullsub is basically a combination
- of the !subs and !libs macros. The first 3 parameters of !nullsub are the same
- as those for !subs, while the rest allow you to pickup values from other
- libraries similar to the !libs macro. This set up allows you import data from
- an external library for use during initialization or cleanup. For example,
- let's say you need intuition base to perform your libraries initialization and
- cleaning up:
-
- !libheader{#mylib,init,0,cleanup,0}
-
- init
- !nullsub{doinit,0,0,#intuitionlib,#la6}
-
- cleanup
- !nullsub{docleanup,0,0,#intuitionlib,#la6}
-
- .
- .
- .
-
- !libfin
-
- doinit ;actual initialization code...
-
- docleanup ;clean up code...
-
- Note that libraries are initialized numerically, from higher numbered
- libraries to lower numbered. Therefore, if you have written 2 libraries of
- which one requires the returned value from the other, the library supplying
- the value should be of a higher library number than the one receiving.
- Also note that the !nullsub macro should appear between the !libheader
- and !libfin macros - NOT in the main code.
-
- THE STACK
- *********
-
- Parameters are normally passed to library routines through data registers
- D0 through D6. However, in the case of string variables, or when a command
- requires more than 7 parameters, parameters may end up on the stack. To help
- in keeping track of stacked parameters, Blitz 2 copies the stack pointer to
- address register A2 before anything gets placed on the stack. This allows
- you to step through stacked parameters using the -(A2) addressing mode instead
- of having to play around with offsets from A7. For example, say you're writing
- a command which requires one string parameter. When the commands routine is
- called, the address of the string will be in D0, and the strings length will be
- on the stack. The routine could then pick up the strings length using:
-
- move.l -(a2),d1
-
- Note that Blitz 2 Version 1.80 and higher will automatically null terminate
- all strings. Earlier versions only null terminate the last string of a
- parameter list.
- Also remember that if you're wanting to use A2 in this way, you must not
- use A2 in the !libs macro.
-
-
- RUNTIME ERROR CHECKING
- **********************
-
- Blitz 2 libraries may also contain runtime error checking code. This code may
- be used to check that command (or function) parameters are within a legal range.
- Remember, this extra code will only be executed if the 'RUNTIME ERROR CHECKING'
- option within the compiler/options menu is enabled.
- Error checking code must always appear at the end of a library. This
- allows Blitz 2 to drop this code when runtime error checking is disabled.
- To add error checking to a library, you need to indicate where in the
- library the actual error checking code starts. This is done through the
- 'runerrs' parameter of the '!libheader' macro. Then, it's simply a case of
- using the '!subs' macro to indicate any error checking routines that needs to be
- called.
- If an error checking routine decides that a parameter is bad, a 'TRAP #0'
- should be executed with D0 pointing to an appropriate error message string.
- To demonstrate this, we'll alter our example library to make sure 'Blink' only
- allows parameters of 0...100:
-
- ;
- ;examplelib
- ;
- ;An example of library writing in Blitz 2
- ;
- ;A decidedly useless command to blink your LED on/off
- ;
- ;we're going to give our library the number 10...
-
- #mylib=10
-
- ;***** First up, a header for the library... *****
-
- !libheader{#mylib,0,0,0,runerrs}
-
- ;***** now, the actual commands in the library *****
-
- !astatement
- !args{#word}
- !libs{#graphicslib,#la6}
- !subs{doblink,doblinkcheck,0}
- !name{"Blink","number of blinks"}
-
- !afunction{#word} ;inidcates that this function returns a word.
- !args
- !libs
- !subs{doledstatus,0,0}
- !name{"LEDStatus",""}
-
- ;That's it!
-
- !libfin
-
- ;***** Now comes the code for the library *****
-
- doblink
- ;
- MOVE d0,d2:BEQ 'skip:SUBQ #1,d2
- 'loop
- BCHG #1,$bfe001:JSR -270(a6) ;call graphics library 'Wait top of frame'
- DBF d2,'loop
- 'skip:RTS
-
- doledstatus
- ;
- BTST #1,$bfe001:SNE d0:EXT d0:RTS
-
- ;***** OK, time for runtime error checking code! *****
-
- runerrs
-
- blinkcheck
- CMP #101,d0:BCC blinkerror:RTS
-
- blinkerror:MOVE.l #blinkerrortext,d0:TRAP #0
-
- blinkerrortext:DC.b "Number of blinks must be 0...100",0:EVEN
-
- ;***** That's all for our library! *****
- ;
-
- WARNING! WARNING! WARNING!
- **************************
-
- Any library routines, whether they be statements, functions, runtime error
- checks or simply initialization code, MUST preserve address registers A4, A5
- and A6. As well, a function MUST ALSO preserve address register A3. Just what
- are these registers used for?
-
- A6 : Blitz keeps track of A6 to prevent it having to be unnecessarily
- re-loaded.
- A5 : Blitz 2's global variable base.
- A4 : Blitz 2's local variable base.
- A3 : Blitz uses this to build temporary strings.
-
-
- THAT'S ALL FOLKS
- ****************
-
- Hopefully, you'll now have enough information to begin writing your own
- libraries. In the next installment of this series, we'll have a closer look
- at string variables in Blitz 2, creating Blitz 2 objects and more. In the
- interests of keeping this document as self contained as possible, I'll finish
- up with the source code to libmacs...
-
- Plesant programming,
-
- Mark Sibly
-
-