SB-Projects On Line

Navigation

Home

SB-Assembler
News
Download
Installing
Quick Start
Source Files
Running SBASM
Expressions
Labels
Directives
Macros
Error Messages
Howto?
History
Known Bugs
DIY Cross Overlays

Cross Overlays

Control

.CP .CR .TF
.TW .EQ .SE
.BI .CH .IN
.OR .BS .NO
.PH .EP .SM
.DU .ED  

Data

.AS .AT .AZ
.DA .DL .DR
.DB .DW .HS
.RF .TS  

Conditional

.DO .EL .FI
.MA .EM .XM

List

.LI .CO .EC
.EF .LF .SF
.EB .EN .ST
.PG .LM .TI
.EJ .ER  

Alphabetical

.AS .AT .AZ
.BI .BS .CH
.CO .CP .CR
.DA .DB .DL
.DO .DR .DU
.DW .EB .EC
.ED .EF .EJ
.EL .EM .EN
.EP .EQ .ER
.FI .HS .IN
.LF .LI .LM
.MA .NO .OR
.PG .PH .RF
.SE .SF .SM
.ST .TA .TF
.TI .TS .TW
.XM    





Directives

A directive is a command to the assembler and thus it is not an instruction for the target microprocessor. Directives are often called pseudo instructions because they appear in the instruction field of the source line. Directives are always placed in the instruction field on program lines and may be followed by one or more operands.
The SB-Assembler uses a special notation for directives. All directives start with a dot, followed by 2 characters. This means that existing code must be changed to represent the SB-Assembler convention when it comes to directives. However this can easily be done with the replace command found in many text editors.

SB-Assembler directives always begin with a dot which is followed by two or more characters. This makes it easier to distinguish directives from mnemonics and avoids name clashes with future mnemonics on new Crosses.
All directives consist of 2 characters, which are usually an abbreviation or acronym of the full directive's name. The SB-Assembler only checks the first 2 characters following the dot to see if it is a legal directive. All other characters following the first 2 are ignored until the next space, TAB or EOL.
Most directives are common to all Cross Overlays. But each Cross Overlay can have its own set of additional directives, e.g. the 6809 Cross knows its own unique .DP directive which sets the Direct Page.
Some Cross Overlays may also change the behaviour of some of the standard directives to suit the needs or peculiarities of the serviced processor type. Some directives may even be disabled by Cross Overlays if their use may couse problems for that particular Cross Overlay.
In any case such Cross specific directives only exist as long as the Cross Overlay is loaded into memory.

Some directives must or may be followed by one or more parameters. Those parameters may not contain space or TAB characters because that will signal the end of the parameter. Only literal strings may contain spaces as long as they are properly enclosed in delimiters.
Parameters must be separated from each other by a comma. The SB-Assembler stops interpreting parameters as soon as it finds a space, TAB or EOL character.
Only version 3 of the SB-Assembler allows the use of one optional space directly following a comma to improve readability.

Document Conventions

I use some common document conventions in the following description of the directives.
Optional parameters that may follow the directives are enclosed in square brackets [ ]. For example [-]string means that the - sign is an optional part of the parameter.

Text printed in Italic font should not be typed literally but indicates the type of the expected parameter. For example filename should be replaced by the real file name, possibly including drive and path. In Version 2 of the SB-Assembler file names and paths are restricted to the normal MS-DOS 8.3 file names. For Version 3 of the SB-Assembler file and path names must follow the rules of your operating system.
Directives which use file names sometimes assume a default extension suitable for the function. For example the .IN directive assumes the extension to be .asm if it is omitted. This doesn't mean that you are not able to use other extensions. If the extension you want to use differs from the default extension it must be given explicitly.
Please note that file and path names are case sensitive on Unix like operating systems. This also applies to the default file extensions, which are always lower case. This only applies to Version 3 of the SB-Assembler, because other versions don't run on Unix like operating systems.
With Version 2 of the SB-Assembler some directives also allow you to use device names in stead of file names like LPT1: COM1: or PRT:. Device names must always end in a colon.

Sometimes you can use one of several options. These options are separated by a pipe ¦ symbol in this document. For example on¦off means you may either use on or off. Notice that on and off are not printed in Italic, so they should be typed literally.

Strings should be delimited. This means that a legal delimiting character must be used to enclose the string. All characters in between the two delimiters are treated literally, spaces and upper and lower case are retained.
Almost any character may be used as delimiter. Only the characters dash - , a comma , , a dot . , a colon : and the character A to Z are not allowed to be used as delimiter. Often used delimiters are " ' / \ ! ¦ .
The delimiter itself may not be used inside the string because that would end the string literal. The full standard ASCII character set with values between $32 and $126 can be used as string characters. Characters from the extended IBM character set are not allowed in strings and can have unpredictable results.

Expressions can be composed of constant values in any of the available radixes, labels and expressions. These expressions always result in a 32 bit value. The directive decides how many of the 32 bits are actually used.

Boundary Sync

Version 3 of the SB-Assembler is better prepared for processors which use multi byte instructions. The problem with multi byte instructions is that the target byte pointer will grow faster than the instruction pointer. For normal program instructions this is not really a problem because each instruction will generate the same amount of bytes.
However when we start using directives to generate data bytes this may become a problem because we may generate single bytes, or an odd number of bytes, leaving the instruction pointer somewhere in the middle of one instruction. Therefore each instruction generated will automatically be forced to start at the next instruction boundary, even when we previously generated an odd number of data bytes. No problem so far.
But what if we want to write a block of text lines to memory for instance? If we allow each directive to automatically sync the program pointer to the next instruction boundary, we might end up with unwanted fill bytes in our text block. These fill bytes have the value $00, which might be mistaken for the end of string marker by your program.
Therefore most data generating directives will NOT perform an automatic boundary sync. Some directives however will perform a boundary sync, simply for logical reasons. For instance the .OR directive will always start the instruction pointer on an instruction boundary. Not doing so would make not much sense.
A special directive .EV is provided for you in case you want to force the assembler to do a boundary sync. You may want to do that for instance to align the next data block with the instruction pointer, to allow proper label assignment. Please note that you can't assign a label to a fractional part of the instruction pointer with multi byte processor types like the AVR and PIC series.

A boundary sync, when executed by the directive, is always executed before the actual function of the directive kicks in. With the description of each directive I will metion whether it performs a boundary sync or not.

In version 2 of the SB-Assembler there was no such thing as a boundary sync. This caused many problems when using multi-byte processors. Therefore I have redesigned the behaviour of the SB-Assembler in version 3.

.AS    Ascii String

Syntax:

        .AS  [-]string¦#expression[,string¦#expression[,...]]

See also: .AT .AZ .DA .DB .DL .DR .DW .HS .RF .TS

Function:

The .AS directive converts ASCII strings and/or expressions to hexadecimal bytes.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

The string parameter is a delimited string. The expression should evaluate to a positive number that is less than 256. The parameter can consist of more than one string or expression, which all should be separated from each other by commas.
All generated bytes will have bit b7=0 if the first character of the parameter is not a - sign, this is called positive ASCII. If the first character of the parameter is a - sign all generated bytes will have b7=1, this is called negative ASCII.
The delimiters may not enclose an empty string. They should enclose at least one character.

Examples:

0000-54 65 73 74           .AS  /Test/
0004-D4 E5 F3 F4           .AS  -/Test/
0008-0D 54 65 73
000C-74 0A 0D              .AS  #$0D,/Test/,#$0A,#$0D
000F-8D D4 E5 F3
0013-F4 8A 8D              .AS  -#$0D,/Test/,#$0A,#$0D
0016-54 65 73 74
001A-0D 54 65 73
001E-74                    .AS  /Test/,#$0D,\Test\

.AT    Ascii string Terminated

Syntax:

        .AT  [-]string¦#expression[,string¦#expression[,...]]

See also: .AS .AZ .DA .DB .DL .DR .DW .HS .RF .TS

Function:

The .AT directive converts ASCII strings and/or expressions to hexadecimal bytes. The last generated byte will have an inverted bit b7 to signal the end of the string. This can be used to signal the end of a character processing loop. Apart from this minor difference the .AT directive works exactly the same as the .AS directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

The string parameter is a delimited string. The expression should evaluate to a positive number that is less than 256. The parameter can consist of more than one string or expression, which all should be separated from each other by commas.
All generated bytes except the last one will have bit b7=0 if the first character of the parameter is not a - sign, this is called positive ASCII. If the first character of the parameter is a - sign all generated bytes will have b7=1 except the last one, this is called negative ASCII.
The delimiters may not enclose an empty string. They should enclose at least one character.

Examples:

0000-54 65 73 F4           .AT  /Test/
0004-D4 E5 F3 74           .AT  -/Test/
0008-0D 54 65 73
000C-74 0A 8D              .AT  #$0D,/Test/,#$0A,#$0D
000F-8D D4 E5 F3
0013-F4 8A 0D              .AT  -#$0D,/Test/,#$0A,#$0D
0016-54 65 73 74
001A-0D 54 65 73
001E-F4                    .AT  /Test/,#$0D,\Test\

.AZ    Ascii string terminated by Zero

Syntax:

        .AZ  [-]string¦#expression[,string¦#expression[,...]]

See also: .AS .AT .DA .DB .DL .DR .DW .HS .RF .TS

Function:

The .AZ directive converts ASCII strings and/or expressions to hexadecimal bytes. The last generated byte will be followed by a byte with the value of $00 to signal the end of the string. This can be used to signal the end of a character processing loop. Apart from this minor difference the .AZ directive works exactly the same as the .AS directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

The string parameter is a delimited string. The expression should evaluate to a positive number that is less than 256. The parameter can consist of more than one string or expression, which all should be separated from each other by commas.
All generated bytes will have bit b7=0 if the first character of the parameter is not a - sign, this is called positive ASCII. If the first character of the parameter is a - sign all generated bytes will have b7=1 except the trailing $00 byte, this is called negative ASCII.
The delimiters may not enclose an empty string. They should enclose at least one character.

Examples:

0000-54 65 73 74
0004-00                    .AZ  /Test/
0005-D4 E5 F3 F4
000A-00                    .AZ  -/Test/
000B-0D 54 65 73
000F-74 0A 0D 00           .AZ  #$0D,/Test/,#$0A,#$0D
0013-8D D4 E5 F3
0017-F4 8A 8D 00           .AZ  -#$0D,/Test/,#$0A,#$0D
001B-54 65 73 74
001F-0D 54 65 73
0023-74 00                 .AZ  /Test/,#$0D,\Test\

.BI    Binary Include

Syntax:

        .BI  filename.ext[,format]

See also: .CH .IN

Function:

The .BI directive copies the contents of a binary file to the current target file from the current location. This enables you to include for example sampled speech, HTML pages, or images in your programs.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

The filename may contain a path name, and a drive letter for Microsoft based operating systems. If no path is given the current directory should hold the file to be included. No default extension is assumed, so if the file has an extension it should be included in the filename.

Binary include files can not be nested. Binary include files can't open other include files by themselves, but it is also not allowed to include a binary file from within a normal include file.
Version 3 of the SB-Assembler doesn't have this restriction. There you may use the .BI directive from within an included source file.

If no format is specified the binary include file will be treated as a plain binary file. All bytes are copied as they appear in the file. No attempt is made by the SB-Assembler to figure out in what format the file originally was written!

The format parameter can have any of the following names:

  BINUnformatted binary file (default)
  E52Elektor's EMON52 format
  FPCFour Packed Code formatted file
  HEXUnformatted HEX file
  INTIntelHex formatted file
  MOTMotorola S19, S28 or S37 formatted file
  SIGSignetics formatted file
  TEKTektronix formatted file

For Version 2 of the SB-Assemlber only the first character of the format name is sufficient to select a particular file format. All other characters on the program line following that character will be ignored and treated as comments.
For Version 3 of the SB-Assembler the formats should be given as shown in the table above.

Please Note for Version 2: That the Motorola format is called MOT here, and not S19, S28 or S37 like it is with the .TF directive. Using S19, S28 or S37 as parameter will result in a *** Binary format error messages if you feed a Motorola formatted file because the SB-Assembler is expecting a Signetics formatted file (which starts with an S).

Address fields of all formatted file formats are ignored. Segment records in Intel HEX files only carry address information and will be ignored too. All data bytes are copied in the order of appearance in the binary include file.
The address field of the FPC formatted files is optional and is also ignored if it is given.

Formatted files don't have to be terminated with the end of file record. No error is given if the end of file record is missing.

Formatted files may contain remark lines. An empty line or a line beginning with ! ; * " or ' will be treated as a remark line.
Records in a formatted file may not contain any spaces. Leading and trailing spaces are ignored though. The only exception to this rule is the EMON52 format where bytes are separated by spaces by default.
The binary include file will be terminated immediately if any error (error in the expected format or disk error) is encountered.

If a label is present in the label field of the source line containing the .BI directive it will be assigned the address of the first byte of the binary include file.

A program line that contains a .BI directive can be listed if the list option is switched on. The generated bytes are never listed though.

Examples:

0000-            BITMAP   .BI  SAMPLE,INT

.BS    Block Skip

Syntax:

        .BS  expression1[,expression2]

See also: .DU .ED .EP .NO .OR .PH .RF .SM

Function:

With .BS you can skip a block of memory. The number of bytes to be skipped is determined by expression1. The skipped bytes can be filled with the 8 bits value of expression2.
The .BS directive is often used in combination with the .DU and .ED directives to define RAM variables. Version 3 of the SB-Assembler can use the .SM directive in combination with the .BS directive to define RAM addresses more effectively.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

Expression1 may not contain forward referenced labels, otherwise a fatal "Undefined label error" will be reported.

The value of expression1 can range from 0 to $FFFFFFFF, although it is not very likely that you're going to use the maximum value. If the value is 0 no bytes are skipped at all.
The maximum value of expression2 is $FF. Larger values will simply be truncated at the lowest byte before they are used. Thus a value of $100 will fill the skipped memory with the value $00.

The .BS directive is often used to declare RAM buffers and RAM variables. Normally it is not very useful to declare buffers in ROM memory because ROM values can not be changed afterwards anyway.

Operation of the .BS directive differs a little between formatted and unformatted target files.
With unformatted target files a filling value is always used, whether expression2 is given or not. If expression2 is omitted the value $00 is used to fill the skipped memory.
With formatted target files a filling value is only used if expression2 is given. Otherwise the skipped memory block will be skipped completely. The current data record is terminated and a new one is started with the new target address of the address field.
The only exception to this rule is when the number of bytes skipped is less than the line record length of the target file. In that case bytes with the value of $00 are used to fill the skipped memory.

The list file will only contain the first address of the skipped memory block. The filled bytes are not listed in the list file.

Examples:

0000-                      .OR  $0000     Define RAM memory
0000-                      .DU            but don't produce any code
0000-            PNTR      .BS  2         Define a 2 bytes pointer
0002-            CNTR      .BS  2         Define a 2 bytes counter
0004-            TEMP      .BS  1         Define a 1 byte temp location
0005-            FLAGS     .BS  1         Define a flags byte
0006-            KEYIN     .BS  1         Last pressed key (1 byte)
0007-            DSPPNT    .BS  1         Display buffer pntr (1 byte)
0008-            DSPBUF    .BS  6         Define a 6 byte display buffer
000E-                      .ED            End of dummy block
8000-                      .OR  $8000     Begin of the program in ROM
8000-                      .BS  $100,$FF  Skip part of ROM memory
8100-            ;                         and fill it with $FF

Please note that no code is generated in the .DUmmy block. Only the addresses are assigned to the appropriate labels.

.CH    CHain file

Syntax:

        .CH  filename[.ext]

See also: .BI .IN

Function:

With the .CH directive you can CHain include files together without going back to the main source file first.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The .CHain directive works exactly the same as the .INclude directive if it's encountered in the main source file. It remembers where we are in the main source file, opens a new source file and starts assembling from the beginning of that new source file. If the new source file is finished, it is closed and we continue where we left off in the main source file.

But if the .CHain directive is encountered inside an include file it will close the current include file immediately, opens the new .CHained file and starts assembling from the top of this new file. This effectively chains the new include file to the previous include file without going back to the main source file first.

Please note that all lines that follow the .CH directive in an include file are ignored by the SB-Assembler. They are not even treated as comment lines because they will never be listed in list files. The program line containing .CH, when encountered inside an include file, is always the last line of the file that is interpreted and listed in the list file.

On Version 2 of the SB-Assembler the .CH directive must be followed by a filename, which may be preceded by a drive letter and a path name according to the normal MS-DOS rules. With Version 3 of the SB-Assembler the filename may be preceded by a path name (and drive letter on Microsoft operating systems) according to the rules of the operatings ystem in use.
The extension .ext is optional. If the extension is omitted the default assembler source extension .asm is used.

Examples:

         .IN   DECLARE           Called from the main source file
 
LABEL    .EQ   10                Imaginary part of the .INclude file
          :
          :
          :
ANOTHER  .EQ   $FF
         .CH   C:\LIB\MACRO.LIB  Chain to the file MACRO.LIB 

MACRO    .MA                     First line of the chained source file
          :
          :
          :
         .EM                     Last line of the chained source file

         NOP                     We're back in the main source file

.CO    COmment

Syntax:

        .CO

See also: .EB .EC .EN .ER .ST

Function:

The .CO directive starts a comment block which can be filled with any remarks. It may also be used to temporarily comment out part of your code during debugging.
With the .CO directive you can implement large blocks of remarks without the need to start every line with a comment prefix like ; * or #.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The part of your source file that should be ignored by the SB-Assembler can be enclosed between the opening directive .CO and the closing directive .EC. All lines in between will be treated as if they all start with a comment prefix like ; * or #. They will be listed in list files, but the syntax is not checked nor will any code be generated.

It is possible to define a label together with the .CO directive on the same source line. All text following the .CO directive on the same source line will be ignored.
All following lines of the source file will also be ignored until the .EC directive is encountered in the operand field of the source line.

The .COmment mode will automatically be terminated if the physical end of the source file is reached.

Examples:

        .CO             Beginning of the comment block
Anything is allowed in this comment block.
You don't have to start the line with ; * or #
; Although it won't hurt if you do.

        .CO             It is not possible to nest comment
blocks. The last .CO directive is treated as a comment itself.
The next .EC directive will end the complete .COmment mode.

        LD    A,B      Is not assembled
        .DO   A>B      Has no effect
        .IN   FILE     Just skipped
        .EN            Not even this is interpreted

        .EC            End of comment block, at last.

.CP    Com port Parameters

Syntax:

        .CP  comport,baudrate,parity,databits,stopbits

See also: .EF .LF .LI .SF .TF .TW

Function:

The .CP directive sets the communication parameters of the selected serial COM port. This is useful if you intend to send the generated object file directly to a programmer or EPROM simulator connected to the COM port.

For now this directive only works on Version 2 of the SB-Assembler. Version 3 doesn't know this directive yet because of the differences in the operating systems it can run on.

Explanation:

I have added this directive to be able to set the communication parameters of the serial port in case you intend to send the target file directly to a device connected to a COM port.

All parameters are to be entered in the order indicated under the heading "Syntax".

comport
This is an expression that must evaluate to a legal DOS COM port number. Usually this in the range from 1..4, but all ports don't necessarily exist depending on your hardware. Only 1..16 is accepted as values, otherwise you'll get a "Range error".

baudrate
This is the baud rate you wish to use for communication. The expression should evaluate to one of the following baud rates, otherwise you'll get a Range error

110
150
300
600
1200
2400
4800
9600
19200

parity
This is the parity you wish to use. The parity is indicated by a letter N (none), E (even), or O (odd). Other letters will generate an Illegal parameter error

databits
This expression should evaluate to a value of 7 or 8. Other values will result in a Range error.

stopbits
This expression should evaluate to a value of 1 or 2. Other values will result in a Range error.

Please note that the COM port parameters are only set during pass 2 of the assembly process.

Examples:

        .CP  1,9600,N,8,1       Set COM1 to 9600 baud, No parity,
;                                8 data bits and 1 stop bit.

.CR    CRoss Overlay load

Syntax:

        .CR  filename[.ext]

Function:

The .CR directive loads a Cross Overlay into memory.

See also: Cross Overlays

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

This is one of the most powerful directives of the SB-Assembler. It loads a Cross Overlay into memory. This allows the SB-Assembler to assemble programs for almost any type of processor. It can even be used more than once in one program to switch between different Cross Overlays in one assembly run to create a program for different processors at same the time.

In Version 2 of the SB-Assembler the .CR directive must be followed by a filename which may be preceded by a drive letter and/or path name.
The extension .ext is optional and if it is omitted the default extension .SBA is used.
If no drive letter and/or path name are given the overlay is searched for in the current directory. If it can't be found there the search continues in the parent directory of the SB-Assembler which is the directory from which the program sbasm.com originated. So normally it is not necessary to include drive and path names. It's even better not to include them at all.
If the requested Cross Overlay is already resident in memory it will not be loaded again. This is usually the case at the start of the second pass of the assembler.

In Version 3 of the SB-Assembler the .CR directive must be followed by the cross overlay name. Cross overlays are allways stored in the sbapack directive of the SB-Assembler package. All cross overlay files have a name like cr*.py, where * is the actual name of the cross overlay to be used by the .CR directive. So you only specify this * part as cross name behind the .CR directive, like for example .CR Z80 (this will use the file crz80.py).
Please note that * part is always changed to lower case letters, so it doesn't really matter what case you use for the overlay name.
Some cross names are longer than 8 characters, including the leading 'cr'. This may cause some problems on DOS only systems. You may rename the affected crosses to your preference and use the new name instead of the original one.

As soon as the Cross Overlay is loaded into memory it will be initialized. This means that some default values are set, like the endian model (the order in which multiple byte values are stored in memory). Also Cross Overlay specific settings are set to their default value, e.g. the .DP value for the 6809 Cross Overlay will be reset to $00.
Please note that this initializing is also done if the Cross Overlay was already resident in memory!

In Version 3 of the SB-Assembler a previously loaded cross overlay is allowed to clean up first, before the new overlay is loaded. This allows the system to finish pending operations. One example is the AVR assembler, which is able to write bytes to the otherwise word sized memory. Should the last write to code memory end up on an odd location, the clean-up would add a padding byte to make it end on an even location.

It is even possible to have more than one Cross Overlay loaded during one assembly run. This enables you to create programs for mixed processor types.
One of the best examples for such a situation was the Apple ][ computer which had a native 6502 processor and an optional Z80 installed. The 6502 should initialize the system and handle I/O while the Z80 might be doing the hard work. Please note that both processors were sharing the same memory busses. To write programs for such a system requires an assembler that can handle more than one processor type at the same time. The SB-Assembler is such an assembler!
Another example could be a programming device to program Motorola processors. These processors need a little bootstrap loader to be uploaded before they can accept the code that must be written into EEPROM. The programmer itself can be made with any type of processor, e.g. the 8052. But the little bootstrap loader code must be written in the target processor's language. The 8052 treats that piece of code as data while the target processor accepts is as executable code.
There is no limit to the number of Cross Overlay switches in an assembly run to the SB-Assembler's point of view. Practically it may be difficult to implement the resulting code in most cases though ;-)

Also note that the SB-Assembler doesn't know any mnemonics of any processor type until a Cross Overlay is loaded into memory. The .CR is best used before any code is generated by the assembler because the Cross Overlay determines the endian model, which is the order in which multiple byte values are stored in memory.

Examples:

        .CR    Z80            Load the Z80 Cross Overlay
        .CR    6502           Load the 6502 Cross Overlay

The .CR directive has a hidden feature in Version 3 of the SB-Assembler. This hidden debug feature is enabled when the .CRD directive is used instead of the normal .CR directive. Normally you would need this hidden feature when you are writing your own cross overlays. If you don't enable the debug function the assembler will only complain that it can't load the overlay when you make a programming error, whithout telling you where the error occurred.
More information can be found on the DIY page.

.DA    DAta

Syntax:

        .DA  [#¦/¦=¦\]expression[,[#¦/¦=¦\]expression[,...]]

See also: .AS .AT .AZ .DB .DL .DR .DW .HS .RF .TS

Function:

The .DA directive is used to enter bytes and words of data into the target code. The data is entered as one or more expressions, separated from each other by commas.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

Every expression following the .DA directive will be evaluated and the lower 16 bit value of the result is stored in the target file. The order in which the bytes are stored depends on the loaded Cross Overlay. Some processors prefer to have the lowest byte of pair stored first, others want the highest byte stored first. So please refer to the description of the particular Cross Overlay to see in what order the bytes are stored.
The default order, when no Cross Overlay is loaded, is lowest byte first. This is also known as little endian model.

The .DA directive can also be used to store single bytes in the target file. To store single bytes the expression must be preceded by one of the symbols:

# stores the lowest byte of the 32 bit result (b0..b7)
/ stores the 2nd lowest byte (b8..b15)
= stores the 2nd highest byte (b16..b23)
\ stores the highest byte (b24..b31)

The lowest 16 bits are stored if none of these prefixes is used.

Data bytes and words can be mixed together on the same .DA directive line. Multiple expressions should be separated by commas.

Important: Be sure to load the appropriate Cross Overlay before using the .DA directive! Otherwise the first data words may be saved in the wrong order (wrong endian model).

I have included the .DR directive for those cases where you need the opposite endian model.

Examples:

0000-09 53 7B 23
0004-61 E1               .DA    #%1001,#@123,#123,#$123,#'a',#"a"
0006-78                  .DA    #$12345678
0007-56                  .DA    /$12345678
0008-34                  .DA    =$12345678
0009-12                  .DA    \$12345678
000A-34 12               .DA    $1234               Notice the byte order
000C-7C                  .DA    #5+$80-%1001        Some math can be done too
000D-34 12 56            .DA    $1234,#$56          Mixed words and bytes

.DB    Define Byte

Syntax:

        .DB  [expression | string[,[expression | string[,...]]

See also: .AS .AT .AZ .DA .DL .DR .DW .HS .RF .TS

Function:

The .DB directive is used to enter bytes only and is meant to add some compatibility with other assemblers in the market. Operation of the .DB directive is almost the same as the DB directive found in most assemblers. Personally I prefer the use of the more powerful .DA directive.
Porting existing software to the SB-Assembler will become a little easier with this directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

Every expression following the .DB directive will be evaluated and only the lower 8 bit value of each result is stored in the target file. If you need other bytes of the 32-bit result you can divide the result by $100, $10000 or $1000000.

Instead of an expression you may also enter a string of characters. Strings must be surrounded by a pair of single or double quotes. The string may not be empty and must be terminated with the same type of quote as it was opened. The opening quote may not be present in the string itself because that would terminate the string prematurely.
There is no difference between using a pair of single quotes or a pair of double quotes, unlike with the .AS and .DA directives. This is done to make the directive more compatible with other assemblers.

Multiple expressions or strings in the operand field must be separated by commas.

I have also included the .DW directive to improve the compatibility of word definitions with other assemblers.

Examples:

0000-78                    .DB   $12345678         Only the LSB is used
0001-7C                    .DB   5+$80-%1001       Complex expression
0002-12 34                 .DB   $12,$34           Multiple expressions
0004-54 65 73 74           .DB   "Test"            Only a string
0008-54 65 73 74
000C-0D 0A                 .DB   'Test',$0D,$0A    A string followed by 2 bytes

.DL    Data Long words

Syntax:

        .DL  [#¦/¦=¦\]expression[,[#¦/¦=¦\]expression[,...]]

See also: .AS .AT .AZ .DA .DB .DR .DW .HS .RF .TS

Function:

The .DL directive is used to enter words and long words of data in the target code. The data is entered as one or more expressions, separated by commas.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

Every expression following the .DL directive will be evaluated and a 16 bit word or the entire 32 bit long word is stored in the target file. The order in which the bytes are stored depends on the loaded Cross Overlay. Some processors prefer to have the lowest byte stored first, others want the highest byte stored first. So please refer to the description of the particular Cross Overlay to see in what order the bytes are stored.
The default order, when no Cross Overlay is loaded, is lowest byte first. This is also known as little endian model.

The .DL directive is usually used to store long words of data, containing 4 bytes each. It can also be used to store words containing 2 bytes each. To store words the expression must be preceded by one of the symbols:

# stores the lowest word of the 32 bit result (b0..b15)
/ stores the middle 2 bytes (b8..b23)
= stores the highest word (b16..b31)
\ stores the highest byte (b24..b31), the upper 8 bits of the word remain 0

The long word of 4 bytes is stored if none of these prefixes is used.

Long words and words can be mixed together in the same .DL directive. Multiple expressions should be separated by commas.

Important: Be sure to load the appropriate Cross Overlay before using the .DL directive! Otherwise the first data words may be saved in the wrong order (wrong endian model).

Unlike the .DA directive the .DL directive has no reverse endian model equivalent. If you want to store long words in the reverse order you'll have to save the bytes or words separately by using the .DA or .DR directives.

Examples:

0000-78 56 34 12        .DL    $12345678
0004-78 56              .DL    #$12345678
0006-56 34              .DL    /$12345678
0008-34 12              .DL    =$12345678
000A-12 00              .DL    \$12345678
000C-78 56 34 12 
0010-78 56              .DL    $12345678,#$12345678

.DO    DO if condition is true

Syntax:

        .DO  expression

See also: .EL .EM .FI .MA .XM

Function:

The .DO directive is one of the 3 directives used for conditional assembly. It can be used to include or exclude parts of the source code from the assembly processes depending on a test condition.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

If the expression evaluates to true (if its value is not 0) all following source lines will be assembled normally. If the expression evaluates to false (if its value is 0) the following source lines will not be assembled until the next .EL or .FI directive.

The .FI directive will end the conditional block that was started by the .DO directive, regardless of whether the expression evaluated to true or false.
The true/false condition can be reversed by the .EL directive as often as necessary.

The .DO .EL and .FI directives can be compared with IF, ELSE and ENDIF in other languages. Remember that the conditional directives control the assembler and not the target processor! They can not be used to let the target system compare values or make other decisions. The target system is unaware of the conditions used during assembly. In fact, only the lines which were surrounded by a true condition will end up in the target file. The target system will never see lines embedded in a false condition.

The expression must evaluate completely and may not contain any forward referenced labels. The .DO directive insists on knowing the condition and that is not possible if one of the labels in an expression is not defined yet.

Conditional assembly can be nested. This means that a .DO .FI block may contain other .DO .FI blocks. This nesting may go on, up to 255 levels deep. If that should not be enough for your application I suggest you get your head examined.
Version 3 of the SB-Assembler doesn't even have a (sensible) maximimum nesting level.

The listing of conditionally excluded source lines can be controlled with the .LI directive. If the .LI CON mode is selected all source lines are listed, regardless of the condition. Lines that are not assembled are marked with the word SKIP in the line number column. With Version 3 of the SB-Assembler the letter 'S' is prefixed in front of the line numbers.
If the .LI COFF mode is selected the skipped lines are not listed at all.

The syntax of skipped lines due to a false condition is not checked. During a false condition the assembler will only look for .DO, .EL and .FI direcitves in the instruction field.
Labels are not allowed on lines containing any of the conditional directives .DO, .EL and .FI.

Examples:

          .CR  Z80            Load the Z80 Cross Overlay
          .DO  VALUE1>VALUE2
;                             These lines are assembled if
;                              VALUE1 is greater than VALUE 2
          NOP
          .EL                 Reverse condition
;                             These lines are not assembled
;                              if VALUE1 is greater than
;                              VALUE2
          NOP
          .FI                 End of conditional block

          .DO  VALUE1>VALUE2
          .DO  ?=0
;                             Condition nested 2 levels deep
;                             These lines are assembled if
;                              VALUE1 is greater than VALUE2
;                              and if we are in pass 1 of the
;                              assembly process (?)
          .FI                 End of 2nd condition (pass 1)
;                             These lines are assembled if
;                              VALUE1 is greater than VALUE2,
;                              regardless of the pass we're in.
          .FI                 First conditional is ended

          .DO  0              Condition is never true!
;                             This line will never be
;                              assembled
          .DO  1              This nested .DO is not evaluated
;                             because the previous .DO is always
;                             false.
;                             This line is never assembled
;                             The value of the expression
;                              doesn't matter for the .DO
;                              is not evaluated anyway.
          .FI                 Nested .DO block ended
;                             This line is still not assembled
          .FI                 Closing outer .DO block
;                             This line is assembled again

; You can invert the condition using .EL as often as you like.
          .DO   1             Condition is true!
          NOP                 This line is assembled
          .EL                 Reverse condition to false!
          NOP                 This line is not assembled
          .EL                 Reverse condition to true again!
          NOP                 This line is assembled again
          .FI                 End of conditonal assembly

.DR    Data Reverse

Syntax:

        .DR  [#¦/¦=¦\]expression[,[#¦/¦=¦\]expression[,...]]

See also: .AS .AT .AZ .DA .DB .DL .DW .HS .RF .TS

Function:

The .DR directive is an alternative tool to enter bytes and words of data in the target code. The data is entered as one or more expressions, separated by commas.
It functions much the same as the .DA directive. The only difference is the order in which the bytes of a 16 bit value are stored.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

Every expression following the .DR directive will be evaluated and the lower 16 bit value of the result is stored in the target file. The order in which the bytes of a pair are stored depends on the loaded Cross Overlay. The order is opposite to the order in which the .DA directive would store the bytes of a 16 bit value. Therefore the order also depends on the loaded Cross Overlay.
The default order, when no Cross Overlay is loaded, is highest byte first. This is also known as big endian model.

The .DR directive can also be used to store single bytes in the target file. To store single bytes the expression must be preceded by one of the symbols:

# stores the lowest byte of the 32 bit result (b0..b7)
/ stores the 2nd lowest byte (b8..b15)
= stores the 2nd highest byte (b16..b23)
\ stores the highest byte (b24..b31)

Please note that there is no difference with the .DA directive when it comes to handling single bytes.

Data bytes and words can be mixed together in the same .DR directive. Multiple expressions should be separated by commas.

Important: Be sure to load the appropriate Cross Overlay before using the .DR directive! Otherwise the first data words may be saved in the wrong order (wrong endian model).

Examples:

0000-09 53 7B 23
0004-61 E1                .DR     #%1001,#@123,#123,#$123,#'a',#"a"
0006-78                   .DR     #$12345678
0007-56                   .DR     /$12345678
0008-34                   .DR     =$12345678
0009-12                   .DR     \$12345678
000A-12 34                .DR     $1234             Notice the byte order
000C-7C                   .DR     #5+$80-%1001
000D-12 34 56             .DR     $1234,#$56        Mixed words and bytes

.DU    DUmmy mode

Syntax:

        .DU   [expression]

See also: .BS .ED .EP .NO .OR .PH .RF .SM

Function:

The .DU directive is mainly used for defining RAM memory locations. Only the location is important while defining Labels in RAM area.
Version 3 of the SB-Assembler has a more elegant way of defining RAM locations, the .SM directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

Code generated after the .DU directive is simply discarded. No code is saved to the target file what so ever. For the rest nothing has changed in the assembly process. Labels are assigned and addresses are counted as if the code really was saved.

Warning: Use the .DU directive with extreme caution. Wrong use of the .DU directive can create a program that will never work. The SB-Assembler won't warn you if you use the .DU directive in the wrong way.

The dummy block that is started by the .DU directive ends at the next .ED directive, or when a new dummy block is started. Also the .OR directive will end the current dummy block. However the .NO directive will not end the dummy block!

Everything on the source line following the .DU directive will be treated as comments.

Please note that the target address after .ED will be exactly the same as the target address at the time the .DU directive was given. Even though the current program counter has increased. Therefore the program counter and target address won't be in sync anymore.
This means that a new .OR directive should follow the .ED under most circumstances, at least if you intend to create a working program.

The dummy mode can span across multiple include files.

As from software version 2.07 you may also specify the starting address of the dummy block by using the optional expression. Effectively this combines a line with the .OR directive and a line with the .DU directive.
The expression may not contain any forward referenced labels.

Examples:

           .OR    $8000        Start defining RAM area
           .DU                 But don't save the code anywhere
COUNTER    .BS    2            Define a 2 byte location
POINTER    .BS    2            Define another 2 byte location
FLAG       .BS    1            Define a single byte location
BUFFER     .BS    10           Define a 10 byte long buffer
VALUE      .BS    2            Define a 2 byte location
           .ED                 End of RAM definition

           .OR    $0000        The real program starts here

As from software version 2.07 this example may also be written as:

           .DU    $8000        Start defining RAM area
COUNTER    .BS    2            Define a 2 byte location
POINTER    .BS    2            Define another 2 byte location
FLAG       .BS    1            Define a single byte location
BUFFER     .BS    10           Define a 10 byte long buffer
VALUE      .BS    2            Define a 2 byte location
           .ED                 End of RAM definition

           .OR    $0000        The real program starts here

Version 3 of the SB-Assembler has a more sophisticated way of performing RAM declareations, using the .SM directive. Therefore I recommend to use the .SM directive instead of the error prone .DU directive. The .DU directive will still work though, for compatibility reasons.
Please note that the .DU directive will only work in Code memory, not in RAM or EPROM code memory.

.DW    Define Word

Syntax:

        .DW  [expression[,[expression[,...]]

See also: .AS .AT .AZ .DA .DB .DL .DR .HS .RF .TS

Function:

The .DW directive is used to enter words only and is meant to add some compatibility with other assemblers in the market. Operation of the .DW directive is almost the same as the DW directive found in most assemblers. Personally I prefer the use of the more powerful .DA directive.
Porting existing software to the SB-Assembler will become a little easier with this directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

Every expression following the .DW directive will be evaluated and only the lower 16 bit value of the result is stored in the target file. The order in which the bytes are stored depends on the loaded Cross Overlay. Some processors prefer to have the lowest byte of a pair stored first, others want the highest byte stored first. So please refer to the description of the particular Cross Overlay to see in what order the bytes are stored.
The default order, when no Cross Overlay is loaded, is lowest byte first. This is also known as little endian model.

Multiple expressions should be separated by commas.

Important: Be sure to load the appropriate Cross Overlay before using the .DW directive! Otherwise the first data words may be saved in the wrong order (wrong endian model).

I have included the .DB directive to improve the compatibility of byte definitions with other assemblers too.

Examples:

0000-34 12               .DW   $1234           Notice the byte order
0002-7C 00               .DW   5+$80-%1001     A more complex expression
0004-34 12 78 56         .DW   $1234,$5678     Multiple expressions

.EB    Error Bell

Syntax:

        .EB  on¦off

See also: .CO .EC .EN .ER .ST

Function:

With this directive you can turn the Error Bell on or off. The Error Bell is the beep that is generated every time the SB-Assembler stumbles over an error in your source code.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

Per default the Error Bell option is switched on, which sounds a beep for every error in your source code. Not all operating systems support the Error Bell. So there's no guarantee that the Error Bell is sounded even if the option is switched on.

Examples:

         .EB   ON          Switch Error Bell option on
         .EB   OFF         Switch Error Bell option off

.EC    End Comment

Syntax:

        .EC

See also: .CO .EB .EN .ER .ST

Function:

This directive ends the comment block that was started by the .CO directive. Provided that the label field of the source line is empty and the .EC directive appears in the instruction field. Otherwise the comment block is not ended.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The label field should be empty and the .EC directive must appear in the instruction field to make it effective. Otherwise the comment block won't be terminated. This means that at least one space or TAB character must precede the .EC directive. No other characters are allowed before the .EC directive, otherwise it will simply be part of the comment lines.

Everything on the same source line that follows the .EC directive will still be treated as comment.

An error message will be reported if the comment block was not activated.

The comment mode will also be terminated automatically at the end of the an include file.

In version 3 a warning is given if an orphaned .EC directive is found. An orphaned .EC directive is one which doesn't have a previous .CO directive.

.ED    End Dummy mode

Syntax:

        .ED

See also: .BS .DU .EP .NO .OR .PH .RF .SM

Function:

The .ED directive will end the dummy mode that was started by the .DU directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

No error is reported if the dummy mode was not started when the .ED directive is encountered. In that case the .ED directive will simply be ignored.

Everything on the source line following the .ED directive will be treated as comment.

The SB-Assembler will not warn you if the program ends when no .ED directive ended an active dummy mode. The dummy mode can span across multiple include files.

.EF    Error File

Syntax:

        .EF  filename[.ext]

See also: .CP .LF .LI .SF .TF .TW

Function:

The .EF directive allows you to send all reported assembling errors to a specific file or device. Opening this file will allow you to quickly locate the locations in your source files which contain the errors.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The SB-Assembler will send all reported errors to the file that was opened with the .EF directive. Apart from this the errors will still be sent to the normal list file and screen if the listing is switched on. Errors will always be displayed on the screen and logged in an opened error file, regardless of the selected list options.
The errors reported in the error file are labelled with the originating source file name and the line number in which the error occurred. This allows you to quickly locate the affected source lines.
The error file remains empty if no errors are reported during the assembling process.

If the error file does not exist yet it will be created. If a file with the same name already exists in the given path it will be overwritten without prior notice.

If you want to make use of the .EF directive you should place that directive preferably among the first few lines of the main source file, before potential errors may occur. Otherwise some errors may not be logged.
In Version 2 of the SB-Assembler only one error file can be created in one assembly run. That error file can not be closed until the end of the assembling process, at which point the SB-Assembler will close all files it had opened.
Version 3 of the SB-Assembler can open multiple error files, for whatever reason you may think of. Errors are always written to the currently open error file. Therefore errors found in pass 2 will always be written to the last opened error file.
The error file will be opened during the first pass of the assembling processes. This allows logging of errors that occur in the first pass as well.

As usual, the filename may be preceded by a path name. On Microsoft systems a drive letter may also preceed the path name. If no extension .ext is given the SB-Assembler assumes the default extension for error files, which is .err.
It is also possible to send error messages to a device like a printer for instance.

Examples:

            .EF  errors              The errors are sent to the
;                                     file ERRORS.ERR
            .EF  LPT1:               The errors are sent to the
;                                     first printer (mind the : )
            .EF  C:\TEXT\ERRORS.PRN  The errors are sent to
;                                      the file ERRORS.PRN on
;                                      drive C:\TEXT

Please note that some operating systems are case sensitive when it comes to path names and file names.

.EJ    EJect

Syntax:

        .EJ

See also: .LM .PG .TI

Function:

In Version 2 of the SB-Assembler the .EJ directive sends a Form Feed character to the list file. When sending the listing to the printer this will cause ejecting of the current page. At the same time the line counter for the list file is reset to 0 and the page number is incremented.
This directive will only work during the second pass of the assembly process because the SB-Assembler does not list anything at all during the first pass (apart from error messages).

Version 3 doesn't have any of the page formatting directives because they have become fairly obsolete nowadays. Therefore the .EJ directive is also scrapped from the list of directives.

Explanation:

This directive acts like the .PG directive. The only difference is that .EJ will not print a new page head above the new page like .PG does.

The source line containing the .EJ directive will not be listed in the list file. Everything following .EJ on the source line will be treated as comment.

If the listing is set to Single Sheet mode by the .TI directive the assembly process will come to a halt and a message is put on the screen requesting you to insert a new page. Hit any key when a new page is inserted to continue the assembly process.

.EL    ELse condition

Syntax:

        .EL

See also: .DO .EM .FI .MA .XM

Function:

The .EL directive is used together with the conditional assembly directives .DO and .FI. The .EL directive will invert the current condition.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

The .EL directive inverts the current test condition. If the current condition was true it will become false. And if it was false it will become true. The following program lines are only assembled if the condition is true until the next .EL directive or until the .FI directive is encountered.

The .EL directive may be used as often as you want to invert the condition between the .DO and .FI directives. The condition is inverted every time the .EL directive is used.

The label field of the source line on which the .EL directive is used must be empty. So it's not possible to declare a label on a source line that contains the .EL directive.

Examples:

           .DO  1            Condition is always true (<>0)
;                            These lines are interpreted by
;                             the SB-Assembler
           .EL               Reverse condition
;                            This line is not interpreted
           .EL               Reverse condition
;                            This line is again interpreted
           .EL               Reverse condition
;                            This line is again not interpreted
           .FI               End of conditional block

.EM    End Macro definition

Syntax:

        .EM

See also: Macros .DO .EL .FI .MA .XM

Function:

This directive ends a Macro definition that was started by the .MA directive unconditionally.
Macro operation is explained in more detail in a separate chapter.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The label field of the source line containing the .EM directive should be empty. It is not possible to define a label on the same line.
Everything on the source line following the .EM directive will be ignored.

In version 3 the user is warned if an orphaned .EM directive is found. An orphaned .EM is one which does not have matching .MA directive.

.EN    ENd

Syntax:

        .EN

See also: .CO .EB .EC .ER .ST

Function:

This directive signals the end of the current source file. The source line containing the .EN directive will be the last line that is assembled of the current source file, regardless of what ever follows it. The current source file is closed and in case it was an include file the SB-Assembler will continue to process it's parent file as if the include file ended in a natural way. In version 2 this will always be the main source file because include files can't be nested there. In version 3 include files can be nested.
With the SB-Assembler the use of the .EN directive is completely optional. Unlike some other assemblers the SB-Assembler is clever enough to detect the natural end of the source file.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The .EN directive can be used to end a source file prematurely. This could be useful for debugging purposes or if the rest of the source file contains only comments which don't have to be listed in the list file.
The source line containing the .EN directive is always the last line that is assembled of the current source file. The file is immediately closed and all text following the current source line will be ignored completely.

If the .EN directive is encountered in the main source file the current pass will end immediately. If we were still in pass 1 the assembler will start pass 2 of the assembly process.
If the .EN directive is encountered in an include file then that file will be closed and the assembler continues with the parent source file, the file which has called the include file.

.EP    End Patch

Syntax:

        .EP

See also: .BS .DU .ED .NO .OR .PH .RF .SM

Function:

With the .EP directive the so called patch mode, that was started by the .PH directive, is switched off .

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The .EP directive switches off the so-called patch mode. In effect this means that the program counter gets the same value as the target pointer again.
The .EP directive will be ignored if the patch mode was not activated. In which case the program counter and target address were in sync already.

A possible label in the label field of the source line still gets the value of the last patch address.

Everything on the source line following the .EP directive is ignored and therefore will be treated as comment.

Please refer to the .PH directive for more details about the patch mode.

In version 3 of the assembler the .PH patch mode is only allowed in code memory. If the .EP directive is found in any of the other memory modes an error is generated.

.EQ    EQuate

Syntax:

label     .EQ    expression
label     =      expression

See also: .SE

Function:

The .EQ directive is used to assign a value other than the default current memory location value to a label. Alternatively the = symbol may be used instead of the .EQ directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The .EQ directive is used to assign a constant value to a label. Per default a new label will get the value of the current memory location. If you want the new label to get a different value than its default value you should use the .EQ directive. The = symbol is equivalent to the .EQ directive and has exactly the same effect.

A label that was assigned using the .EQ directive can be considered a constant value because its value can not be changed anymore in this assembly run.
Internally the label value is always 32 bits long. The expression may not be preceded by the # / = and \ symbols to force the value to be only 8 bits in length.

Please note that the .EQ directive does not generate any code for the target system. It only assigns the expression's value to a label which helps us humans to cope better with meaningless numbers.

Forward referenced labels in the expression are not allowed. This means that all labels in the expression should be completely resolved.

The SB-Assembler will stop parsing the source line immediately after it has evaluated the expression. Everything following the expression is treated as a comment. This will allow you to let the expression be followed by a second expression to indicate that the label's value is the beginning of multiple addresses. It will have no effect on the value that is assigned to the label though and is only meant for documentary purposes.

Like all labels used with the SB-Assembler, labels declared with the .EQ directive may be redefined, as long as the new definition gives the label the same value as it already had. This is useful if labels are declared in libraries. Linking multiple libraries may cause some labels to be redefined. This is no problem as long as the definition results in the same value every time. For this redefinition it doesn't matter whether the label gets its value automatically or by using the .EQ directive.
The SB-Assembler will report an "Extra definition error" if a label is redefined with a different value than the first time.

It is even allowed to assign a value to Local labels using the .EQ directive. The SB-Assembler won't protest if you do. But remember that Local labels only "live" until the definition of the next Global label.

Legal Examples:

1234-       LABEL     .EQ    $1234        Assign a constant value to LABEL
000D-       CR        .EQ    $0D          Assign the Carriage Return to CR
0050-       POINTER   .EQ    $50,$51      Assign the value $50 to POINTER,
0000-       ;                              the rest is treated as comment
1236-       NEW       .EQ    LABEL+2      LABEL is already defined
ABCD-       ALT       =      $ABCD        = symbol is equivalent to .EQ
123456-     BIG       .EQ    $123456      Number larger than 16-bits
12345678-   VERYBIG   .EQ    $12345678    And even larger (up to 32 bits)

Illegal Examples:

            TEST      .EQ    FORWARD      Forward referenced!
            ERROR     .EQ    #$0D         # prefix not allowed here
                      .EQ    %1001        Label field is empty
            MISSING   .EQ                 ; The expression is missing

.ER    forced ERror

Syntax:

        .ER  [F|W[,]][errormessage]

See also: .DO .EL .FI .CO .EB .EC .EN .ST

Function:

The .ER directive can force the SB-Assembler to report an error message. Such an error message can either be a normal error or a fatal error.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Example:

You can force an error message to be reported with the use of the .ER directive. This may be useful if you want to be warned if the program you're writing exceeds a certain memory range, or if a memory page boundary is crossed.
The .ER directive is intended to be used in co-operation with the conditional assembly directives .DO .EL and .FI. Without conditional assembly this directive has very little use because the SB-Assembler would never reach pass 2 to produce the program if the .ER directive is used unconditionally.

The parameter following the .ER directive is the text of the error message that is to be reported. It is not possible to place comments on the same source line. All text is considered to be the error message, including spaces. Even the case of the characters of the message is retained. The parameter doesn't have to be enclosed in delimiters, like it would have been for other literal strings.

If no parameter is given the standard text "User error" is reported.

If the parameter is a single character F or an F followed by a comma a fatal error will be reported. A fatal error will terminate the assembly process immediately.
If you want to include a custom error text with this fatal error the character F must be followed by a comma, which should be followed by the custom error message.

In version 3 of the SB-Assembler you may also generate warnings, in stead of the errors. A user generated warning is reported if the first character of the error text is a single W or an W follwed by a comma.

Examples:

; Generate a standard non-fatal error
         .ER

; Generate a standard fatal error
         .ER   F

; Generate a custom non-fatal error
         .ER   *** This is the error message

; Generate a custom fatal error
         .ER   F,*** This is the error message

; Generate a standard warning (version 3 only)
         .ER   W

; Generate a custom warning (version 3 only)
         .ER   W,*** This is the warning message

.FI    FInished conditional

Syntax:

        .FI

See also: .DO .EL .EM .MA .XM

Function:

The .FI directive is used in co-operation with .DO and .EL for conditional assembly. The .FI directive will close a condition that was opened by the last .DO directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

The .FI directive will close the condition that was opened by the last .DO directive and at the same time it will decrement the nesting counter.
The conditional mode will be terminated if the nesting counter reaches 0. In that case all following source lines will be assembled unconditionally.
The SB-Assembler will report a "Missing .DO error" if no .DO is active. This is when the nesting counter was already 0 when the .FI directive is encountered.

The label field of the source line containing the .FI directive must be empty. So it's not possible to declare a label on a source line that contains the .FI directive.

Examples:

         .DO  1         Condition always true (<>0)
;                       This line is assembled
         .EL            Reverse condition
;                       This line will not be assembled
         .FI            End of conditional assembly
;                       This line and following lines
;                       are assembled unconditionally.

.HS    Hex String

Syntax:

        .HS  [.]hexbyte[,[.]hexbyte[,.....]]

See also: .AS .AT .AZ .DA .DB .DL .DR .DW .RF .TS

Function:

The .HS directive accepts a string of hexadecimal encoded bytes. Each hexadecimal encoded byte must consist of 2 hexadecimal digits.
The .HS directive can be used to enter large tables of hexadecimal bytes with less parameter overhead than with the normal .DA directive.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

The Hex String consists of a number of hexadecimal digit pairs. Every digit pair may be separated from the next pair with a dot. This dot serves no purpose other than improving the readability for us humans. Digit pairs belonging to the same byte may not be separated by a dot!
Bytes should be entered as a digit pair, which means that leading zeroes must be included!

The bytes are saved to the target file in the order of appearance.

All data entered are plain hexadecimal bytes. No expressions are allowed here.
The interpretation of the Hex String is ended at the first space, TAB or EOL. The rest of the line is regarded as comment.

Examples:

0000-01 23 45 67
0004-89 AB CD EF            .HS   .01.23.45.67.89.AB.CD.EF
0008-01 23 45 67
000C-89 AB CD EF            .HS   0123456789ABCDEF
0010-01 23 45 67
0014-89 AB CD EF            .HS   0123.4567.89AB.CDEF

.IN    INclude source file

Syntax:

        .IN  filename[.ext]

See also: .BI .CH

Function:

The .IN directive allows you to split the complete source text of your program into different modules, which are loaded and interpreted one by one to form the total source of your assembly program.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

Splitting a large job into smaller sub-jobs makes program management and total overview a lot easier. This is also true for creating programs in assembly. In DOS the maximum source file size the SB-Assembler can handle is only limited by your favourite text editor and free memory. The maximum source file size in other operating systems is sheer unlimited. However shorter files, each dedicated to a specific task, are much easier to maintain.

The main source file is opened when you start the SB-Assembler. This main source file may open as many include files as you like. Preferably the main source file should only contain some initialization directives like .CR and .OR and all references to the required .INclude files.

The .IN directive requires a filename as parameter. This filename may be preceded by a path name, and possibly a drive letter for Microsoft systems. The extension .ext is optional. If the extension is omitted the default extension .asm is used.
Wirh Version 2 of the SB-Assembler the maximum total length of path and file name may not exceed 122 characters. The length limit for Version 3 is only dictated by the operating system you run the assembler on.
Please note that file names on some operating systems are case sensitive.

An include file will be closed when the assembler reaches the end of that include file. Assembly will then continue in the main source file on the line following the line that opened the include file.
Please notice that all include files are opened and closed twice during the 2 pass assembly process.

With Version 2 of the SB-Assembler it is not possible to nest include files. This means that you can not open another include file from within an include file.
With Version 3 it is now possible to nest include files, which means that an include file can open another include file. When such a nested include file is closed the calling include file will proceed on the line following the directive which called the just terminated include file.
Please note that it is technically possible to create an endless program this way. The assembler only checks if the new include file is the same as the present one, giving you an error if does. However it will not warn you if include file A will call include file B, which calls include file A again, which calls inlcude file B again, again and again and again. It's your responsibility to avoid this if you don't be prepared for a system crash as soon as the operating system runs out of resources.

Line numbers in list files are preceded with an 'I' to indicate that they originate from an include file. Line numbers are reset to 1 every time a new include file is opened.

Examples:

        .IN  declare            Include declaration module (extension .asm)

        .IN  C:\LIB\MACRO.LIB   Include Macro library (extesion .lib)

        .IN  INIT               Include initialization module (extension .asm)

.LF    List File

Syntax:

        .LF  [filename[.ext][,linelength]]

See also: .CP .EF .LI .SF .TF .TW

Function:

With the .LF directive you can divert the listing output from the screen to a file or other output device.
During the assembly process you can divert the listing to different files or devices as often as you like. However only one diversion can be active at the same time.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

Per default the listing is output to the screen with a maximum line length of 254 characters (Version 3 has nog length limit). This means that longer lines are simply broken down at the right end of the screen and continue on the next line. The .LF directive allows you to send the listing elsewhere.

The filename may be preceded by a path name, and a drive letter if you're using a Microsoft operating system. If no extension .ext is given the default extension .lst is used.

An already open list file will be closed when the .LF directive is encountered. If no filename is given the output will be redirected to the screen again.
If you want to add a comment on a line that should only contain an empty .LF directive this comment should be preceded with a semicolon, otherwise it is treated as a file name.

If a filename is given behind the .LF directive a new file will be created if the filename does not exist yet. If the filename does already exist its length is reduced to 0, effectively overwriting the existing file irreversible without prior warning.

The filename may be followed by the maximum line length to be used in the listing. A comma should separate the filename from the linelength expression.
Lines in the listing will be truncated at this maximum length. All other characters on such a line will be discarded in the listing. The minimum line length is 64 characters long. The maximum length is 254 characters, excluding the closing CR and LF characters.
No error is given if a too small or too large number is entered, however the minimum or maximum length is used instead.

Source lines containing the .LF directive will only be interpreted during pass 2 of the assembly process. Any errors in the parameters will be detected in pass 2.

Source lines containing the .LF directive will never be listed in a list file themselves.

Please note that you are still able to exclude parts of the program from being sent to the list file by using options of the .LI directive.

Examples:

         .LF  list         Send listing to list.lst
         .LF  C:\ASSEMBLE\TEST.PRN  Send listing to TEST.PRN
;                           on drive C: in directory \ASSEMBLE\
         .LF             ; Close listing file, output to screen

.LI    LIst options

Syntax:

        .LI  on¦off¦mon¦moff¦con¦coff¦ton¦toff[,on¦off¦mon¦moff¦con¦coff¦ton¦toff[,.....]]

See also: .CP .EF .LF .SF .TF .TW

Function:

With the .LI directive you can precisely control what is listed to the list file or screen during assembly.
For instance if you put the directive .LI OFF at the very last line of your source file you will inhibit the time consuming listing of the symbol table. Please note that this symbol table is only listed at the end of the assembly on Version 2 of the SB-Assembler.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

At least one list option should be present in the parameter field. Multiple list options should be separated by commas.

With the option on¦off you can switch the listing completely on or off. Nothing will be sent to the list file or screen if the listing is switched off. Please note that error messages will always be listed, regardless of the settings of the list options.
The off list option has priority over all other list option. If the list option is switched off there's nothing the other options can do about it.

With the mon¦moff option you can switch the listing of expanding Macros on or off. Expanding Macros will not be listed if this option is switched off (moff). The line calling the Macro to expand will be listed however.
Please note that the listing of the definition of the Macro will not be affected by this list option.
If the Macro list option is switched on (mon) all following Macro expansions will be listed completely in the list file or to the screen. The letter M will precede all Macro line number in the list file.

With the con¦coff option you can control the listing of source lines that are not assembled due to conditional assembly when the condition is false.
Source lines that are not assembled because a previous condition proved to be false will not be listed if the coff list option is selected. Program lines that are assembled because of a true condition will be listed normally.
All source lines will be listed if the con list option is selected. So also the lines that are not assembled due to a false condition will be listed. Source lines that are not assembled due to a false condition will be marked with the word SKIP in the line number column of the list file. Version 3 of the SB-Assembler will not print the word SKIP on the line number position for skipped lines. It will simply print an S in front of the line number in the list file.

Only version 3 of the SB-Assembler has a fourth list option, ton¦toff. This option controls the listing of instruction timing information. If this option is switched on (ton) it will print the timing information in between paranteses just behind the line number on lines containig mnemonics. Lines containing comments only or directives won't have timing information printed.
If you're not interested in the timing information you can switch them off with the toff option.
Normally the timing information shows the number of clock cycles the instructions takes. Sometimes two values are printed, which means that the particular instruction can take two different times to execute, probably due to a previous status condition. At other times an * is printed behind the instruction time, which means that this particular instruction has some rather complicated instruction times, depending on several conditions. You should consult the processor's documentation in that case to find out what applies to your particular situation.
Be aware of the fact that the instruction times shown are derived from the original documentation. Later processor improvements can result in different instruction times. Especially the 8051 direvatives will probably show you many differences in insturctions times.

Per default all three/four list options are switched on. This means that all source lines will be sent to the list file or screen.

It is allowed to have multiple list options in the parameter field after the .LI directive, as long as they are separated from each other by commas. It is even allowed to switch any of the list options on and off repeatedly on the same line, although only the last option will be remembered.
For example the next source line will switch the main and conditional list options on, and the Macro list option off.

         .LI  OFF,MON,COFF,ON,CON,MOFF

Source lines containing a .LI directive will never be listed in the list file them selves. Except when an error in such a line is detected.

Examples:

         .LI   ON              Switch main list option on
         .LI   OFF             Switch main list option off
         .LI   MON             Switch macro list option on
         .LI   MOFF            Switch macro list option off
         .LI   CON             Switch conditional list option on
         .LI   COFF            Switch conditional list option off
         .LI   ON,MON,CON      Switch all options on
         .LI   OFF,MOFF,COFF   Switch all options off
         .LI   ON,MOFF,CON     Only macro option off
         .LI   ON,OFF,ON,OFF   Results in main list option on
; Only for Version 3
         .LI   TON             Turn timing information on
         .LI   TOFF            Turn timing informaiton off

.LM    Left Margin

Syntax:

        .LM  expression

See also: .EJ .PG .TI

Function:

With the .LM directive you can set the width of the left margin of the list file. This is useful if you plan to send the listing to a printer.

Version 3 doesn't have any of the page formatting directives because they have become fairly obsolete nowadays. Therefore the .LM directive is also scrapped from the list of directives.

Explanation:

Usually the lines of a list file begin in the left most column. With the .LM directive you can let each line begin with a number of spaces to create a left margin. The number of spaces used as a margin is determined by the expression that follows the .LM directive. The expression may have a value in the range from 0 to 16.
The setting of the left margin has no effect if the listing is sent to the screen.

The .LM directive will only be evaluated during pass 2 of the assembly process. Any errors in the parameter will be detected in pass 2.

.MA    MAcro definition

Syntax:

macroname    .MA    [comment]
             .MA    macroname [comment]

See also: Macros .DO .EL .EM .FI .XM

Function:

The .MA directive starts the definition of a Macro.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The syntax of the .MA directive has 2 appearances.
The first one above has the more usual notation with the macroname in the label field, followed by the .MA directive in the instruction field. The .MA directive may be followed by comments.
The second notation puts the macroname in the operand field, behind the .MA directive. This notation is not recommended and is only available for compatibility reasons with the Apple ][ version of the SB-Assembler. The macroname may also be followed by comments in this notation.

There is a special reason why I explicitly say that comments are allowed behind the .MA directive. Most directives may be followed by comments, so that's not so special by itself. But here it is particularly useful to add comments to indicate what parameters are expected by the Macro that you're going to define.
Please note that the real parameters are given at the instances where you want the Macro to expand. Here, after the .MA directive they serve only a documentary purpose.

The same rules apply to macroname as for Global label names, with the only exception that a macroname is only remembered up to 31 characters (Version 3 of the SB-Assembler has no length limit). The macroname must start with a character from A to Z, an may contain other characters from A to Z, digits from 0 to 9, the underscore _ and a dot .
The macroname must be a unique Macro name. However it is allowed to give a Macro the same name as a label. Macro names are stored in a separate symbol table.

The following directives are not allowed during the definition of a Macro (from the opening .MA directive until the closing .EM directive):

.MA, .IN, .CH, .BI, .EN, .CO and .EC

In Version 3 of the SB-Assembler the .EN directive is allowed inside a macro definition. When the .EN direcitve is encountered inside an expanding macro it will end all currently expanding macros and the current list file, all at the same time.

With Version 2 of the SB-Assembler new Local label definitions are not allowed after a Macro definition until at least one new Global label is declared.

With Version 2 of the SB-Assembler a fatal error will be reported if the end of a source file is reached while in the middle of defining a Macro with the .MA directive.
Version 3 of the SB-Assembler will automatically insert an .EM directictive if the source file ends during a macro definition, which avoids causing any error.

A detailed description of the Macro capabilities of the SB-Assembler can be found in a separate chapter.

Examples:

Let's define a Macro that exchanges 2 bytes in memory without altering any of the processor's registers on a 6502.

XCHNG    .MA  memory1,memory2
         PHP           ; Save flags register
         PHA           ; Save Accu
         LDA  ]1       ; Get the 1st byte from memory
         PHA           ;  and put it on the stack
         LDA  ]2       ; Copy the 2nd byte to the
         STA  ]1       ;  1st memory location
         PLA           ; Save the 1st byte to 
         STA  ]2       ;  the 2nd memory location
         PLA           ; Restore Accu
         PLP           ; Restore the flags register
         .EM           ; Done

All parameters in the Macro definition have the notation ]x , where x is the parameter number. This parameter number is determined by the location in the operand field of the Macro call. In the example above the parameter ]1 will be replaced by the first parameter memory1. The parameter ]2 will be replaced by the second parameter memory2.

.NO    New Origin

Syntax:

        .NO  expression1[,expression2]

See also: .BS .DU .ED .EP .OR .PH .RF .SM

Function:

The .NO directive is very similar to the .OR directive, yet it has some significant differences.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The effect of this directive is that the program counter is set to the value of expression1. The way that this is done differs significantly from the way the .OR directive would do that. In principle the .NO directive works identical to the .BS directive, with the only difference being the way the block size is defined. With the .BS directive you say how big the skipped block should be in terms of the number of bytes. The .NO directive expects you to specify where the skipped block will end by providing the end address in expression1.

Expression1 may not contain forward referenced labels otherwise a fatal "Undefined label error" will be reported.

The two following program lines will have exactly the same effect:

         .NO  newpc
         .BS  newpc-$

You can determine what should be done with the skipped bytes by supplying the fill value in expression2, just like with the .BS directive.

The value of expression1 may not be less than the current program counter. Values less than the current program counter would otherwise result in very large blocks to be skipped.
The maximum value of expression2 is $FF. Larger values will simply be truncated at the lowest byte before they are used. A value of $100 will fill the skipped memory with the value of $00.

Operation of the .NO directive differs a little between formatted and unformatted target files.
With unformatted target files a filling value is always used, whether expression2 is given or not. If expression2 is omitted the value $00 is used to fill the skipped memory.
With formatted target files a filling value is only used if expression2 is given. Otherwise the skipped memory block will be skipped completely. The current data record will be terminated and a new one is started with the new target address of the address field.
The only exception to this rule is when the number of bytes skipped is less than the line record length of the target file. In that case bytes with the value of $00 are used to fill the skipped memory.

The list file will only contain the first address of the skipped memory block. The filled bytes are not listed in the list file.

Please note that unformatted files rely on the .NO directive to change the program counter because using the .OR directive would close an unformatted file immediately.

Examples:

This is a typical 6502 program to be burned into EPROM. First comes the program together with interrupt routines. Interrupt and reset vectors must be placed at the end of the address space.

         .OR    $F800        Start address of the ROM
NMI      NOP                 The NMI routine
          ;
          ;
          ;
         RTI

IRQ      NOP                 The interrupt request routine
          ;
          ;
          ;
         RTI

RESET    NOP                 The initialization routine
          ;
          ;
          ;
         JMP    AGAIN        End of the program

         .NO    $FFFA,$FF    Skip all unused memory until
;                             the vector space. All skipped
;                             bytes are filled with $FF
         .DA    NMI          The NMI vector
         .DA    RESET        The Reset vector
         .DA    IRQ          The IRQ vector

.OR    ORigin

Syntax:

    .OR  expression

See also: .BS .DU .ED .EP .NO .PH .RF .SM

Function:

The .OR directive is used to set the starting address of a program, a part of the program, or a data block. All following bytes are stored in consecutive addresses, starting at the address specified by expression.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The .OR directive sets both the program counter and target address to the value of the expression.
This effectively switches off a possible patch mode (see .PH directive). A possible dummy mode is also terminated (see .DU directive). In Version 3 of the SB-Assembler the .OR directive will also set the .TA address in sync with the program counter again.

The expression may not contain forward referenced labels otherwise a fatal "Undefined label error" will be reported.

One single assemble run may contain several .OR directives. But some additional rules exist when sending the generated code to an unformatted target file like BIN or HEX.
The .OR directive will close an unformatted target file because these file formats do not support address information. Formatted files do support address information and those files will not be closed by the .OR directive. This implies that you have to use the .OR directive before creating an unformatted file, otherwise you'll end up with an empty target file.
If you do use more than one .OR directive together with unformatted files you'll have to open a new target file every time the .OR directive is used. Therefore you should better use the .NO directive when you're using unformatted target files.
The occurrence of the .OR directive while using formatted files will flush the current target line buffer to the target file and a new target line is started with the new address in the address field.

Due to several questions from users I decided to change (read: improve) the behaviour of the .OR directive in combination with unformatted files. As from software version 2.07 it is now allowed to start an unformatted file before setting the .OR address, but only if the unformatted file is still empty when the .OR directive is encountered. However if the .OR directive is used when the unformatted file is not empty it will still close the target file, there is no way to prevent that!
Version 3 of the SB-Assembler also behaves in this improved way with regard to unformatted files. Version 3 also gives the user a warning when an unformatted file is closed by the .OR directive. Version 2 closes unformatted files without a warning!

It goes without saying that the programmer is responsible to prevent overlapping of memory spaces when multiple .OR directives are used in one assembly run. The SB-Assembler will not protest if you reset the target address to an already used location of memory.
When writing a program that has to run in bank switched memory you better use the .PH directive instead of using the .OR directive to reset the program counter every time you want to start again from the beginning of the bank switched memory area.
If you insist on using the .OR directive for bank switched memory applications you should store every overlay in a separate target file.
With Version 3 of the SB-Asembler you may also use the .OR directive in combination with the .TA directive.

Examples:

         .OR   $1000    Store program from $1000 upwards
          ;
          ;
          ;

         .OR   $2000    Continue from address $2000
          ;
          ;
          ;

         .OR   $0000    You can also continue at lower addresses
          ;
          ;
          ;

.PG    PaGe

Syntax:

        .PG  [expression]

See also: .EJ .LM .TI

Function:

The .PG directive will force the listing to start on a new page in the list file or list device. The title, set by the .TI directive, will be printed on top of that new page along with the page number. The printing of the title and page number on top of the new page is the only difference with the .EJ directive.

Version 3 of the SB-Assembler no longer supports page formatting. Therefore the .PG directive has been omitted there.

Explanation:

If a title is defined by a .TI directive it will be printed on the first line of the new page, along with the page number.

If expression is given the new page will be numbered with the value of the expression. The expression should not be more than 9 spaces away from the .PG directive to be evaluated, otherwise it will be treated as a comment.
The high word of the expression's value will not be included in the page number and is assumed to be 0. The largest page number that can be used is 65535, which should be more than sufficient I think.

A source line containing the .PG directive will never be listed in the list file itself, unless an error is encountered on that line.
A source line containing the .PG directive will only be evaluated in the second pass of the assembly process.

.PH    PatcH

Syntax:

        .PH  expression

See also: .BS .DU .ED .EP .NO .OR .RF .SM

Function:

The .PH directive will switch over to the patch mode. The current program counter is saved during patch mode. The saved program counter will still count up for every byte that is saved to the target file in the background. At the same time a new, temporary, program counter is selected. The .EP directive switches off the patch mode and replaces the temporary program counter with the original one again.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The expression may not contain forward referenced labels otherwise a fatal "Undefined label error" will be reported.

A previous patch mode will be automatically closed when a new patch mode is initiated. This allows you to write multiple patch routines in a row, where each patch routine gets its own address space.

Please note that the .OR directive also terminates an active patch mode automatically.

The patch mode is typically used to generate pieces of code that are moved to a different memory location by the processor before it is used as code. All labels that are defined during the patch mode automatically get the appropriate values as if the code really was generated at the intended address. In the mean time the code is saved to the target file in a consecutive order as if the program counter was not changed.

Originally the patch mode was intended to write some patch routines that should be copied into an existing program by a simple move routine, hence it's name.

Another useful application for the patch mode is writing code that is supposed to start at e.g. address $8000 of the target system, but should be burned to an EPROM starting at address $0000. You can't simply use .OR $0000 because that would produce erratic destination addresses for jumps, calls and memory access instructions.
The patch mode can solve this little dilemma by first setting .OR $0000 and then set .PH $8000. Code will be saved to the target file starting at address $0000. But the SB-Assembler pretends to generate code that originates at address $8000.

The patch mode can also be used to write programs that should run in bank switched memory.
Imagine a system that has 4 banks of memory mapped in the address space from $0800 to $0FFF. The first time you can simply set the .OR to $0800. The code is sent to the target file starting at address $0800. But if you want to program the next memory block you can't use .OR $0800 again because that would effectively overwrite the code of the previous block of memory, which also started at $0800.
Example 2 explains how this can be solved by using the .PH directive.

A label declared on the line cotaining the .PH directive will get the value of the real program counter, not the modified program counter. This simplifies calculation of the beginning and the length of the piece of patch code.
Thus when a patch mode is active and a new .PH line is found, with a label in the label field, the label will get the real program counter's value, not the value it would get from the previous patch code block.

Version 3 of the SB-Assembler has the more convenient .TA directive which can be used for mapping code to the appropriate ROM locations.

Example 1:

Imagine a piece of 6502 program that should be copied to RAM memory to allow direct changing of addresses used by instructions.

8000-                   .OR  $8000         Begin of program
8000-A0 0A    INSTALL   LDY  #NEXT-PATCH1  Calc. length of patch
8002-B9 0C 80 .LOOP     LDA  PATCH,Y       Get byte from ROM
8005-99 00 20           STA  RAM,Y          and put it in RAM
8008-88                 DEY                Decrement length counter
8009-10 F7              BPL  .LOOP         Repeat while Y>=0
800B-60                 RTS
800C-
800C-         PATCH     .PH  $2000         Destination of patch routine
2000-48       RAM       PHA                Save Accu on stack
2001-AD 00 00           LDA  $0000         Address may be changed
;                                           dynamically because it's
;                                           stored in RAM now
2004-38       .LOOP     NOP                Any other code goes here
2005-68                 PLA                Restore Accu
2006-60                 RTS
2007-                   .EP                End of patch routine
8013-
8013-EA       NEXT      NOP                The rest of ROM code

Explanation: The INSTALL routine copies the patch routine to RAM location starting at address $2000. In this case the patch routine may not be longer than 127 bytes to simplify the copy loop. The first thing that's done is calculating the length of the routine that has to be moved by subtracting the end address of the patch routine in ROM ($8013) from the begin address of the patch routine in ROM ($800C, and not $2000!). Then the patch routine is copied to RAM byte by byte.
The labels defined in the patch routine get the value as if the routine was already copied to its RAM location. The label RAM gets the value of $2000 and the Local label .LOOP is assigned the value $2004. In reality however the object bytes of the patch routine generated by the assembler are stored in the normal sequence at the addresses $800C to $8012, in ROM.

Example 2:

Imagine you want to create a program for the 8048 processor which can address only 4 kb of ROM memory. But you want to increase to ROM addressing range to 8 kb by using bank switching. The memory range $0000 to $07FF (2 kb) is always available. The memory range from $0800 to $0FFF is available 3 times in 3 different banks. Two I/O lines control what bank is selected.

0000-            .OR  $000        Begin of bank 0
                  ;               Here come universal
                  ;                routines, the interrupt
                  ;                service routines and bank
                  ;                switch routines.
                 .NO  $800,$FF    Fill bank 0 with $FF

0800-            NOP               Bank 1.1 starts at $0800,
                  ;                No special attention is
                  ;                 required yet to do that.
                  ;                Here comes the code
                  ;                 of bank 1.1
                 .NO  $FFF,$FF     Fill bank 1.1 with $FF

1000-            .PH  $800         Bank 1.2 again starts at
0800-             ;                 address $0800. But this time
                  ;                 the target address in the
                  ;                 object file continues normally
                  ;                 from $1000 where we are now.
                  ;                Here comes the code of bank 1.2
                 .NO  $FFF,$FF     Fill bank 1.2 with $FF
1000-            .EP               (.EP is optional here)

1800-            .PH  $800         Bank 1.3 also starts at
0800-             ;                 address $0800. The target
                  ;                 address still continues which
                  ;                 is $1800 now.
                  ;                Here comes the code of bank 1.3
                 .NO  $FFF,$FF     Fill bank 1.3 with $FF
                 .EP               End of bank 1.3

Explanation: Bank 0 of the program is nothing special from the SB-Assembler's point of view. Bank 0 contains some universal routines, interrupt service routines and bank switch routines. Bank 0 is always available to the target processor.
Bank 1.1 is a normal bank 1 which can be coded as usual. The bank starts at address $0800, immediately following bank 0. The bank continues to address $0FFF. The .NO directive fills the unused portion of bank 1.1 with $FF.
Bank 1.2 should also start at address $0800, at least the 8048 must think it does. But the address space from $0800 to $0FFF is already used in the EPROM. But by using the .PH directive we can pretend to start at address $0800 again, while in reality the code continues to be stored from address $1000 onward.
The procedure for bank 1.3 is equal to that for bank 1.2, with the only difference being the target address in EPROM that has grown to $1800.

Please note that switching from bank 1.2 to bank 1.3 does not necessarily require the .EP directive. The .PH directive would have automatically executed an .EP directive.
The last bank does not have to be filled completely because there are no more banks following it. Also the last .EP is optional. It is allowed to end the program without ending the patch mode first.

This example works for formatted and unformatted target files because all banks are filled completely by using the .NO directives at the end of every bank.
It is also possible to use the .OR directive instead of the .NO directive to start the new bank. In that case we can't use unformatted files however.

.RF    Random Fill

Syntax:

          .RF  expression1,[expression2]

See also: .AS .AT .AZ .DA .DB .DL .DR .DW .HS .TS

Function:

The .RF directive can fill a portion of memory with randomly generated bytes. This can be useful for software security.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

The expression1 indicates the number of bytes that should be filled with randomly generated values. Expression1 may not contain any forward referenced labels. Expression1 may not be a negative number.

The optional expression2 can be used as a seed value for the pseudo random number generator. If expression2 is not used the pseudo random bytes generated are different every time the source file is assembled. By specifying the seed you can generate the same pseudo random sequence time after time. In Version 2 of the SB-Assemble the seed value is truncated to the lower 16 bits. In Version 3 the entire value is used as seed value.

In Version 2 of the SB-Assembler the pseudo random sequence will repeat itself after 65536 generated bytes. This is not a big problem for I can't think of an application that would require more random bytes than that.
In Version 3 of the SB-Assembler the pseudo random sequence will repeat itself after 6,953,607,871,644 bytes, thanks to Python's better pseudo random number generator.

Because of the totally different pseudo random number generators of Version 2 and 3 of the SB-Assembler, they will not generate the same pseudo random number sequences when both seeded with the same seed.

Examples:

For example the single chip processor 8051 (or its relatives) provide a few security levels to prevent software piracy. One of these levels of security encrypt the ROM contents when read by a programmer. Without the correct encryption key sequence this information is useless.
The encryption system of the 8051 uses a 32 byte encryption key. All bytes read are EXNORred with one of those key bytes. The keys are used in sequence over and over again. Now imagine that only 3 kB of the 4 kB program space is used in your 8051 system. That would leave an empty space of 1 kB in your ROM. If you don't put something in there all bytes from that empty space will read $FF. Using the encryption system will EXNOR all these $FF bytes with the encryption key sequence, resulting in exactly the encryption key sequence repeating over and over again every 32 bytes!
All a potential software pirate has to do is check to see if a 32 byte sequence repeats itself at the end of the program space to find out what your encryption key sequence is. Knowing the encryption key sequence he is now capable of decoding your program again.
Filling the unused portion of your ROM with randomly generated bytes can easily fill this security hole. I don't say that it will become impossible to break your code if you do, but you will make it a lot harder for the software pirate to obtain your life's work.

Examples:

         .RF  $1000-$     Fill up to 4kb with random numbers

.SE    SEt variable

Syntax:

label   .SE  expression

See also: .EQ

Function:

With the .SE directive you can declare and change a variable value to a label.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

Normally only constant values are assigned to labels. Once a particular value is assigned to a label it can not be changed anymore.
The .SE directive allows you to declare a label with a variable value. You can change the value as often as you want. For example this may come in handy for counters, intermediate results and for complex expressions.

The syntax for the .SE directive is almost identical to the syntax for the .EQ directive. The only difference is that the .SE directive only allows you to use Global labels. This means that the label name should start with a letter from A to Z.
The expression may not contain forward referenced labels.
A variable label must be declared using the .SE directive. A label that is declared automatically or by the .EQ directive can not be changed to a variable anymore. Once the .SE directive declared a label as a variable label it is not possible to give it a new value with the .EQ directive anymore. New values can only be given using the .SE directive.
Variable labels may have different values in pass 1 and pass 2. They don't have to be in sync with each other.

After the definition of a variable label it is not possible to declare or use Local or Macro labels until the next declaration of a normal Global label. Subsequent changes to the value using the .SE directive are transparent to the use of Local and Macro labels.

The values of variable labels are not printed in the Symbol table because their value is not necessarily constant throughout the entire program.

See to it that a variable is declared during pass 1 of the assembly process, because new labels can't be added to the Symbol table in pass 2 anymore.

A variable can not be used as a forward referenced value. This means that the current value is always used, not the value that the variable may have in the future.

Examples:

The 8048 processor does not allow lookup tables to cross a memory page boundary. This means that the most significant byte of the address must remain the same for the beginning of the table and the last byte in the table. Two Macros are working together to see if a table does not cross a page boundary.
The first Macro simply remembers the start memory page of the table. The second Macro's task is to see if that value hasn't changed.

OPEN      .MA
BEGIN     .SE   $/256              ; Remember the page
          .EM

CLOSE     .MA
          .XM   $/256=BEGIN        ; Quit macro if page is equal
          .DO   $*$1000000*?       ; Do only if LSB<>0 and pass 2
          .ER   *** Table page error
          .FI
          .EM

I agree that the second Macro calls for some extra explanation. The .XM directive will terminate the Macro's expansion immediately if the current memory page is equal to the value stored in the variable label BEGIN. If the pages are different we'll continue with the Macro.
The expression of the .DO directive is somewhat strange. But this is what it does. It multiplies the current location counter ($) by $1000000. This will result in a value that is 0 only if the least significant byte of the current location counter was 0. Remember that calculations in the SB-Assembler have an internal resolution of 32 bits and it won't warn you for overflows. This is a perfect example of a situation where we can take advantage of that. The overflowed value is simply ignored.
If this result is 0 the whole expression will be 0 as well (multiplying by 0 always results in 0). Thus the .DO expression is false and the next line is not assembled.
The purpose of the .DO directive here is to prevent an error message if the lowest byte of the location counter is 0 at the end of the table. In that case the last byte was stored on the last byte of the previous memory page, which still is OK even though the upper byte of the location counter differs.
The expression following the .DO directive also remains 0 if we're still at pass 1 of the assembly process. This allows us to see other, more severe errors before we have to change the table's start address.

Please note that these two Macros may be used as often as you like because the value of BEGIN may be changed over and over again. This would not have been possible using the .EQ directive.
Also note that Macro labels wouldn't have solved our problem either because they can't span across multiple Macros.

PS: This is only an example to demonstrate the use of variables. The problem presented here is so common for the 8048 that I have included 2 dedicated directives in 8048 family Cross Overlays to replace these 2 Macros (.OT and .CT).

.SF    Symbol File

Syntax:

        .SF  filename[.ext]

See also: .CP .EF .LF .LI .TF .TW

Function:

The .SF directive allows you to create a Symbol file at the end of the assembly process.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The symbol file lists all Global constant labels followed by .EQ directives and their value. Such a Symbol file could be used to transfer all constants from one program into another program for linking purposes.
Please note that no Local labels or Macro labels are included in the Symbol file.

The Symbol table is opened by the .SF directive in pass 2 of the assembly process and will only be filled with the symbols at the end of pass 2. Therefore errors are only recognized in pass 2.

As usual drive letter (on DOS/Windwos machines) and path are allowed together with the filename. The extension .ext is optional. The default extension is .sym .
An already existing file with the name filename will be overwritten without prior notice.
Only in Version 2 of the SB-Assembler the Symbol file may also be directed to a device instead of a file like PRN:, LPT1: or COM1:

The .SF directive may only be used once in a program.

In version 3 local labels are also listed to the symbol file, grouped together with their parrent global label. Macro labels are not listed though. The comment field in the symbol file will hold the number of references to the particular label and the source file it was declared in.

.SM    Select Memory

Syntax:

        .SM  code¦ram¦eeprom

See also: .BS .DU .ED .EP .NO .OR .PH .RF

Function:

Version 3 of the SB-Assembler allows you to split memory into 3 major segments. Per default you are using CODE memory, just like version 2 would have known it. However now you can also select RAM or EEPROM memory.
Both CODE and EEPROM memory can have a target file open simultaneously. This allows you to write a pice of code to CODE memory, switch to EEPROM memory and declare some pre-set values there, and switch back to CODEmemory to continue there with your program. You can switch back and forth between CODE, EEPROM and RAM memory as often as you want during an assembly run. In the end you will have two target files, one containing the CODE memory and another one with EEPROM memory data in it.
The RAM memory segment can't save any data. It is only intended to assign memory locations in a convenient way, without the need of the error prone .DU mode.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

A total of 3 different memory segments are supported as of version 3 of the SB-Assembler.

  • CODE memory is the default segment and is inteded to write program code to (just as version 2 of the SB-Assembler would have done it). CODE memory has its own address space and target file (or files). Some processors write more than one byte per instruction to the target file. This implies that the target addres can grow faster than the program pointer.
  • EEPROM memory is intended for data which has to be written to EEPROM memory. It may only contain data. No program instructions are allowed in EEPROM memory. It has its own address space and target file (or files). EEPROM memory is always byte sized, which means that the program counter is always in sync with the target address.
  • RAM memory is intended for memory definitions. No data can be saved in the RAM segment! It has its own address space, but since no data can be written a target file is not allowed.

Each of the 3 memory segments has its own address space. This means that you can setup 3 different .OR addresses, one for each memory segment. Now you can switch back and forth between these three memory segments as often as you want. Declare some RAM, write some code, declare some more RAM, save some pre-set values to EEPROM memory, write some more code, declare some memory space to EEPROM memory, etc, etc.

A line containing the .SM directive must have an empty label field. An error is reported if the label field is not empty.

Please note that you can not write CODE memory and EEPROM memory to the same target file. If you use CODE and EEPROM segments you will always have to use (at least) 2 different target files.

Example:

The following piece of code demonstrates the use of memory segments. First a piece of RAM memory is defined. RAM starts at $8000 here and 2 labels are defined in RAM space, the first one spanning 2 bytes, the second one only one byte. You don't have to, or better yet, you can't open a target file while in the RAM memory segment.
Then we switch to EEPROM memory. A new target file is opened and the starting address and the target address of the EEPROM memory is defined. Then some values are saved to the EEPROM target file.
Code memory is next in line. A new target file is opened, while the EEPROM target file is still open but not accessible at this moment. And a new starting address for CODE memory is defined. Then we start our code, which is written to the CODE target file.
Then we switch back to the EEPROM memory segment, which makes the EEPROM address space and the EEPROM target file active again. Some more data bytes are written to the EEPROM target file, a block of memory is declared without writing data to it, and some more data is written.
After that the RAM memory segment is selected again, using RAM address space and no target files now. A few more bytes are assigned in RAM space here.
And finally we switch to CODE memory again. From here we use the CODE memory address space and target file again.

You can switch back and forth between the different segments as often as you want. And each time the appropriate address space and target file is automatically selected.

        .SM     RAM
        .OR     $8000
POINTER .BS     2       Declare a 2 byte pointer in RAM
COUNTER .BS     1       Declare a 1 byte counter in RAM

        .SM     EEPROM
        .TF     EEPROMFILE.HEX,INT Write EEPROM data here
        .OR     $1000   Begin of EEPROM memory
        .TA     $0000   Write data from address $0000
IP_ADDR .DA     #192,#168,#1,#200   Set default IP address
IP_MASK .DA     #255,#255,#255,#0   Set default net mask

        .SM     CODE
        .TF     CODEFILE.HEX,INT Write Code data here
        .OR     $0000   Begin of Code memory
RESET   JMP     INIT    Get the system started
NMI     JMP     DO_NMI  Handle non maskable interrupts
         :
         :
         :
        RET             End of some code

        .SM     EEPROM  Write some more data to EEPROM
SERVER  .AZ     /www.sbprojects.com/
NV_BUF  .BS     40      Reserve a 40 byte block of memory
URL     .AZ     \www.sbprojects.com/sbasm\

        .SM     RAM     Define some more RAM bytes
BUFFER  .BS     40      Reserve a 40 byte block of memory
BUFPNTR .BS     1       Reserve 1 byte buffer pointer

        .SM     CODE    Continue code memory
INIT    NOP             Get the system started
         :
         :
        RET             End of some code

.ST    STop

Syntax:

        .ST  [stopmessage]

See also: .CO .EB .EC .EN .ER

Function:

The .ST directive is used to stop the assembly process temporarily. A message is displayed on the screen and the SB-Assembler waits until the operator presses almost any key.
This could be used for example to prompt the operator to insert another disk.

The function of this directive has become fairly obsolete now adays. Therefore the .ST directive is no longer available in Version 3 of the SB-Assembler.

Explanation:

If no stopmessage is given the assembler will display the default stop message "Press almost any key to continue". Otherwise the text following the .ST directive will be displayed up to a maximum length of 79 characters. This limits the maximum length of the stop message to one line on the screen.

The stopmessage will be erased from the screen when the operator presses almost any key and then the assembly process will resume.
Except when the ESC key is pressed, in which case the assembly process is completely terminated. This is also true if the operator normally presses the ESC key during an assembly process.

Source lines that contain the .ST directive will never be listed in the list file and can not hold comments. All text following the .ST directive is considered to be the stopmessage.

Examples:

Prompt the operator for a new disk:

         .ST  Insert disk 2 and press any key

Warning! Don't use the drive that must hold different disks for writing target files, error files, or what ever other generated files to! This could even destroy the contents of the diskette written to.

.TA    Target Address

Syntax:

         .TA  expression

Function:

In Version 2 of the SB-Assembler this is an obsolete directive, originating from the Apple version of the SB-Assembler.
In Version 3 of the SB-Assembler this directive is used to set the target address in the formatted output file.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

This directive was used on the Apple ][ version of the SB-Assembler to send generated code directly to memory, where it could be started directly. This is never possible on the PC however.

In Version 2 of the SB-Assembler this directive will always report the "Not implemented in MS-DOS version error" message.

In Version 3 of the SB-Assembler this directive is reinstated and will set the target address of the formatted target file. Normally the current program counter is equal to the addresses in the target file. Some processors however don't start their programs at address $0000. For the 6502 for instance ROM memory is mapped somewhere at the end of the address space. Thus the program may start at $C000 for instance. However the EPROM address spaces always starts at address $0000.
Up until Version 2 of the SB-Assembler this could be solved by using the .PH directive following the .OR directive. Thus there the program counter was set to $0000, and an offset of $C000 was added to that to let the processor think the ROM started at $C000. This was the only way to solve the above problem in Version 2 of the SB-Assembler.

In Version 3 of the SB-Assembler you may now solve the above problem in a more natural way. Simply set the .OR to the real starting address of your program ($C000 in the example above), and then change the target address to $0000. Now the assembler will still generate code for the intended address range, while the target file is correctly written from address $0000 and upwards.

Each time a byte is written to the target file, the target address is incremented. Therefore the program counter and the target address counter will remain in sync with each other.
Some processors store 2 bytes per program instruction. Others may even store 3 or more bytes per program instruction. In these cases the target counter will still be incremented with every byte written to the target file. However the program counter is incremented only once per instruction. In these cases the target file will grow twice as fast as the program counter (or even 3 times faster, or more on some processors). Be aware of this when you set the target address! When a processor stores 2 bytes per instruction always set the target address 2x higher than the program counter. The SB-Assembler simply obeys your orders, and will not complain if you mess up the target addresses!

The .OR directive will set the target address to the new program counter multiplied with the number of bytes stored per instruction. This is normally exactly what you want, unless you want to change the target address to reflect propper ROM alignment.

.TF    Target File

Syntax:

        .TF  [filename.ext[,format[,expression]]]

See also: .CP .EF .LF .LI .SF .TW

Function:

With the .TF directive you can open a target file in any of the available formats. This target file will be filled with the generated object code of your program.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

The .TF directive, without parameters, will close an already open target file. Nothing will happen if no target file is open at that time.
If you want to include a comment behind an empty .TF directive a semicolon should precede this comment.

If a filename does follow the .TF directive an already open target file will also be closed. Then a new target file is created with the name filename. If that file already exists its length will be reduced to zero, effectively overwriting the file without prior notice!
As usual the filename may be preceded by a drive letter and legal path name, obeying the file name rules of your operating system. The SB-Assembler will NOT provide a default extension with target files if you don't provide one. If you omit the extension .ext the created filename will not have an extension.

TIP: To avoid problems with other MS-DOS programs I advise you not to use the extensions .COM, .BAT, .EXE or .OBJ for your target files. The use of the extension .ASM for your target files will also cause confusion you clearly can do without. It could cause your source file to be overwritten accidentally.

Some target file formats won't allow you to create programs that are larger than 64 k bytes, provided that the maximum address used is not greater than $FFFF. So if you start your program at $F000 your program can't be any bigger than 4 k bytes!
There is no limit to the number of target files used during one assembly run. You can have as many target files filled with part of your program as you like. Only one of those target files will be open at any given time. Every time you open a new target file the previous one is closed.

Other target file formats allow you to create programs up to 4 G bytes, which will be sufficient for the next few years from now ;-)
The unformatted files BIN and HEX don't have an address field and can grow as large as your file system allows it.
Motorola has designed 3 different file formats, each with their own limit to file size. The address range for the S19 format is only 64 k bytes and so is the maximum file size. For format S28 the maximum address range is 16 M bytes (24 bits address). Finally the maximum file size for the S37 format is 4 G bytes (32 bits address).
The FPC file format is standard equipped with a 32 bit address range, so that file format is automatically capable of handling file sizes of 4 G bytes.
The Intel Hex file format originally has an address range of only 64 k bytes. When Intel noticed that this was not enough they invented some extensions to overcome this 64 k limit.
The first method of having larger file sizes was the use of segments, like in 80x86 processors. Every segment still can hold up to 64 k bytes. But at every 16 byte interval you can start a new segment of 64 k again. This could be quite useful for 80x86 processors, but is particularly difficult to handle for other processors because program counter and target address will be out of sync without obvious relation. The maximum target file size for segmented Intel Hex files is 1 M bytes.
The second solution they came up with at Intel is somewhat easier to comprehend. This solution uses linear segments. Again every segment is still 64 k bytes long. But at the end of this segment a new linear segment is started. Up to 64 k segments of 64 k bytes each can be used, which in fact is a 32 bit addressing range resulting in a maximum target file size of 4 G bytes.
The SB-Assembler can handle linear segmented Intel Hex files. Every time a segment boundary is crossed a new segment is started automatically.

Please note that all bytes generated by the program will be lost when no target file is open yet.

Warning: If the file filename already exists its contents will be erased and overwritten without prior notice.

In Version 2 of the SB-Assembler it is also possible to send the target file to a device, instead of to a file. That way you can send your object code directly to a programmer or EPROM simulator. A device name should always end in a colon. All MS-DOS device names are allowed like PRN:, LPT1:, COM1:, NUL:. Avoid sending the object file to the screen (CON:) however, it will only cause a lot of gibberish to be displayed there.

The file format following the filename is optional. If it is not provided the default BIN format is used.

Please note: The .OR directive will close the unformatted file types BIN and plain HEX immediately because they don't support an address field. Please specify the start of the program before opening the target file if you intend to use one of these two file formats. If, for any reason, you do have to change the start address of the next code you can always use the .NO directive.
With all other file formats you may change the program address as often as you like.

These are the possible file format names:

AP1Apple 1 format
BINBinary format
E52Elektor EMON52 format (not a standard format!)
HEXHexadecimal format (every byte is translated to 2 hexadecimal digits coded in ASCII)
S19Motorola S19 format (64 kb range)
S28Motorola S28 format (16 Mb range)
S37Motorola S37 format (4 Gb range)
INTIntel Hex format (No opening segment if segment 0)
INSIntel Hex format (Always opening segment included)
SIGSignetics format
TEKTektronix format
FPCFour Packed Code format

What format you can use best depends on the capabilities of your EPROM programming device. I prefer the FPC format because it produces the most compact formatted target files. Unfortunately not many EPROM programmers support that code though.
The desired format is entered behind the filename, separated by a comma. Your choice is made by entering one of the 3 letter format names shown above.
The difference between the INT and INS formats applies only to the very first line sent to the target file. If the first address of your target file requires a segment of 0, the INT format will not include a segment definition line in your target file. This is useful for programs that don't grow larger than 64k, no segmentation is required there anyway. If you use the INS format the first line of the target file is always a segment address definition, even if it is segment 0.

The format identifier may also be followed by an expression, separated by an other comma. This expression defines the maximum number of data bytes you want to have on each line in your target file. Only BIN files don't provide for this because they don't consist of lines.
Legal values for expression range from 8 to 32. Lower values will be increased to 8, higher values will be reduced to 32. If the optional expression is omitted the default line length will be 16 data bytes long.

The syntax of the .TF directive will only be checked during pass 2 of the assembling process. An existing file with the name filename will not be erased and overwritten before pass 2. So if any errors are encountered during pass 1 the old target file(s) will still exist unchanged.

All errors that occur in the parameter field of the .TF directive will result in a fatal error message to be reported. This will stop the assembly process immediately.

Examples:

         .TF   C:\OBJ\TARGET.BIN     Open BIN file (BIN is default)
         .TF   C:\OBJ\TARGET         Open BIN file (no extension)
         .TF   TARGET.BIN,BIN        Open BIN file
         .TF   TARGET.TXT,AP1,8      Open Apple 1 format
         .TF   TARGET.HEX,E52        Open EMON52 file
         .TF   TARGET.HEX,HEX        Open HEX file
         .TF   TARGET.INT,INT,32     Open INT file (32 bytes/line)
         .TF   TARGET.INT,INS        Open INS file
         .TF   TARGET.MOT,S19,8      Open S19 file (8 bytes/line)
         .TF   TARGET.MOT,S28        Open S28 file
         .TF   TARGET.MOT,S37        Open S37 file
         .TF   TARGET.SIG,SIG,0      Open SIG file (8 bytes/line)
         .TF   TARGET.TEK,TEK,100    Open TEK file (32 bytes/line)
         .TF   TARGET.FPC,FPC        Open FPC file
         .TF   TARGET.MOT,INT        Confusing, but legal
         .TF   TARGET.BIN,BIN,10     Legal, but length irrelevant
         .TF                         ; Close previous target file
         .TF   COM1:,INT,32          Send object to COM1:

Note on the Apple 1 format: Vince Briel started some sort of Apple 1 fever around the 30th anniversary of this legendarily computer. The original Apple 1 has only the cassette recorder as mass storage. However it is possible to expand the original Apple 1 with a serial interface and several replica versions are standard equipped with a similar serial interface.
All these serial interfaces have one thing in common: Everything received is literally "typed" to the Apple 1. This behaviour allows us to simply send a file to the Apple 1. And that is exactly what the Apple 1 format is meant for. Each line starts with an address, followed by a colon, which is then followed by the data bytes. Just like you would have done to manually type the code to the Apple 1.

.TI    TItle

Syntax:

        TI  [S],[expression[,title]]

See also: .EJ .LM .PG

Function:

In Verison 2 of the SB-Assembler the .TI directive is used to set the page length and title for each page in the list file.
Version 3 of the SB-Assembler doesn't support any page formatting, therefore the .TI is missing here.

Explanation:

If only the .TI directive is given on a source line, or when the text following the .TI directive is more than 9 spaces away from it, all default parameters are set. This means that the Single Sheet mode is switched off, the page length is set to infinite and the title is erased. The infinite page length implies that no form feeds are inserted after a certain number of lines.
Please note that these are the default settings for list files. So these settings also apply if no .TI directive is present in your source file.

The Single Sheet mode is selected if the first character of the operand field is a single S, or an S followed by a comma. This means that the SB-Assembler will wait for the operator to insert a new page in the printer when the previous page is full. The user is prompted to press almost any key when the new page is loaded in the printer with the message: "Insert new sheet and press any key".
The SB-Assembler will not ask you to insert the first sheet of paper though. So the operator should provide the first sheet before starting the SB-Assembler.
Please note that this function was included when ink jet and laser printers were not as common as they are today. The Single Sheet mode is a bit outdated nowadays.

The expression defines the number of lines that are to be printed on a page in the list file. The minimum number of lines is 8, the maximum number is 254. All other values result in a "range error" to be reported.
A form feed is generated every time the number of lines reaches the pre-set value, starting a new page. The title and a page number is printed above each new page.

The title can be any piece of text, up to 127 characters in length. The title is treated as literal text, where case and spaces are not changed. The title is always printed above each new page in the list file. It does not matter if that page is started automatically or was forced by the .PG directive.
The .TI directive will force a new page to be started with the new title printed above it.

The title may be changed as often as you want during the assembly. Every time you change the title, using the .TI directive, a new page is started with the new title above it.

The .TI directive is never listed in a listing file itself. Therefore it does not accept comments. Everything following the title will be treated as part of the title itself.

The .TI directive is only parsed during pass 2 of the assembly process. Errors will not be discovered during pass 1.

Examples:

; Set the list page length to 55 lines, without a title
         .TI  55

; Set the page length to 55 lines, with title
         .TI  55,This is the title

; Set the page length to 40 lines, with title and
; Single Sheet mode
         .TI  S,40,New title

; Switch off auto page mode and titles.
         .TI

.TS    Time Stamp

Syntax:

        .TS

See also: .AS .AT .AZ .DA .DB .DL .DR .DW .HS .RF

Function:

This directive is new to version 3. It write a time stamp string to the target file.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will not perform a boundary sync.

Explanation:

A time stamp string can be written to your target file by using the .TS directive. The system time at the start of the current assembly run is taken as time stamp. This means that you can use .TS as often as you want, generating the same time stamp throughout the entire program.
.TS will write a 23 character time stamp to your target file in the format "DOW YYY-MM-DD HH:MM:SS". An example would be Sat 2013-05-25 16:54:24.

.TW    Target Write

Syntax:

         TW  string¦#expression[,string¦#expression[,...]]

See also: .CP .EF .LF .LI .SF .TF

Function:

This directive allows you to write strings of text directly to the target file.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

This command will flush the current target file's line buffer and then it writes a string directly to the file. The string can be anything, but usually holds some remarks or programming device commands.

I can think of two main reasons why you would want to write to the target file directly.
The first reason is to enter some comments in the target file. Be careful though, not all programming devices allow you to enter comments in the target file. Comment lines usually begin with a single quote or an exclamation point.
The second reason is to embed programming device commands directly in the target file. This way the target file can be sent directly to the programming device during assembly. Remember though to remove the commands from the target file if you intend to share it with others who don't have such sophisticated programming devices.

The syntax of the .TW directive is somewhat comparable with that of the .AS directive, with the only exception that it is not possible to create strings with a negative ASCII polarity. You may use either a delimited string, or a separate byte per parameter. Multiple parameters must be separated by commas.
You may even use characters from the extended IBM character set if you like.

Please note that strings are not terminated with a CR or LF automatically in version 2! If you do want to end the string with a CR/LF pair you will have to enter them as normal byte parameters.
Version 3 will write an End Of Line at the end of each .TW string.

This directive should be used with some care because you can make the target file useless if you write something to it that your programming device doesn't understand. Also be very careful not to write directly to a binary formatted file because they rarely allow comments or other commands.

Strings may not be empty and must be terminated by the same delimiter that was used to start the string, otherwise an error will reported.
Bytes must evaluate to a value of 0 to 255, otherwise you'll get a "Range error".

The .TW directive is only parsed during pass 2 of the assembly process. Errors will not be discovered during pass 1.

Please note that it is not possible to put comments or commands at the absolute end of the target file, unless the target file is a binary or HEX unformatted file. The reason for this is very simple. The "end of file" line is only written just before the target file is closed. Therefore the "end of file" line is always the last line to be written to the target file, simply because the file is closed immediately afterwards. And you can't write to an already closed file anymore.
This may cause some problems if your programming device requires some instructions to be given at the very end. Usually these problems occur only when the target file is sent directly to the COM port. In that case we can simply overcome the problem by reopening an new target file to the COM port, this time as binary format.

With version 3 it is no longer possible for .TW to write to onformatted binary files.

Examples:

         .TF   TWTEST.HEX,INT
         .AS   /Test/
         .TW   /'Remark line/,#$0D,#$0A
         .AS   /Test/

The program above generates the target file below:

:04000000546573745C
'Remark Line
:040004005465737458
:00000001FF

Omitting the #$0D,#$0A part of the .TW directive in the example above would result in the probably useless file below:

:04000000546573745C
'Remark Line:040004005465737458
:00000001FF

Please note that the program below will generate a remark line just before the "end of file" record in the target file. The "end of file" line is always the last line of the target file!

         .TF   TWTEST.HEX,INT
         .AS   /Test/
         .AS   /Test/
         .TW   /'Remark line/,#$0D,#$0A
:04000000546573745C
:040004005465737458
'Remark Line
:00000001FF

.XM    eXit Macro

Syntax:

        .XM  [expression]

See also: Macros .DO .EL .EM .FI .MA

Function:

The .XM directive prematurely exits an expanding Macro. This premature exit can be caused conditionally or unconditionally.

Boundary Sync:

In Version 3 of the SB-Assembler this directive will perform a boundary sync.

Explanation:

If the optional expression is omitted the .XM directive will prematurely exit the expanding Macro. If the expression is given the expanding Macro will be terminated when the expression evaluates to be true, i.e. unequal to 0.

The expression may not contain any forward referenced labels. The expression must follow the .XM directive within 9 or 10 spaces, otherwise it is treated as comment.

The unconditional exit is normally only used in co-operation with conditional assembly directives .DO, .EL and .FI. Without any of these conditional directives the use of an unconditional .XM does not make much sense.
This presents us with a little problem. If the condition is started inside the Macro, which it usually is, then the .XM directive will immediately terminate the Macro. Therefore the .FI directive, which is also part of the Macro, will never be executed. This results in a corrupted conditional stack which holds all pending true and false conditions. That is why the .XM directive will pop one condition from the condition stack, like the .FI directive would have done.
Please note that the .FI directive itself is still required to terminate the conditional part correctly in case the condition was not true! The .FI directive normally must directly follow the unconditional .XM directive in your source file. Any instructions between those two directives would never be interpreted anyway, the condition behind the .XM directive is false, remember.

A detailed description of the Macro capabilities of the SB-Assembler can be found in a separate chapter.

Examples:

The following example shows us a Macro that can push up to 3 registers on the processors stack. You can expand the Macro to handle even more than 3 registers yourself.

1   PUSH      .MA    reg1,reg2,reg3
2             PUSH   ]1        ; Push register 1 on the stack
3             .XM    ]#=1      ; Done if only 1 parameter
4             PUSH   ]2        ; Push register 2 on the stack
5             .XM    ]#=2      ; Done if only 2 parameters
6             PUSH   ]3        ; Push register 3 on the stack
7             .EM
8
9   TEST      >PUSH ACC,PCL,PCH
M1            PUSH  ACC
M2            .XM   3=1
M3            PUSH  PCL
M4            .XM   3=2
M5            PUSH  PCH
10
11            >PUSH ACC
M1            PUSH  ACC
M2            .XM   1=1
12
13            >PUSH B,ACC
M1            PUSH  B
M2            .XM   2=1
M3            PUSH  ACC
M4            .XM   2=2
14            NOP           Rest of the program

 

Last Updated: 29 July 2012
© 2002, San Bergmans, Oisterwijk, The Netherlands
http://www.sbprojects.com