home *** CD-ROM | disk | FTP | other *** search
- ZSM, ZLINK, ZLIB, ZPATCH, ZC - Z80 assembler package
-
- Background.
-
- I originally wrote this assembler with a view to using it as part
- of a C compiler, however I don't know when, if ever, I'll write the compiler.
- As for the assembler, I chose to write my own because the only other one I've
- worked with is Microsoft's M80, and while this is a good assembler, I find
- that it is a bit to restrictive in the way it deals with external labels. In
- addition, I wanted to make library management easy, hence the production of
- ZLIB, and the .lib directive.
-
-
- Usage.
-
- Assuming that you have used an editor to produce your source file,
-
- A>ZSM FILENAME.Z -LSX -TB
-
- is the command that will turn it into an object file. Source files must have
- the .Z extension, and object files will have a .O extension (or .L: see
- libraries and the .lib directive). Since the .Z must be on the source file,
- it is optional on the command line.
-
- The only four flags recognised by ZSM are -L -S -X and -TX. As
- implied above, they can be handed to in groups: -LSX has the same effect
- as -L -S -X. The -T flag can be given in a group, but if this is done is
- is best made the last one, as it requires a following character.
-
- The -L flag generates a list file: in the above example it would have
- the name FILENAME.LST. List files are full of all sorts of goodies: in
- addition to the source, a fairly comprehensive copy of the object code is
- produced; ZSM also inserts page breaks in the right places, so you don't get a
- line of listing over the place where the paper tears; finally a cross
- reference page is produced at the end showing all the labels, variables and
- macros defined in the assembly.
-
- The -S flag generates a symbol table file called FILENAME.SYM, in the
- right format for use with ZSID (Digital Research's Z80 Symbolic Interactive
- Debugger). These symbols will only be correct if FILENAME.O is linked on it's
- own because, as will be seen later, linking in other files will throw some of
- the references off. Note also that since ZSID hasn't latched onto the fact
- that there is such a thing as lower case, all labels are converted to upper
- case before being written to the .SYM file. As a result, a little care and
- attention with labels will make work with ZSID a lot easier.
-
- The -X flag is used when a single source file is being assmbled
- and linked, this causes a linker built into ZSM to produce a .COM file
- directly, in addition to the .O file. This can represent a fair saving
- of time on a big file (source in the order of 32K), since ZLINK is a two
- pass linker (1st. pass sets up certain addresses and values); whereas
- the linker in ZSM only needs one pass as it already has evaluated the
- necessary addresses and values. The -X flag will be ignored if -
- A: the source contains external references (except #end - see ZLINK below),
- B: there are any errors in the source,
- C: the source produces a library.
-
- The -TX flag tells ZSM to place it's temporary files on drive X:
- usually ZSM places it's temporary files on the same drive as the source,
- by doing this, the temporary files are placed elsewhere. This sometimes
- allows assemblies to be done on otherwise almost full disks, or by putting
- the temporary files on a ramdisk, speed of assembly can be improved.
-
- As an alternative to supplying the arguments on the command line
- that invokes ZSM, it is possible to assemble several files with ZSM, start
- by giving it no arguments, then after it has signed on, it will prompt
- with a '=', and a command line typed in will be processed, after which
- ZSM will prompt again for another command line. This process will repeat
- until an empty line is given, allowing multiple assemblies without the
- overhead of loading ZSM each time.
-
- Now that FILENAME.O has been produced:
-
- A>ZLINK FILENAME.O -O OUTNAME LIB.L -S -TX
-
- is the sort of thing that will link it. FILENAME.O is a single object file,
- and always gets linked in. In the absence of a -O flag ZLINK gives the
- output .COM file the same name as the first file it encounters on the
- command line, however in the above example the output file will be called
- OUTNAME.COM, because of the -O OUTNAME present in the command line. Note
- that the name referenced by the -O flag can be a .O or .L file:
-
- A>ZLINK ARX.O -O PROGRAM.O LIB.L -S
-
- is perfectly acceptable, giving PROGRAM.COM from ARX.O & PROGRAM.O etc.
- The -TX flag works just like in ZSM - it places ZLINK's temporary files
- on drive X.
-
- LIB.L is a library: this is best considered as a list of .O
- files (or modules) all joined together, however instead of linking them all
- in, as happens with .O files in the command line, a .O module in a library
- only gets linked in if it will resolve a currently undefined label. Note also
- that the following is possible: if LIB1.L and LIB2.L both contain .O modules
- that would resolve the undefined external label "input", then the linkage:
-
- A>ZLINK PROGRAM.O LIB1.L LIB2.L
-
- would link in the module from LIB1.L to resolve "input", and leave the
- corresponding module in LIB2.L out.
-
- The -S flag has a similar effect to ZSM: it generates a symbol
- table file for ZSID, however it only contains labels defined as external
- in the assembly, internal labels will not show up. Note that the same
- restrictions apply regarding upper & lower case.
-
- ZLINK also recognises three other flags: -CXXXX, -DXXXX, -UXXXX.
- Under normal conditions, ZLINK puts all the code first, then the data
- immediately following the code, then the uninitialised data areas; and the
- addresses are set up so that the code starts at 100 hex: for a standard CP/M
- program. However by using the -C, -D and -U flags, it is possible to move
- these sections around, so to give an example:
-
- A>ZLINK PROM.O -C0 -U4000
-
- would produce a .COM file where the data followed right after the code (no -D)
- but the code started at 0 hex, not 100 hex, and the uninitialised data started
- at 4000 hex, typically this would be used to produce code to burn into a prom
- in a dedicated environment, where the prom code starts at zero, and there is
- a ram chip at address 0x4000. Alternatively:
-
- A>ZLINK BIOS.O -CF400
-
- would link up code for a CP/M bios, starting at 0xf400, with data and
- uninitialised data following right after.
-
- Note also that ZLINK creates one external label itself when linking
- code: "#end": this is defined as the address of the first byte after the end
- of the uninitialised data.
-
- Like ZSM, ZLINK can be made to prompt for its arguments, however the
- action taken by ZLINK in response to multiple line input is a little
- different. Instead of processing each line on it's own, ZLINK internally
- joins everything together and does one big linkage. This is especially useful
- when large numbers of .O and .L files are being linked, as it allows the files
- to be entered in groups. Note that several files can be given in response
- to one '=' prompt. While doing the linkage, in regards to order of files,
- the files are scanned from left to right on a given line, and first line
- first. One important thing to note in both ZSM and ZLINK: termination of
- input occurs when a line containing no arguments is given, in particular
- a single space is considered as no arguments, the practical upshot of which
- is that exit from ZSM and ZLINK under SUBMIT and XSUB can be achieved
- gracefully (c.f. PIP).
-
- ZSM itself (as will be noted) does not complain about undefined
- labels, it just notes them and passes them right along to ZLINK, however if
- ZLINK cannot resolve a reference, then it will complain, in addition it will
- complain if a label is defined more than once.
-
-
- Libraries.
-
- ZLIB, the librarian is invokes as follows:
-
- A>ZLIB LIBRARY.L
-
- and as in ZSM, since the .L is mandatory on the file being processed, it is
- optional on the command line. If LIBRARY.L does not exist, it is created, and
- if it does, then it is saved in LIBRARY.LBK to provide a backup. Once ZLIB has
- signed on, it will prompt for each command, once a command is given, ZLIB will
- prompt further for the other arguments necessary.
-
- Commands available to ZLIB are:
-
- 1. L(ist) - Print a list of all .O modules currently in the LIBRARY file.
- .O modules are tagged, depending on what action is to be taken: 'k'
- means the file will be killed, '>' means it will be output to a .O
- disk file, '<' means it has been input from a disk .O file, '<FILE.L'
- means it has been copied over from another library. Finally, if you
- append another library file, the name of the second .L file shows up
- surrounded by '--'s, see the example below
-
- 1: MODULE1.O ; Left alone - gets copied over
- 2: MODULE2.O k ; killed: will be removed from .L file
- 3: MODULE3.O > ; output: will create MODULE.O on disk
- 4: MODULE4.O k> ; extract: does both of the above
- 5: MODULE5.O < ; input disk file MODULE5.O to library
- 6: MODULE6.O <FILE1.L ; search MODULE6.O in from FILE1.L
- 7: -- FILE2.L -- ; append library file FILE2.L
- 8: MODULE7.O ; left alone
- 9: [end]
-
- 2. K(ill) - asks for a module: you can specify it by name (MODULE2
- in the above example, or by number (i.e. place in the library file)
- when all the work is finished, this module will be removed from the
- library file.
-
- 3. O(utput) - asks for a module as in kill, when all work is finished
- a .O file is created on disk containing the appropriate module.
-
- 4. E(xtract) - asks for a module, then does both a kill and an output to
- it.
-
- 5. I(nput) - asks first where the new module is to be input, note that
- the new module will be placed immediately before the one given, in
- the above example, if the input command (working on MODULE5.O) is the
- last command given, then MODULE5.O would be input immediately before
- MODULE6.O. In this case it is permissible to specify [end] as a
- module, which would add the new module right on the end of the
- library. Once the position has been determined, ZLIB asks for the
- name of the .O file to be input.
-
- 6. S(earch) - this command behaves in a similar manner to input: however
- instead of asking for a .O file on disk, it asks for a .L file, and
- when one is given, it is listed, and a module from the .L file is
- chosen: it will be placed in the output .L file at the point chosen.
-
- 7. A(ppend) - asks for the name of a library file on disk, and simply
- appends the given file to the end of the current work file.
-
- 8. D(one) - Commands which have an effect (2 - 7) are not implemented
- as they are typed, instead a note is made to execute each command,
- and when the done command is given, all the commands are executed.
- Note that the file being processed gets backed up in a .LBK file, in
- case you want to keep your original.
-
- 9. Q(uit) - leaves ZLIB without doing any of the changes specified.
-
- As implied above, all of the commands are recognised by their initial
- letter, so kill, k, krunch all work equally well.
-
-
- Patching.
-
- ZPATCH.COM is a small program designed for doing "Hot Patches" to
- .COM files that already exist without needing to mess around with ZSID and
- SAVE.
-
- A>ZPATCH PROGRAM.COM PATCHES.O
-
- is a typical command line invoking ZPATCH. PROGRAM.COM is the file being
- patched, and PATCHES.O is the patch file - like ZLIB, since there is no
- ambiguity of file extensions they are optional on the command line: if not
- present then they will be added by ZPATCH.
- PATCHES.O would be created by assembling a .Z source file with ZSM,
- and there are several limitations imposed on the source: first there can be
- no .dseg or .useg code or references (see section on directives for meaning
- of .dseg & .useg); also there can be no external references.
- The behavior of ZPATCH depends on what it has just encountered in
- the .O file: the only two significant items are .org directives (including
- ds opcodes) and "real" code (i.e. instructions or db / dw opcodes). If
- ZPATCH finds a .org directive (or a ds opcode), then it will start copying
- bytes over without modification, however when it encounters code or data
- in the .O file it replaces the bytes in the old version of the file with
- the bytes specified in the .O file.
- To give an example, consider the following .Z source file:
-
- .org 0x0100
- start: jp patch
- .org 0x0862
- entry:
- .org 0x2000
- patch: ld de,string
- ld c,9
- call 5
- ld hl,entry
- ld (start + 1),hl
- jp start
- .org 0x2860
- string: db 'Signon message\r\n$'
-
- The first line sets the label start: at 100 hex, which is the start of a
- CP/M program. The second line is a jump that will replace the original
- jump so that the code at patch: gets executed on startup. The third and
- fourth lines set the label entry: to 862 hex which was the original entry
- point of the program. The fifth line sets 2000 hex as being the address
- where part of the patch will go - this simply prints a signon message
- resets the jump at the start of the program and starts again at 100 hex.
- The final .org might be there because there isn't enough room at 2000 hex
- to include the signon string, so another patch area has to be used: 2860
- hex in this case.
-
- If the .O file finishes it's work before the end of the .COM file
- then the only changes will be the inclusion of the patches, however if the
- .org's in the .O file extend beyond the end of the .COM file then the
- intervening spaces will be filled with zero bytes.
-
- When ZPATCH has finished it's work, it will have created a new .COM
- file, however it leaves the original in a .CBK file to provide a backup.
-
-
- Doing it all at once:
-
- ZC is based loosely on UNIX CC: the C compiler, with some MAKE
- thrown in (make is a program that does the minimum amount of work needed
- to bring a multi source executable up to date when you edit one or more
- of the sources). In particular, on the same disk as ZC.COM you should have
- ZSM.COM, ZLINK.COM, ARX.O and friends (see ARX.DOC), and LIB.L. A typical
- usage would be:
-
- A>ZC B:FILE.Z
-
- which would firstly invoke ZSM to assemble B:FILE.Z to B:FILE.O, and then
- invoke ZLINK to link ARX.O, B:FILE.O, and LIB.L together to give B:FILE.COM.
- By specifying several sources on the command line, ZC can be made to glue
- them all together into one:
-
- A>ZC B:FILE1.Z B:FILE2.Z
-
- would assemble the two sources, and then link them with ARX.O and LIB.L.
-
- As well as handling .Z files, ZC knows about .O files and .L
- libraries, so:
-
- A>ZC B:FILE3.Z C:FILE4.O C:LIBRARY.L
-
- is fair game: it would assemble B:FILE3.Z to B:FILE3.O, and then link
- everything together.
-
- ZC has a whole host of options:
-
- -S: generate a .SYM symbol table file - this is just passed along to ZLINK.
-
- -X: alter which ARX.O header is used: by saying -XSTR, STRARX.O is used
- instead of the regular ARX.O (for a list of the ARX.O files available
- and what they do see ARX.DOC). As a special case, just saying -X
- with no following string causes no ARX.O module to be used at all.
- When a string is provided, ARX.O is added to the end of it, and the
- resulting filename is used, so -XB: would use B:ARX.O, and -XC:Q
- would use C:QARX.O etc.
-
- -L: add extra libraries, or disable LIB.L. This works much like -X, except
- that these are additive: so -LB:X would include B:XLIB.L as well
- as LIB.L. Note that this option is position sensitive, in effect
- -LX is a shorthand that gets expanded to XLIB.L, in the same place
- as the -LX was in the command line. Again -L is a special case, it
- causes LIB.L not to be included, but any other libraries selected
- with other -L options still remain.
-
- Note that in normal usage, the selected ARX.O file always is the
- first thing to be linked, and LIB.L always follows all other files
- and libraries.
-
- -TX: move temporary files around - this is simply passed straight along to
- ZSM and ZLINK, and acts as explained above.
-
- -PX: look elsewhere for programs and ZLINK files: normally ZC looks on the
- current drive for programs (ZSM & ZLINK) and ZLINK files (ARX.O etc.
- & LIB.L etc.). This option tells it to look on drive X instead - so
- if B: were the current drive:
-
- B>A:ZC XYZ.Z -PA
-
- would cause ZSM etc. to be pulled from A: as opposed to the default
- drive B:
-
- -O: behaves just like the -O flag in ZLINK - it alters the name of the output
- .COM executable. As in ZLINK, the -O can be followed by a plain
- FILENAME, in which case the name is used, or it can be placed in
- front of a .Z, .O or .L file, in which case the name is transferred
- to the output file, as well as using the specified file for the
- assembly / linkage.
-
- -B: in a case such as:
-
- A>ZC FILE1.Z FILE2.Z FILE3.Z -B
-
- the -B causes the .Z files to assembled only if corresponding .BAK
- files exist. This is the 'Make' portion of ZC: by using this
- command option, only those files that need assembly have ZSM invoked
- for them. As an addition, -BE has the same effect, but in addition
- to doing the assembly, if the assembly succedes, the .BAK file is
- erased.
-
- -A: when ZC is invoked, it usually links the output .O files together. This
- causes the ZLINK phase to be bypassed, stopping with production
- of the .O files only. This is most useful for assembling a collection
- of .Z files, without linking them:
-
- A>ZC B:FILE1.Z B:FILE2.Z B:FILE3.Z -A
-
- just assembles the three .Z files and stops.
-
- -CXXXX, -DXXXX, -UXXXXX: these options are simply passed straight through
- to ZLINK, where they have the effects noted above.
-
-
- Features.
-
- ZSM recognises standard ZILOG neumonics, along the lines of
-
- ld a,(hl)
-
- or
-
- inc (ix+0x76)
-
- etc. etc. - these are not covered here as there are many good text books
- covering writing assembly language on the Z80. Comments start with a ';'
- and continue to the end of the line, to define a label, put the label name
- at the start of the line and follow it with a ':'. A typical line of code
- might then be:
-
- setup: add a,17 ; add the offset to a
-
- Line length is limited to 100 characters - anything else is simply truncated,
- the only time this is likely to cause an assembly error is if a long string
- is given to a 'db' statement.
-
- Case is not significant in opcodes, reserved operands or directives, so
-
- ld a,(hl)
- LD A,(HL)
- Ld a,(hL)
-
- are all legal and all produce the same thing.
-
- Targets of jp and call opcodes are covered later, but in the case of jr and
- djnz opcodes, the target can be one of three things:
-
- 1. jr label
-
- simply jump to the specified label;
-
- 2. jr label + expression
-
- jump to expression bytes offset from label: to give an example
-
- jr input + 3
-
- .......
-
- input: ld hl,buffer
- call getdata
-
- in this case, the jr would jump to the call, bypassing the ld hl instruction;
-
- 3. jr expression
-
- jump the specified number of bytes, for example
-
- dec a
- jr nz,-3
-
- would implement a timing loop. In addition the '@' term is allowed in jr
- targets (see expressions) so the above loop could also be implemented as
-
- dec a
- jr nz,@ - 1
-
-
- db: define a list of bytes, note that strings enclosed in quotes are
- legal, and as in C, the backslash is used as an escape character:
- to give an example:
-
- string: db 'Can\'t find file'
-
- by preceding the quote in the string with a backslash, it becomes a
- character in the string rather than a string delimiter. There are a
- total of 9 cases where the backslash has a significant effect:
-
- \r generates a carriage return (0x0d)
- \n generates a linefeed (0x0a)
- \b generates a backspace (0x08)
- \t generates a tab (0x09)
- \f generates a formfeed (0x0c)
- \e generates an escape (0x1b)
- \\ generates a backslash (0x5c)
- \' generates a single quote (0x27)
- \OOO generates the octal character OOO
-
- in this last case OOO can be at most 3 octal digits, to give a few
- examples: '\033' generates an escape, as does '\33', '\0' generates
- a null, '\177' generates a delete char. To briefly explain, when
- ZSM finds a backslash followed by an octal digit ('0' to '7') it
- will continue scanning until either it finds a character which is
- not a legal octal digit, or it has scanned three characters: so
- '\0034' will generate 0x03 0x34, the \003 gives the 0x03, and the
- 4 gives the 0x34. Note that a single backslash preceding any other
- character is ignored:
-
- 'stringX'
-
- and
-
- 'string\X'
-
- generate exactly the same thing. Typical use of the \r type sequences
- might be in a case such as
-
- db 'Data error:\r\nTry again please\r\n'
-
- which is somewhat easier than
-
- db 'Data error:',0xd,0xa,'Try again please',0xd,0xa
-
- although both would generate the same thing. Alternatively, to ring
- the bell on a video screen a string such as
-
- db 'ERROR\007'
-
- or
-
- db 'ERROR\7'
-
- could be used. As is shown above, multiple strings can be given, they
- are simply concatenated and output in the order given. Note also that
- expressions are legal, so
-
- db 'This "', 'c' & 0x1f, '" is a control C'
-
- would be perfectly legal, generating a control C in the middle of the
- text (even though ' ..."\003"... ' would do the same thing)
-
- dw: generates words of data, arranged in the right order (low byte first)
-
- dw 0x1234, label
- dw label - 0x1000
-
- unlike db's, dw "operands" can be relocatable, so a jump table might
- be implemented as follows:
-
- dw l1,l2
- dw l3,l4
- dw 0
-
- with the zero word flagging the end of the table. Note also that while
- up to 100 bytes can be generated with just one db statement, the limit
- is 2 words (4 bytes) with one dw statement - the table above could not
- be implemented as:
-
- dw l1,l2,l3,l4,0
-
- ds: generate a space of the given size:
-
- ds 0x1000
-
- if given in the .cseg or .dseg sections of a program, then the space
- is guaranteed to be zero filled, if given in the .useg section, then
- the contents will be garbage at the start of program execution (see
- section on directives for an explanation of .cseg, .dseg, .useg)
-
- Finally, ZSM does not need a .end directive to make it stop (indeed there is
- no provision for recognising such a thing) - it simply keeps on going till it
- falls off the end of the source file.
-
-
- Identifiers.
-
- An identifier is a collection of seven or fewer characters, given that
- the first must be a letter (ZSM considers the underscore and hash characters
- '_' and '#' as letters), and the remaining six must be letters or numbers. ZSM
- is case sensitive regarding identifiers, but all characters following the
- seventh are ignored, so
-
- Foo:
- foo:
-
- are different labels, whereas
-
- long_label
- long_label1
-
- are not. Opcodes, reserved operands & directives cannot be used as
- identifiers: you cannot have a variable called 'hl' etc. etc.
-
-
- Expressions.
-
- ZSM recognises two types of expression: absolute or relocatable.
- An absolute expression is one composed of variables and constants, i.e. one
- that can be evaluated fully by the assembler during pass 1 - these can be
- used anywhere. In addition, if an opcode has a word operand such as
-
- call address
- ld hl,(address)
- dw address1, address2
-
- then the address can be considered as a relocatable expression, which is
- simply a label, followed by an optional absolute expression: for example
-
- call setup
- ld hl,(table + 0x0100)
- dw swtab - 2, 0x1234
-
- In the first of the above examples 'setup' is a label, in addition to using
- a label, the term '@' refers to the start of the current instruction: so
-
- jp p,@ + 6
- ld hl,.....
-
- will only do the 'ld hl' if the 'm' flag is set. In absolute expressions,
- there are seven levels of operator precedence:
-
- 1. || &&: logical or / logical and. x && y is true (1) iff
- both x and y are true (non-zero), x || y is true iff
- either x or y or both are non-zero.
-
- 2. == != >= <= > <: relational operators: in order shown
- equal, not equal, greater than or equal, less than or equal
- greater than, less than. Note that expressions are unsigned,
- so -1 < 0 is false as -1 is considered to be 65535
-
- 3. >> <<: right shift, left shift: 1 << 3 is 8, 0x8000 >> 15 is
- 1, and not 0xffff: right shift is zero fill
-
- 4. & | ^: bitwise and, bitwise or, bitwise exclusive or.
- Note that 1 & 2 is zero, whereas 1 && 2 is 1
-
- 5. + -: binary addition and subtraction
-
- 6. * / %: binary multiply, divide, modulus. Note that division by
- zero does not generate an error: it just returns zero, and
- the % operator gives remainder on division: so 10 % 3 is 1,
- again anything % 0 gives zero, without an error
-
- 7. ! - + ~ [] {}: unary logical not, unary minus, unary plus,
- unary bitwise not, brackets to force order of evaluation,
- braces to evaluate a relocatable difference.
-
- ! 0 is 1
- ! 1 == ! 76 == 0 as is ![any non-zero value]
- ~ 0 == 0xffff
- ~ 0xc000 == 0x3fff
-
- Square brackets are used to force order of evaluation as they
- solve problems in potentially ambiguous cases such as
-
- ld hl,('0' << 8) + ' '
-
- In an expression, a term with the form
-
- {label1 - label2}
-
- will be evaluated as the difference between label1 and label,
- typically it can be used to determine the size of a table, or
- the length of a section of code. Certain restrictions apply to
- the use of such terms: they can be used in both relocatable
- and absolute expressions:
-
- ld bc,{endtbl - table} ; get size of table to bc
-
- in this case the only limitation on endtbl and table is that
- they be defined in the current source code file, and that they
- be in the same segment. However in a case such as
-
- .var ident {label - base}
-
- or
-
- ds {end - start}
-
- these are absolute expressions, and as such they must be
- evaluated immediately on being encountered, hence the labels
- they contain must already have been defined otherwise an
- error will result. This is to prevent paradoxes such as this
- ocurring
-
- table:
-
- ......
-
-
- ds {endtbl - table}
-
- .......
-
- endtbl:
-
- Note also that '@' can be used as a legal "label" in { }
- terms, so code such as
-
- label:
-
- .........
-
-
- .var ident {@ - label} * 2
-
- or
-
- ld bc,{foo - @}
-
- are both legal.
-
- Constants are assumed in base 10, unless there is a leading 0X / 0x
- for hexadecimal (both 'A' - 'F' and 'a' - 'f' are allowed), 0 for
- octal, or 0B / 0b for binary, in addition a single character enclosed in
- quotes is considered a legal constant by the expression parser, so
-
- db 0x4D ; hexadecimal
- db 77 ; decimal
- db 0113 ; octal
- db 0b1001011 ; binary
- db '\113' ; octal character
- db 'M' ; ascii character
-
- all produce the same thing
-
-
- Directives
-
- There are 14 directives: they are introduced by starting a line
- with a period:
-
- 1. .cseg, .dseg, .useg: define code, data or uninitialised data segments.
- These are the segment directives that are used when generating
- standard CP/M .COM files: .cseg is aimed to hold all the executable
- code, .dseg holds initialised data, and .useg holds uninitialised
- data. These can be freely intermixed in the source file: by the
- time ZLINK has finished all the .cseg code will be contiguous in
- the .COM file, followed by the .dseg data. After the .dseg data
- is finished, .useg space begins. Two things to note: ZSM starts
- assuming .cseg; and .useg space can only contain label definitions,
- ds opcodes, and .org directives (q.v.) .useg is best used for
- allocating space for large tables that are to be filled in at run
- time. To give a couple of examples:
-
- .cseg
- ld de,string
- .dseg
- string: db 'Hello World!\r\n$'
- .cseg
- ld c,9
- call 5
- jp 0
-
- will print 'Hello World!' because the string is pulled out of the
- middle of the code; similarly
-
- .cseg
- ld hl,table
- .useg
- table: ds 0x0100
- .cseg
- ld de,table+1
- ld bc,0x00ff
- ld (hl),0xff
- ldir
-
- will fill a table with 256 bytes all -1, further the table will
- not occupy any space in the .COM file, .useg can only be used to
- create labels for reference purposes: before the ldir is executed
- the table will be full of junk.
-
- 2. .org: origin, which allows holes to be left in code, which will be
- zero filled in .cseg & .dseg, junk filled in .useg. Note that
- .org's refer to the base of the current segment, and .org's
- only move forward, so
-
- .org 0x4000
-
- followed by
-
- .org 0x3000
-
- will create a hole of 60K in the output file. In the absence of any
- .orgs, ZLINK puts the .COM file together to run at 0x0100 so it will
- work right under CP/M. The main use for these is putting code in the
- right place with ZPATCH, because results of using this directive in
- multi-source files is not particularly useful, and moving things
- around with ZLINK is far easier with the -C, -D and -U flags.
-
- 3. .extern: define a label as external:
-
- .extern label
-
- By default all labels are defined internal, unless a .extern is used,
- however when used, if a label is not defined in the current file, it
- is automatically assumed to be defined externally in another module
- which will be linked in by ZLINK. The exception to this is jr targets:
- these must (a) be defined in the current file; and (b) exist in the
- same segment. As a result of all of this, ZSM will never complain
- about undefined labels, it just notes them and leaves it for ZLINK to
- sort it all out (in much the same way as a C compiler handles
- procedure definition and usage).
-
- 4. .incl: include a .I file:
-
- .incl "file"
-
- causes FILE.I to be included: these are most useful to hold macro
- definitions and variable declarations (qq. v.), see STDHDR.I and
- BDOS.I for typical examples.
-
- 5. .macro, .endm: macro definition:
-
- .macro load r1,r2,offset
- ld r2,(ix+offset)
- ld r1,(ix+[offset]+1)
- .endm
-
- is a typical macro definition: in usage a line of the type:
-
- load h,l,10
-
- generates the following:
-
- ld l,(ix+10)
- ld h,(ix+11)
-
- As regards macro arguments, when the macro is defined, they must
- be legal identifiers, however when the macro is used they can be
- any eleven characters except ',' and ';' as these two are reserved
- for delimiting. A macro may have any number of arguments up to
- eight, if a macro is invoked with too many arguments, then the
- extra ones are ignored, and if there are too few arguments, then
- the undefined ones are left blank. Macro usages can nest up to a
- maximum depth of five, and recursive macros are only detected by
- the excessive nesting depth.
-
- 6. .var: set a variable:
-
- .var variable expression
-
- the above line defines variable if it doesn't already exist, and
- assigns it the value of the expression. To give a real life example:
-
- .var bdos 5
-
- allows a line of the type
-
- call bdos
-
- to get into CP/M. There can be no duplication of names, i.e. no two
- of:
-
- foo:
- .var foo ....
- .macro foo
-
- can appear in the same .Z file, however the line
-
- .var foo expression
-
- can be included many times, each occurence changing the value of foo.
-
- 7. .lib: direct library production - to give an example:
-
- .lib "strcpy" ; generating STRCPY.O in the output .L file
- .extern _strcpy ; _strcpy is the only external label
- _strcpy: ; here it is - note that it could be anywhere
- call #arg2 ; from here to the next .lib
- l1: ld a,(de) ; and the code ....
-
- etc. etc.
-
- is the start of a typical library module source: in the above example
- ZSM will produce a .L file directly, and the code segment given
- would behave just as if ZLIB had been used to insert a file STRCPY.O.
- Note that ALL .externs in a library source must come immediately
- after a .lib, and that .lib automatically does a .cseg. .lib has to
- must be the first thing in the file (with the exception of .macro's
- and .var's) so that ZSM latches onto the notion of producing a .L
- file before it actually does anything.
-
- 8. .if, .else, .elif, .endif: conditional assembly. These directives allow
- assembly of different sections of code depending on the value of
- expressions:
-
- .if test1
-
- code1 ; assembled iff test1 is true
-
- .elif test2
-
- code2 ; assembled iff test1 false and test2 true
-
- .else
-
- code3 ; assembled iff both test1 and test2 false
-
- .endif
-
- To explain more fully, .if starts a section of conditional code,
- .else (optional) "reverses" the test, only code on one side of the
- .else is used, and .endif closes the .if down. .elif has exactly
- the same result as
-
- .else
- .if test2
-
- except that using .elif saves a level of nesting. Only one .elif is
- shown above, they can be chained together as many times as are needed
- following an initial .if. As with macro usage, .if's nest, up to a
- maximum depth of five.
-
-
- Errors
-
- There are 16 error codes: when an error occurs, ZSM prints the
- offending line, including (among other things) a letter code in the thirty
- third character explaining what went wrong:
-
- a bad arguments in macro invocation
- c constant error: illegal digit in constant (e.g. 059 or 0b011020)
- d directive error: e.g. misplaced .lib's, .endm's, etc., or bad syntax
- e expression error: something wrong with expression syntax
- f .incl file not found
- g segment error: typically code in .useg
- i .if error: misplaced .else, .elif, .endif
- l jr length error or jr to undefined label
- m multiply defined label / macro
- n macro's / if's nested too deep
- o opcode error: unknown opcode
- p error with formal parameters in macro definition
- q missing trailing ' in db string
- s syntax error: something wrong with the operands
- u undefined variable in expression
- v value error e.g. rst 77 or im 10
-
- Only the first error on a line will be reported, for example in the case of
- a multiply defined label AND a syntax error, only the 'm' error will get
- reported.
-
- In addition ZSM will exit if there is a symbol table overflow, or
- macro / symbol definitions run it out of memory, but as there are some
- 1000 symbol table slots, it requires typically in excess of 64K of source
- to approach these kinds of limits.