.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. As of Version 3.01 label may also start with an underscore.
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 (or = ) 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 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).