SX/B Definitions |
I/O Pins
I/O pins are defined as variables -- either as a group, or as a single pin -- using the following syntax:
Symbol VAR Port{.Bit}
DigCtrl VAR RA ' 4 IO pins Segments VAR RB ' 8 IO pins Sio VAR RC.7 ' 1 IO pin
As of SX/B version 1.5, three 16-bit pseudo-ports have been added:
On power-up or an external reset (via MCLR), an SX/B program clears all I/O pins (port bits cleared to 0) and initializes them to inputs (TRIS bits set to 1).
Constants
Constant values can be declared in four ways: decimal (default), hex, binary, and ASCII using the following syntax:
Symbol CON Value
Hex numbers are preceded with a dollar sign ($), binary numbers are preceded with a percent sign (%), and ASCII characters and strings are enclosed in double quotes ("). If no special punctuation is used then the SX/B compiler will assume the value is decimal. An underscore character may be used in numbers for clarity.
MaxCount CON 4_000 ' decimal LedMask CON $F0 ' hex SegMap CON %0110_0101 ' binary Letter CON "A" ' ASCII character Baud CON "T9600" ' ASCII string
Constant names can be any combination of letters, numbers, and underscores (_), but the first character must not be a number. Also, constant names cannot use reserved words, such as SX/B instruction names (SERIN, GOTO, etc.) and SX aliases (RA, OPTION, etc.). The maximum number of characters allowed for a constant name is 32.
As of version 1.10 you may define computed constants for use by SASM in assembly routines. For example:
B2400 CON 16 ' 2400 Baud B9600 CON 4 ' 9600 Baud BitTm CON B9600 ' samples per bit BitTm15 CON 3*BitTm/2 ' 1.5 bits
In the examples above, the first three constants may be used anywhere in the program. The final definition, for BitTm15, is a computed constant and my be used anywhere a variable is allowed. Note that computed constants may not be used where a constant value is required (e.g., the frequency parameter of FREQOUT).
String constants can be used to create "shortcuts" that ease programming, in effect, allowing the programmer to create new commands. For example:
GOSUB RX_Byte, @serByte ' get command
can be replaced with:
SERRX @serByte ' get command
by defining the following string constant:
SERRX CON "GOSUB RX_Byte, "
Using string constants in this manner has generally been superceded by the SUB and FUNC definitions (for subroutine names and parameter requirements). See below for an improved method of declaring subroutines and functions.
Variables
SX/B supports words, bytes, arrays of bytes, and bit variables using the following syntax:
Symbol VAR Word{.bitIndex} When defining byte arrays, only constant values or named constants may be
used for the Size parameter, and array elements are zero-based, that is
the elements are indexed from zero to Size-1. For example, myArray(10) contains
the elements myArray(0) through myArray(9). In the SX18/20/28 arrays are
limited to 16 elements; in the SX48/52 arrays may have up to 223 elements. When
defining arrays for the SX18/20/28 it is best to define them largest to smallest
to maximize RAM use efficiency. Note that word variables may not be used in the index of an array. You can,
however use the LSB of a word variable like this: Variable names may be aliased (renamed) for programming convenience.
This also allows a group of bit variables to be included in the same
byte for single-line evaluation or modification Internal SX aliases may also be renamed for improved
program readability. For example: Variable names can be any combination of letters, numbers, and
underscores (_), but the first character must not be a number. Also,
variable names cannot use reserved words, such as SX/B instruction names
(SERIN, GOTO, etc.) and SX aliases (RA, OPTION, etc.). The maximum
number of characters allowed for a variable name is 32. On power-up or an external reset (via MCLR), an SX/B program initializes
all variables to zero unless the NOSTARTUP option is used with the PROGRAM
directive. Variables are usually passed by value using this form: ... actually copies the value of var2 and places it into var1.
The address (RAM location) of a variable may be passed by prefacing the
variable name with '@':
This feature is particularly useful for passing address parameters to
subroutines, especially when using PUT, GET, or the __RAM()
system array. Note that when assigning a bit variable the value of a byte or word, as in... ... the bit variable will get cleared to zero if the variable is zero, otherwise
the bit variable will be set to one. If you would rather copy a specific bit from
a byte or word variable, simply use the bit index you wish to copy: Word variables have an additional assignment option with two byte values
(variables or constants): Variable space (bytes):
Symbol VAR Byte{(Size)}{.bitIndex}
Symbol VAR Bit
result VAR Word ' word (16 bites)
count VAR Byte ' one byte (eight bits)
display VAR Byte(4) ' array of bytes
timer VAR Byte(NumTimers) ' named constants are allowed
alarm VAR Bit ' one bit
idx VAR Word
Start:
FOR idx = 1 TO 10
Leds(idx_LSB) = idx
NEXT
END
clock VAR Byte(3) ' clock array
secs VAR clock(0) ' seconds
mins VAR clock(1) ' minutes
hrs VAR clock(2) ' hours
flags VAR Word ' all flags
hiTemp VAR flags.15 ' high temp flag
loTemp VAR flags.14 ' low temp flag
Segs VAR RB ' display segments (anodes)
TRIS_Segs VAR TRIS_B ' segments TRIS reg
DigCtrl VAR RA ' digit control (cathode)
TRIS_Dig VAR TRIS_A ' digits TRIS reg
var1 = var2 ' copy var2 to var1
var1 = @var2 ' put address of var2 into var1
bitVar = variable
bitVar = variable.bitIndex
wordVar = lsbValue, msbValue
Device
General
Arrays
Max. Array
SX18/20
20
6x16 + 1x5 + 1x4
16 (each)
SX28
19
6x16 + 1x5 + 1x4
16 (each)
SX48/52
17
223
223
Program Labels
An SX/B program uses labels to define entry points into code sections or data tables. When used as a code entry point or data table name, label names must start in column one (not indented), end with a colon(:), and be on its own line. When used elsewhere in the program, labels are named without the colon, as in the example below:
Start: ' colon required idx = 0 PAUSE 500 Main: ' colon required READ Msg + idx, char ' no colon required INC idx IF char = 0 THEN Start ' no colon required SEROUT Sio, Baud, char GOTO Main ' no colon required ' ------------------------------------------------------------------------- Msg: ' colon required DATA "SX/B makes the SX fun!", 13, 0
Label names can be any combination of letters, numbers, and underscores (_), but the first character must not be a number. Also, label names cannot use reserved words, such as SX/B instruction names (SERIN, GOTO, etc.) and SX aliases (RA, OPTION, etc.). The maximum number of characters allowed for a label name is 32.
Comments
Comments can be used to add additional information to a program. The apostrophe character (') begins a comment section; anything to the right of the comment character will be ignored by the compiler. This allows comments to be added to a line of code. Using the comment character is also a convenient way to disable a line of code without removing it from the program.
' Display a running counter on RB Main: INC RB ' update LEDs ' INC RB ' this line disabled PAUSE 100 ' insert delay GOTO Main ' run forever
Note: For backward-compatibility with older versions of the BASIC programming language, REM may be used to define a line comment, though this style is outdated and generally discouraged.
REM This is an old-fashioned style comment and typically not used.
Inline Assembly Instructions
SX assembly instructions can be inserted into an SX/B program using the "\" (back-slash) character to preface the assembly code statement. For large blocks of assembly code ASM...ENDASM is recommended.
LedsLo VAR RB LedsHi VAR RC cntr VAR Word ' 16-bit counter Start: TRIS_B = %00000000 ' make RB pins outputs TRIS_C = %00000000 ' make RC pins outputs Main: \ MOV LedsLo, cntr_LSB ' copy low byte to LEDs \ MOV LedsHi, cntr_MSB ' copy high byte to LEDs PAUSE 100 \ INC cntr_LSB ' update counter \ SZ ' skip if cntr_LSB is zero \ JMP Main ' jump to Main \ INC cntr_LSB ' increment high byte \ JMP Main ' jump to Main
Note: Array elements hold the address of a variable so they should not be used in inline assembly instructions.
Subroutine Declaration
The programming and use of subroutines is simplified by declaring the subroutine name and the parameter(s) (if any) required. Additionally, the declaration of subroutines allows them to return a byte value (see FUNC, below, for return word values). Declaring subroutines offers significant advantages to the programmer:
SX/B subroutines are defined using the following syntax:
Label SUB {Min{, Max}}
Where Min is the minimum number of required parameters (if any) and Max is the maximum number of parameters passed to the subroutine. If Max is not specified then Min is the fixed number of parameters allowed.
The following short segment shows how predefined subroutines simplify SX/B program development:
TX_BYTE SUB 1, 2 ' sub with 1 or 2 parameters Start: TXBYTE "*" ' send one asterisk TXBYTE "-", 20 ' send 20 dashes TXBYTE ' raises syntax error END TX_BYTE: temp1 = __PARAM1 ' save character IF __PARAMCNT = 2 THEN temp2 = __PARAM2 ' save repeats ELSE temp2 = 1 ' set to 1 if not specified ENDIF DO WHILE temp2 > 0 SEROUT SOut, Baud, temp1 ' send the byte DEC temp2 ' dec repeats LOOP RETURN
Subroutines can also behave like functions in other languages, returning a byte value directly to a variable after the subroutine call. For example:
char = RX_BYTE
The value/variable to be returned to the calling code is placed after RETURN at the end of the subroutine code:
RX_BYTE: SERIN Sin, Baud, temp1 ' wait for serial input RETURN temp1 ' return to caller
When defining subroutines that require no parameters (as RX_BYTE, above), it is best to define the subroutine with a zero parameter count, as this will prevent the compiler from generating an assembly instruction (CLR __PARAMCNT) that is not needed by the program:
RX_BYTE SUB 0 ' receive serial byte
Subroutines do not have to be declared, but by doing so allows the subroutine code to be placed anywhere in the listing (without declaration the code must be in the first half of a code page), GOSUB is no longer needed to call the subroutine, and the compiler is able to check the for the proper number of parameters. The only requirement is that the SUB declaration(s) be placed in the first half of a code page. The advantages of the SUB declaration far outweigh the minor effort required to add the declaration.
When declaring a subroutine for string handling, it must be set to accept at least two parameters (base and offset address values). See READ for details on handling strings with SX/B.
Function Declaration
As of SX/B 1.5, a subroutine can return one or two bytes when defined as a function. As with SUB, FUNC routines are declared in the first half of a code page, but the actual code may reside anywhere.
SX/B functions are defined using the following syntax:
Label FUNC ReturnCount{, Min{, Max}}
Where ReturnCount is the number of bytes (0 - 4) returned by the function, Min is the minimum number of required parameters (if any), and Max is the maximum number of parameters passed to the function.
The following short segment shows how to define and use a function that returns a 16-bit value:
FREQ_IN FUNC 2 ' function returns two bytes Start: freq1 = FREQ_IN ' get frequency END FREQ_IN: COUNT Fpin, 1000, tmpW1 ' count cycles for one second RETURN tmpW1 ' return two bytes
Note that a function can return more bytes than the target variable. If, for example, a function is designed to return a word and the target output variable for that function is a byte, only the LSB of the return value will be assigned.
The programmer may assign additional return bytes manually, immediately following the function call. In the example below the function is designed to return a 32-bit result. The low word of the result is automatically assigned by the compiler, the high word of the result is manually assigned on the line that follows.
' ------------------------------------------------------------------------- ' Variables ' ------------------------------------------------------------------------- result VAR Word ' 32-bit result resultHi VAR Word tmpW1 VAR Word ' subroutine work vars tmpW2 VAR Word tmpW3 VAR Word WATCH result, 32, UHEX ' display 32-bit result ' ========================================================================= PROGRAM Start ' ========================================================================= ' ------------------------------------------------------------------------- ' Subroutine Declarations ' ------------------------------------------------------------------------- MULT32 FUNC 4, 2, 4 ' ------------------------------------------------------------------------- ' Program Code ' ------------------------------------------------------------------------- Start: result = MULT32 $FFFF, $0010 ' get low word resultHi = __PARAM3, __PARAM4 ' get high word BREAK ' display result in Debug END ' ------------------------------------------------------------------------- ' Subroutine Code ' ------------------------------------------------------------------------- ' Use: MULT32 value1, value2 ' -- multiplies two values ' -- when mixing a word and byte, the word must be declared first MULT32: IF __PARAMCNT = 2 THEN ' byte * byte tmpW1 = __PARAM1 tmpW2 = __PARAM2 ENDIF IF __PARAMCNT = 3 THEN ' word * byte tmpW1 = __WPARAM12 tmpW2 = __PARAM3 ENDIF IF __PARAMCNT = 4 THEN ' word * word tmpW1 = __WPARAM12 tmpW2 = __WPARAM34 ENDIF tmpW3 = tmpW1 ** tmpW2 ' calculate high word tmpW2 = tmpW1 * tmpW2 ' calculate low word RETURN tmpW2, tmpW3 ' return 32 bits, LSW first
The discussion above applies to simple variables only. When using an array element as the target, all bytes are automatically assigned. For example:
bigVal VAR Byte(4) ... bigVal = MULT32 $1234, $1234
In this case, bigVal(0) .. bigVal(3) are assigned to the return variables __PARAM1 .. __PARAM4 from the function.