You are here: Home DOCUMENTATION information SBASIC Manual

Technological Arts Inc.

Your Shopping Cart

Your Cart is currently empty.

SBASIC Manual

Article Index
SBASIC Manual
Page 2
Page 3
Page 4
Page 5
Page 6
Page 7
Page 8
Page 9
Page 10
Page 11
Page 12
Page 13
Page 14
Page 15
Page 16
Page 17
Page 18
Page 19
Page 20
Page 21
Page 22
Page 23
Page 24
Page 25
Page 26
Page 27
Page 28
Page 29
Page 30
Page 31
Page 32
Page 33
Page 34
Page 35
Page 36
Page 37
Page 38
Page 39
Page 40
Page 41
Page 42
Page 43
Page 44
Page 45
Page 46
Page 47
Page 48
Page 49
Page 50
Page 51
Page 52
Page 53
Page 54
Page 55
Page 56
Page 57
Page 58
Page 59
Page 60
Table of Contents
Index
All Pages




                                             








                                 User's Manual
                          SBasic Compiler Version 2.7




                                       by
                                  Karl E. Lunt

                  Copyright (c) 1996, 1998, 1999   Bothell, WA
                              All rights reserved
                            Printed December 5, 1999





                                     DISCLAIMER


            I am releasing the executable for the SBasic compiler, all
           supporting library and include files, assorted test cases,
           and this document as freeware.  Feel free to use SBasic for
             whatever non-commercial application seems appropriate.

           The SBasic compiler, with or without its attendant support
        files, is freeware and in the public domain.  You may not charge
       for the sale or distribution of SBasic or its distribution files.
         If you distribute SBasic to others, please include this manual
              in its present form, complete with this disclaimer.

           I make no warranty, representation, or guarantee regarding the
         suitability of SBasic for any particular purpose, nor do I assume
         any liability arising out of the application or use of SBasic,
       and I disclaim any and all liability, including without limitation
                      consequential or incidental damages.

            You, as the user, take all responsibility for direct and/or
      consequential damages of any kind that might arise from using SBasic
                                in any fashion.

          I do not warrant that SBasic is free of bugs.  If you find what
     you think is a bug, kindly let me know what it is IN DETAIL, and I'll
       certainly consider fixing it in a later release, if there ever is
                                     such.

         I developed SBasic as a tool for working with the Motorola 68hc11
     and 68hc12 MCUs.  If you use SBasic for developing robotics (or other)
        application code and find it useful, fine.  If you don't find it
                  suitable in some fashion, then don't use it.


                                   DISCLAIMER




                                   Karl Lunt
                               116 173rd St., SW
                              Bothell, WA   98012






     SBasic User's Manual     SBasic Version 2.7              Page 2
     Printed:  December 5, 1999
     Introduction


     This manual describes the use of the SBasic (SB) compiler.  SB is a
     PC-based cross-compiler for a subset of the Basic language.  Source
     files containing SBasic statements are compiled into a source file of
     assembly language for the target machine.  Subsequent assembly of that
     file yields an exectuable file for the target machine.

     SB creates code for either a 68hc11 or 68hc12 target.  For the 68hc11,
     SB's output code is compatible with the Motorola FREEWARE asmhc11
     assembler, which is bundled with the SBasic distribution files.  For
     the 68hc12, SB's output code is compatible with the Motorola FREEWARE
     as12 assembler, available from several sites on the Internet,
     including my web site (http://www.seanet.com/~karllunt).

     The SBasic compiler was written in Borland C (version 4.52), and is
     compiled as a 32-bit DOS standard app.  My SB design is loosely based
     on a small Basic interpreter developed by Herbert Schildt and
     presented in his excellent book, "The Art of C."  (Osborne McGraw-
     Hill, Berkeley, CA   94710; ISBN 0-07-881691-2)
































     SBasic User's Manual     SBasic Version 2.7              Page 3
     Printed:  December 5, 1999
     History of SBasic


     Version 2.7 fixes a bug in the GOSUB statement that only appeared if
     you tried to use a variable as the argument; the code would refer to
     either the wrong or an unknown variable.  The resulting .asc file
     could create errors during the assembler phase.

     Version 2.6 fixes a bug that appeared in some programs compiled for
     the 68hc12.  Some DO-LOOPs or IF-ENDIFs created sections of code so
     long that the 68hc12 direct branch instructions failed (target out of
     range).  This version treats 68hc11 and 68hc12 compilations the same;
     DOs and FORs create short branches around JMP instructions.  This
     version also increases the number of labels, constants, and variables
     that your programs can create.

     Version 2.5 *finally* kills the last known bug in SB, which corrupted
     comparison tests in several different loop constructs.  The
     distribution file contains a number of test cases that verify the bug
     is finally dead (I hope!).

     Version 2.4 generates all assembler literals as hex constants, rather
     than decimals.  It also replaces the JMP *+5 branching construct in
     6812 output with a straight branch; the 6812 assembler will
     automatically assign the correct branch opcode.  It also fixes a bug
     in the shift and roll functions, which were generating dead PSHx-PULx
     instructions.

     Version 2.3 adds the ~ unary operator, which generates the one's
     complement of an argument.  It also now reports an error if the source
     file contains a DO with an UNTIL or WHILE but without a terminating
     LOOP.  It also now reports an error if an IF statement does not
     contain a comparison clause.

     Version 2.2 adds the MIN(), MAX(), MINU(), and MAXU() functions.  It
     also fixes a nasty bug in the assignment operator, which created bad
     code if you set a variable equal to an array element.

     Version 2.1 adds the COPY statement, for moving blocks of data between
     areas of memory.  Runtime support relies on two new library files,
     COPY11.LIB and COPY12.LIB.

     Version 2.0 adds support for the 68hc12 MCUs.  Code output does not
     take full advantage of the newer instruction set, but it's a start.

     Version 1.5 fixes bugs in code generated for certain uses of peek()
     and peekb().  Also fixes an obscure bug in certain array operations.
     Also allows use of '_' (underscore) in function names; see description
     of ASMFUNC statement below.  Also cleaned up the array assignment
     code; complex array index calculations seem to work fine.  If you
     notice any that don't, please contact me.

     Version 1.4 fixes bugs in code generated for certain uses of multiply.


     SBasic User's Manual     SBasic Version 2.7              Page 4
     Printed:  December 5, 1999

     Version 1.3 fixes bugs in code generated for certain uses of peek()
     and peekb().

     Version 1.2 changes the assembly source for variable references.  SB
     now creates variable references with unique labels, rather than as
     offsets to the varbeg address.  Added support for inline assembly
     language, through the ASM and ENDASM statements.  Added support for
     the ASMFUNC statement, used to define SBasic entry points into
     assembly language routines.  Cleaned up the code generated for POKE
     and POKEB statements; handles literal target addresses more cleanly.
     Fixed bug in POKE and POKEB statements; older versions compiled bad
     code for multiplies in the second argument.

     Version 1.1a fixes remaining bugs in the code generator regarding
     arrays.  It also fixes a nasty bug concerning operations such as /
     (division), mod, poke(), and pokeb().  The code generated for these
     operations was bad if the result was stored into an array element.

     Version 1.1 contains fixes to the code generator regarding arrays and
     the ADDR() function.  In particular, the code generated for array
     references is much tighter.

     I removed the error message for labels that are defined but not
     referenced.  This made developing modules of code too difficult; if
     you mistype the name of a label, you're going to get other errors,
     anyway.

     I added the SWAP command, to make it easier to deal with multiple
     items on the data stack.

     Version 1.0 follows a long succession of beta releases, spanning many
     months.  In 1.0, SBasic finally reached a point where, like it or not,
     I had to call the project done, at least for now.

     Version 1.0 supports single-dimension arrays, as well as math
     operations in constant declarations.  These features, added to those
     already existing in the previous beta release, constitute what I
     consider to be the bare minimum for a final system.

     At this point, however, the code generator is getting kind of fragile,
     and needs to be rewritten.  This is a large task that I won't take on
     easily, but I'll continue to support SBasic for bug fixes.












     SBasic User's Manual     SBasic Version 2.7              Page 5
     Printed:  December 5, 1999
     Invocation


     You execute SB by entering the command:

         sbasic  infile 

     where 'infile' contains the path to the source file you wish to
     compile.  SB writes its output, the assembly language source for the
     target, to the standard output, which is normally the screen.

     You can redirect the output file to another file by entering the
     command:

         sbasic  infile    >outfile

     where 'outfile' is the path to an output file to hold the created
     source lines.

     If SB did not detect any errors in your source file, its output file
     should assemble correctly with the appropriate target assembler.  If
     SB detected errors, it inserts error notices in the output file.
     These are almost guaranteed to generate numerous errors if the
     resulting output file is assembled.

     SBasic supports several command-line options, used to control the
     addresses of key elements in the final program.  These options will be
     explained in detail below.

     Upon completion, SB returns an errorlevel that can be used to
     determine success or failure of the compilation.  If SB successfully
     compiled the source program, it returns an errorlevel of 0.  If SB
     detected one or more errors during compilation, it returns an
     errorlevel of 1.





















     SBasic User's Manual     SBasic Version 2.7              Page 6
     Printed:  December 5, 1999
     Command-line options


     You can control the placement of variables, code space, and stack
     space in the target executable by means of SBasic command-line
     options.  If you supply any options in your command line, they must
     follow the name of the SBasic source file.  Refer to the above section
     on executing SBasic.

     You can control where SBasic places the start of its RAM variables by
     using the /v option.  The format of this option is:

          /vxxxx

     where xxxx is a four-digit hexadecimal address that marks the start of
     the variable space.  SBasic assigns this address to the assembler
     label VARBEG; if you do not use the /v option, SBasic assigns a
     default value of $0000 to VARBEG.

     You can control where SBasic places the beginning of the executable
     code by using the /c option.  The format of this option is:

          /cxxxx

     where xxxx is a four-digit hexadecimal address that marks the start of
     the code space.  SBasic assigns this address to the assembler label
     CODEBEG; if you do not use the /c option, SBasic assigns a default
     value of $b600 to CODEBEG.

     You can control where SBasic places the top of the target's stack
     space by using the /s option.  The format of this option is:

          /sxxxx

     where xxxx is a four-digit hexadecimal address that marks the top of
     the stack space.  SBasic assigns this address to the assembler label
     STKBEG; if you do not use the /s option, SBasic assigns a default
     value of $00ff to STKBEG.

     You can control the type of branch instruction SBasic creates by using
     the /b option.  The format of this option is:

          /b

     SBasic normally converts a transfer or jump instruction into two
     assembly language source lines.  The first line is a relative branch
     around the next line, and the second line is a long jump to the target
     address.  For example:

          while
               n=3
          wend



     SBasic User's Manual     SBasic Version 2.7              Page 7
     Printed:  December 5, 1999
     contains a branch instruction that tests the value of variable N and
     branches back to the WHILE statement if N equals 3.

     For the 68hc11 and 68hc12 MCUs, SBasic normally generates code similar
     to:

     whl000
          ldd  var001
          cpd  #3
          bne  *+5                      branch instruction, line 1
          jmp  whl000                   branch instruction, line 2

     For short transfers, where the branch target is within the relative
     addressing limit of the target MCU, this code is larger and will run
     more slowly than necessary.

     Using the /b option forces SBasic to generate relative branches
     directly to all targets.  If the /b option is in effect, SBasic would
     generate the following code for the above example:

     whl000
          ldd  var001
          cpd  #3
          beq  whl000                   branch instruction

     Note that the branch has reversed sense, and the JMP instruction has
     disappeared.


          WARNING:  Branches to addresses beyond the target MCU's
          relative branch limit will result in assembler errors, even
          though SBasic will not report any compilation errors.
          SBasic does not maintain an internal program counter, and
          will not detect that a branch target is out of range.


     Beginning users should omit the /b option, and accept the slight
     increase in size and execution times caused by the default branch code
     generation.

     Experienced users may, however, use the /b option to gain improved
     performance.  In this case, however, you must carefully monitor the
     assembler's output for any errors resulting in out-of-range branches.

     If your code generates out-of-range branches using the /b option,
     recompile without the option.  SBasic currently does not support any
     method for selectively compiling direct branches.

     You can select the target MCU by using the /m option.  The format of
     this option is:

          /mxxxx



     SBasic User's Manual     SBasic Version 2.7              Page 8
     Printed:  December 5, 1999
     where xxxx is either 6811 to generate output code for the 68HC11 MCU,
     or 6812 to generate output code for the 68HC12 MCU.  If you don't
     supply the /m option, SB will generate code for the default MCU, the
     68HC11.

     The differences in output code caused by compiling for the two
     machines mostly concerns the library files used.  See the discussion
     below on library files for more details.

     Certain variations of the 68HC12, notably the 68HC912B32, use on-chip
     firmware to take over the MCU's interrupt vector table.  Similarly,
     some 68hc11 chips include masked ROM firmware (such as BUFFALO) that
     also takes over the vector table.  In both these cases you need to
     prevent SBasic from trying to set up a vector table on the target
     machine.  You can prevent SB from creating an interrupt vector table
     by using the /i option.  The format of this option is:

          /i

     If you use the /i option and your SB program must use interrupts, you
     will have to add SB code to prepare the appropriate RAM-based jump
     table.  Refer to the Motorola literature on your target MCU for
     details.

     Note that the /i option surpresses ALL changes to the vector area,
     including the reset vector.  SB programs compiled with the /i option
     must use some resident firmware, such as BUFFALO, to transfer control
     to the start of the program.



























     SBasic User's Manual     SBasic Version 2.7              Page 9
     Printed:  December 5, 1999
     Environment variables


     SB supports the use of two DOS environment variables.  These variables
     can help ease development of multiple projects in SBasic.

     When SB begins execution, it checks for the existence of two
     environment variables, SB_INCLUDE and SB_LIBRARY.  SB assumes
     SB_INCLUDE contains the path to a directory containing custom INCLUDE
     files.  Similarly, SB assumes SB_LIBRARY contains the path to a
     directory containing the standard SBasic library files.  If either of
     these environment variables does not exist, SB defaults to the current
     directory when searching for any corresponding files.

     You can assign a path to either of these variables in your
     AUTOEXEC.BAT file, using DOS' SET command.

     Example:

          set  SB_INCLUDE=C:\MYPROJ\INC
          set  SB_LIBRARY=C:\SBASIC\LIB

     These commands assign paths to the SB_INCLUDE and SB_LIBRARY
     environment variables.































     SBasic User's Manual     SBasic Version 2.7             Page 10
     Printed:  December 5, 1999
     Library files


     SB normally compiles all operations into in-line assembly language
     source for the target machine.  In some cases, however, a function may
     translate into so many lines of source code that inserting the code
     in-line each time the function is used would yield an unacceptably
     large output file.

     In these cases, SB automatically appends one or more files of assembly
     language source code to the output file.  These files, called library
     files, contain pre-written source code for performing the
     corresponding operation.

     For example, most versions of the 68hc11 require several lines of
     assembly language code to perform a 16-bit by 16-bit multiplication.
     Rather than insert this large section of assembler source every time
     your program uses the * operator, SBasic instead compiles a JSR to a
     library assembly language subroutine.

     At the end of your output file, SBasic then includes the library file
     containing the source code for this multiplication subroutine.

     SBasic only includes library files when necessary, based on your
     source code.

     One library file deserves special mention.  SB always includes the
     library file START11.LIB (START12.LIB for the 68hc12 MCU) during each
     compilation.  The assembly language source in this file will be
     executed each time the target machine begins running your SBasic
     program.  In fact, the code in this file is executed immediately
     following system reset.

     If your SBasic application requires changes to the time-sensitive I/O
     registers in the 68hc11, you can customize START11.LIB to include
     those changes.

     Note, however, that you should not change any of the labels provided
     in the original versions of START11.LIB and START12.LIB.  Other parts
     of the SBasic system require that those labels exist, and that they be
     named exactly as they are.














     SBasic User's Manual     SBasic Version 2.7             Page 11
     Printed:  December 5, 1999
     Features


     SB is a free-form Basic that supports enough control structures, such
     as IF-ELSE-ENDIF, that line numbers should not be necessary.  It does
     not expect nor support line numbers; if you use them, you will get a
     syntax error back.

     SB does not support GOTO.

     SB generates code that uses the target's largest commonly available
     accumulator(s).  This means that for the 68hc11 and 68hc12, SB uses
     16-bit variables and 16-bit math operations.

     SB compiles down to fairly concise assembly language.  It does no
     optimization from source line to source line.  That is, it does not
     maintain a history of register usage and attempt to optimize out
     redundant operations.  Even so, the generated code is quite compact,
     and will run fast enough to accomodate most projects.

     For those projects that demand higher performance, SB allows you to
     embed assembly language source directly in your program.  These
     assembly statements are passed intact to the target assembler.

     SB is case-insensitive with regard to statements, labels, variables,
     and constants.  The variable FOO may also be referred to as foo, Foo
     or fOo.

     SB has built-in maximums for several compilation elements such as
     variables and labels.  These limits are:

     Depth of FOR-NEXT nesting is 25.  No one should EVER hit this limit.

     Compilation parsing stack is limited to 60 atoms.  This is an internal
     limit of the compiler that determines how complex of a statement the
     compiler can parse.  Again, no one should ever hit this limit.

     Compilation data stack is limited to 40 cells.  This should be
     sufficient for all programs.

     Maximum number of variables that a program can declare is 400.  Note
     that an array, no matter how large, counts as one variable.

     Maximum number of constants is 400.  Maximum number of labels is 500.

     SB supports the following Basic functions and operators:

      rem            starts an SBasic comment
      '              (single quote) starts an SBasic comment
      include        includes other SBasic source files
      org            changes location of generated code
      data           stores 16-bit values in a ROM table
      datab          stores 8-bit values in a ROM table


     SBasic User's Manual     SBasic Version 2.7             Page 12
     Printed:  December 5, 1999
      copy           copies a block of data between two memory areas
      =              assignment
      +              addition
      -              subtraction; unary negation
      ~              1's complement
      *              integer multiply
      /              integer divide
      mod            integer modulus
      and            boolean AND
      or             boolean OR
      xor            boolean XOR
      =              test, equal
      <              test, less-than
      >              test, greater-than
      , ><         test, not-equal
      <*             test, unsigned less-than
      >*             test, unsigned greater-than
      rshft()        shift argument 1 bit to right
      lshft()        shift argument 1 bit to left
      rroll()        rotate argument 1 bit to right
      lroll()        rotate argument 1 bit to left
      min()          returns smaller of two values (signed)
      max()          returns larger of two values (signed)
      minu()         returns smaller of two values (unsigned)
      maxu()         returns larger of two values (unsigned)
      peek()         read 16-bit contents of an address
      peekb()        read 8-bit contents of an address
      poke           write 16-bit value to an address
      pokeb          write 8-bit value to an address
      swapb          exchange bytes
      for            starts a FOR-NEXT iterative loop
      to             signed test in a FOR-NEXT loop
      to*            unsigned test in a FOR-NEXT loop
      step           optional part of a FOR-NEXT loop
      next           ends a FOR-NEXT loop
      if             starts an IF-ELSE-ENDIF structure
      else           part of an IF-ELSE-ENDIF structure
      elseif         part of an IF-ELSE-ENDIF structure
      endif          ends an IF-ELSE-ENDIF structure
      while          starts a WHILE-WEND structure
      wend           ends a WHILE-WEND structure
      do             starts a DO-LOOP structure
      while          optional part of a DO-LOOP structure
      until          optional part of a DO-LOOP structure
      loop           ends a DO-LOOP structure
      waitwhile      waits while an I/O condition exists
      waituntil      waits until an I/O condition occurs
      select         starts a SELECT-CASE structure
      case           starts a CASE clause within a SELECT-CASE structure
      endcase        ends a CASE clause
      endselect      ends a SELECT-CASE structure
      exit           leaves loop structure early
      print          output text to the console


     SBasic User's Manual     SBasic Version 2.7             Page 13
     Printed:  December 5, 1999
      printu         output text; numbers print as unsigned
      printx         output text; numbers print as hexadecimal
      inkey()        input a character from the console
      outch          output a character to the console
      interrupt      marks start of an SBasic ISR
      const          creates a named constant
      declare        creates a single 16-bit variable
      asm            marks start of inline assembly language source
      endasm         marks end of inline assembly language source
      addr()         returns address of a label or variable
      push           pushes a value onto the SB data stack
      pop()          pops a value from the SB data stack
      pull()         synonym for pop()
      place          change an element in the SB data stack
      pick()         copy an element from the SB data stack
      drop           remove one or more elements from SB data stack
      interrupts     enables or disables system interrupts
      gosub          invokes an SBasic subroutine
      usr()          invokes an SBasic subroutine, returns one value
      return         returns from an ISR or subroutine
      end            ends an SBasic program or ISR


































     SBasic User's Manual     SBasic Version 2.7             Page 14
     Printed:  December 5, 1999
     Remarks


     SBasic provides two comment delimiters, for imbedding remarks in your
     source files.  The traditional REM statement can be used to start a
     comment at nearly any point in an SBasic program.  You can also use
     the newer ' (single-quote).  All text following a remark delimiter is
     ignored by the SBasic compiler.

     You can place a comment at the beginning of any line.  You can also
     place a comment at the end of any complete SBasic statement.  You
     cannot place a comment within an SBasic statement.

     Example:

          rem  This is a legal comment
          '    So is this

          a = c + 5                ' this is a legal comment, too
          a = c +                  ' this is illegal!

     Note that you can always insert a blank line anywhere in your source;
     SBasic always ignores blank lines.
































     SBasic User's Manual     SBasic Version 2.7             Page 15
     Printed:  December 5, 1999
     Include files and the INCLUDE statement


     SBasic supports the use of include files to help you organize and
     maintain your projects.  Include files are simply files containing
     SBasic source code for commonly-used functions.

     You can insert any include file into your SBasic program file by using
     the INCLUDE statement.  SBasic will automatically open the named file,
     compile the code it contains, then resume compiling your original
     file.

     For example, you might keep a single file of SBasic code for
     controlling servo motors.  You can force SBasic to include the code in
     this file (call it servo.bas) in your current program file, by using
     the INCLUDE statement:

          include  "servo.bas"

     Note the use of double-quotes around the file name.

     You can, if you like, supply a full pathname with the file name.  For
     example:

          include  "c:\sbasic\inc\servo.bas"

     forces SB to search only the supplied path for the file servo.bas.  If
     SB cannot find the file using this path, it will report an error.

     You can also, if you wish, set the DOS environment variable SB_INCLUDE
     to contain the full pathname of a directory dedicated to holding your
     include files.  If SB_INCLUDE exists, SBasic will search that
     directory for any files named in INCLUDE statements, provided that the
     file name does not itself contain any path information.  If SB_INCLUDE
     does not exist, SBasic defaults to searching the current directory.

     To summarize:

     1.  If the file name does not contain any path information, SB checks
     for the existence of a DOS environment variable, SB_INCLUDE.  If
     SB_INCLUDE exists, SB searches the path in that variable for the named
     file.  If SB_INCLUDE does not exist, SB searches the current
     directory.

     2.  If the file name contains path information, SB checks only the
     given path, regardless of the existence of SB_INCLUDE.

     Rule 2 above means that you can force SB to search the current
     directory, even if SB_INCLUDE exists, by using an INCLUDE statement of
     the form:

          include  ".\test.bas"



     SBasic User's Manual     SBasic Version 2.7             Page 16
     Printed:  December 5, 1999
     Here, the backslash serves as path information, forcing SB to search
     the full path given in the INCLUDE statement.





















































     SBasic User's Manual     SBasic Version 2.7             Page 17
     Printed:  December 5, 1999
     Labels


     SBasic does not support line numbers, but it does support line labels.
     Line labels consist of a string of up to 20 characters, ending with a
     colon (:).  Labels must begin with an alphabetic character or an
     underscore ('_'); remaining characters in a label can also include
     digits.  Any text following a line label definition is ignored.

     NOTE:  Though legal, starting labels with an underscore can cause
     obscure problems if you embed assembly language in your SBasic source
     file.  See the section below on ASM and ENDASM, regarding references
     to SBasic variables from within an ASM block.

     Example:
          foo:                     ' define the line label foo
               a = 3               ' write a value to A
               return              ' return from this subroutine

          main:                    ' start of the main program
               gosub foo           ' execute the subroutine foo

     This example shows several important points.  Note that labels require
     a trailing colon only when they are defined, but not when they are
     referenced.  Thus, the GOSUB to FOO doesn't need a colon at the end of
     FOO.

     Also, every SBasic program MUST contain the line label MAIN, even if
     it contains no other line labels.  The startup code that supports
     SBasic on the target system always jumps to the label MAIN: to begin
     execution.  If your program does not have a MAIN:, the compiler will
     report an error.

     Note that the line label MAIN does not mark the first line of your
     program's code; it only marks the starting point for execution of your
     program following reset.  You are free to place the line label MAIN
     anywhere in your file you deem appropriate.


















     SBasic User's Manual     SBasic Version 2.7             Page 18
     Printed:  December 5, 1999
     Numeric constants


     SBasic supports decimal, hexadecimal, and  binary numeric constants.
     To enter a hexadecimal number in an SB file, preface the number with a
     '$'.  To enter a binary number in an SB file, preface the number with
     a '%'.

     Hexadecimal numbers may contain the characters 0-9, A-F, and a-f.
     Binary numbers may contain the characters 0 and 1.

     The following examples show how to enter different numeric constants:

          foo = 1234               '  assigns decimal 1234 to FOO
          bar = $1234              '  assigns hexadecimal $1234 to BAR
          alpha = %10000           '  assigns decimal 16 to alpha
          cat = $12 + 34           '  adds hex $12 to decimal 34


     SBasic also supports ASCII character constants.  To enter an ASCII
     constant, enclose the character in single-quotes.  The value used will
     consist of the binary equivalent of the quoted character.  An ASCII
     constant always consists of eight bits; the upper eight bits of the
     variable involved will always be 0.

     For example:

          foo = 'a'                '  assigns lowercase-A (97) to foo



























     SBasic User's Manual     SBasic Version 2.7             Page 19
     Printed:  December 5, 1999
     Variables, arrays, and named constants


     SBasic requires you to declare the names of all variables used in your
     program.  You declare variables with the DECLARE command.  For
     example,

          declare  foo

     creates the SBasic variable FOO.

     Variable names must begin with an alphabetic character or an
     underscore ('_'); remaining characters in a variable name can also
     include digits.

     NOTE:  Though legal, starting variable names with an underscore can
     cause obscure problems if you embed assembly language in your SBasic
     source file.  See the section below on ASM and ENDASM, regarding
     references to SBasic variables from within an ASM block.

     All variables use two bytes of RAM.  The first variable defined is
     always located at assembler address VARBEG.  Variables are assigned
     addresses based on the order of their declarations.

     You must declare a variable before your code can reference that
     variable.  This means that you will usually place all DECLARE
     statements in a block at the beginning of your SBasic source file.

     Note that, unlike traditional Basics, SBasic does not automatically
     initialize all variables to zero.  The value of any variable following
     system reset is unknown!  Your SBasic program must provide any needed
     variable initialization.

     SBasic also supports single-dimension arrays, or vectors.  Each
     element in an array occupies one 16-bit location (two bytes).  You use
     the DECLARE statement to define an array in much the same way you use
     it to define a simple variable.  For example:

         declare  foo(5)

     defines the array FOO, consisting of five sequential 16-bit locations.
     The first element in any array is always element zero.  Thus, FOO in
     the above example consists of the five elements named FOO(0) through
     FOO(4).

     You can use arrays anywhere a variable name would be legal, including
     the left side of an assignment operator.  For example:

         declare  foo(5)

         foo(2) = 100/n




     SBasic User's Manual     SBasic Version 2.7             Page 20
     Printed:  December 5, 1999
     SBasic allows you to create named 16-bit constants.  You create
     constants with the CONST statement.  For example:

         const  bar = 34

     creates the SBasic constant BAR with a value of 34.  CONST statements
     may refer to previously defined constants, and may include any number
     of math operations.  CONST statements may not, however, refer to
     variables, as the contents of variables are not known at compile-time.
     If you refer to a variable inside a CONST statement, the compiler will
     report an error.

     You must create a constant before your code can reference that
     constant.  This means that you will usually place all CONST statements
     in a block at the beginning of your SBasic source file.

     Note that named constants do not consume any space in the final
     executable file.  They only exist as equates in the assembler source
     file generated by SBasic.




































     SBasic User's Manual     SBasic Version 2.7             Page 21
     Printed:  December 5, 1999
     Data tables


     SBasic allows you to store tables of data in ROM, for access by your
     program at run-time.  This technique is used often for storing pre-
     defined information, such as lookup tables for motor speeds or
     mathematical functions.

     To store 16-bit values in a data table, use the DATA statement.
     Follow the DATA statement with a list of values to be written into
     ROM.  For example:

          data      0, 1, 2, 3          ' store 4 16-bit values in table

     SBasic will generate suitable assembly language source to store the
     values into code memory at the current location.  For the 68hc11, this
     example would generate assembly language source similar to:

          fdb  0,1,2,3

     To store 8-bit values in a data table, use the DATAB statement.
     Follow the DATAB statement with a list of values to be written into
     ROM.  For example:

          datab     $ff, 123, 256, 'z'       ' store 4 8-bit values

     SBasic will generate suitable assembly language source to store the
     values into code memory at the current location.  For the 68hc11, this
     example would generate assembly language source similar to:

          fcb  255,123,0,122

     Note that the third value appears in the SBasic source as 256, but is
     converted to 0 in the output source file.  This happens because SBasic
     only writes the low eight bits of a DATAB list item to the output
     file.

     In order to access items within a DATA (or DATAB) table, you must
     provide a label at the start of the list.  Your program can then use
     this label to find the first item in the list.  For example:

          declare   n
          declare   sum
          
          foo:
          data      1,2,3,4
          data      5,6,7,8

          main:
          sum = 0
          for  n = 0 to 7
               sum = sum + peek(addr(foo) + n * 2)
          next


     SBasic User's Manual     SBasic Version 2.7             Page 22
     Printed:  December 5, 1999
          end

     This code uses the ADDR() function to locate the start of the data
     table at label FOO.  The list item of interest is found by adding an
     offset value (N * 2) to the address of FOO.  The PEEK() function then
     reads the 16-bit value stored at that address in the table.

     To use the above technique with a DATAB table, you must change PEEK()
     to PEEKB() and remove the multiplication by 2 in the offset
     calculation.

     Note that SBasic writes a DATA table in place.  That is, the table
     appears in exactly the same position in the output file as it appears
     in your SBasic source file.

     This means you cannot place a DATA table inside a block of executable
     code.  If you do, the target MCU will eventually try to execute the
     DATA table as if it were machine code, and your program will crash.

     For that reason, put your DATA statements outside of executable
     blocks.  A good place to write DATA statements is immediately before
     the MAIN: label in your program.

































     SBasic User's Manual     SBasic Version 2.7             Page 23
     Printed:  December 5, 1999
     COPY statement


     SBasic provides the COPY statement, used to move data from one memory
     area to another.  This proves very handy when you need to initialize a
     large array.  Format of the COPY statement is:

          copy  from, to, count

     where FROM is the address of the data block, TO is the address of the
     destination area, and COUNT is the number of BYTES (not variables) to
     move.

     For example, assume you need to initialize the array FOO with a table
     of data, already existing in a block of DATA statements.  You would
     use statements similar to:

          declare  foo(10)

          table:
          data     $1234, $5678, $1, $2, $3, $4
          data     $5, $6, $7, $8

          copy  addr(table), addr(foo), 20

     This code uses the ADDR() function to locate the addresses of the
     TABLE data block and the FOO array, then moves 20 bytes of data from
     the table to the array.

     Note that COPY cannot be used to move data into an area of memory that
     overlaps the source area.  Should you need to perform this operation,
     use two COPY statements, first to move the data into an intermediate
     area, then to move it into the final destination area.






















     SBasic User's Manual     SBasic Version 2.7             Page 24
     Printed:  December 5, 1999
     Operators


     SBasic supports all of the common arithmetic operators:

     = (equal-sign) sets the value of a variable to the result of a
     calculation.  This is the traditional assignment operator.  All
     assignments store a 16-bit value into a variable.
     + (plus-sign) performs 16-bit addition.

     - (minus-sign) performs 16-bit subtraction.  It also acts as the unary
     negation operator.

     ~ (tilde) performs 16-bit one's complement.  This is logically
     identical to N XOR $ffff.

     * (asterisk) multiplies two 16-bit values, yielding a 16-bit product.

     Run-time support for SBasic's multiplication operator on a 68hc11 MCU
     relies on a library file, included with the SBasic distribution.  This
     file is automatically added to the assembler source file created by
     SBasic, whenever your program invokes the multiplication operator.

     Note that this library file is only included if your code uses a
     multiply operation.  You can create smaller executables by eliminating
     any use of the multiplication operator, if appropriate.

     For the 68hc12 MCU, multiplication is done with inline assembly using
     the EMUL opcode, and executes much faster than it would on a 68hc11.

     / (forward-slash) divides a 16-bit dividend by a 16-bit divisor,
     yielding a 16-bit quotient; the remainder is lost.

     MOD (modulus) divides a 16-bit dividend by a 16-bit divisor, yielding
     a 16-bit remainder; the quotient is lost.


     Examples:

          alpha = foo + bar        ' adds two variables
          beta = gamma - $1234     ' subtracts a hex constant
          var1 = 3 * var2          ' multiplies a variable
          c = delta / 88           ' divides a variable by a constant
          m = gamma MOD 10         ' takes the modulus function


     SBasic also supports most of the common Boolean operators:

     AND performs the logical AND of two 16-bit values.

     OR performs the logical inclusive-OR of two 16-bit values.

     XOR performs the logical exclusive-OR of two 16-bit values.


     SBasic User's Manual     SBasic Version 2.7             Page 25
     Printed:  December 5, 1999


     Examples:

          alpha = foo AND $7f      ' leaves only low 7 bits of foo
          beta = alpha OR 255      ' sets all low 8 bits of alpha
          gamma = beta XOR $ffff   ' inverts all bits in beta
















































     SBasic User's Manual     SBasic Version 2.7             Page 26
     Printed:  December 5, 1999
     Comparisons


     SBasic supports a wide range of comparisons, for use with control
     structures such as IF-ELSE-ENDIF and DO-LOOP.  All comparisons test
     two 16-bit values and return TRUE if the values meet the comparison
     test.

     = (equal-to) yields TRUE if the two 16-bit values are equal.

     < (less-than) yields TRUE if the first 16-bit value is less than the
     second 16-bit value.  This is a signed comparison; $8000 is less than
     0.

     > (greater-than) yields TRUE if the first 16-bit value is greater than
     the second 16-bit value.  This is a signed comparison; 0 is greater
     than $8000.

     (not-equal-to) yields TRUE if the two 16-bit values are not equal.

     >< (not-equal-to) yields TRUE if the two 16-bit values are not equal.

     <= (less-than-or-equal-to) yields TRUE if the first 16-bit value is
     less than or equal to the second 16-bit value.  This is a signed
     comparison.

     >= (greater-than-or-equal-to) yields TRUE if the first 16-bit value is
     greater than or equal to the second 16-bit value.  This is a signed
     comparison.

     <* (less-than unsigned) yields TRUE if the first 16-bit value is less
     than the second 16-bit value.  This is an unsigned comparison; 0 is
     less than $8000 unsigned.

     >* (greater-than unsigned) yields TRUE if the first 16-bit value is
     greater than the second 16-bit value.  This is an unsigned comparison;
     $8000 is greater than 0 unsigned.

     SBasic does not allow you to store the result of a comparison in a
     variable.  SBasic also does not allow multiple comparisons in a single
     operation.  Control structures such as IF-ELSE-ENDIF can use only one
     comparison in the IF-clause.













     SBasic User's Manual     SBasic Version 2.7             Page 27
     Printed:  December 5, 1999
     Control structures


     SBasic supports several structures for controlling the flow of your
     program.  Used properly, these control structures can improve the
     quality of your program design, making your source file easier to
     read, understand, and debug.

     Some of the following control structures allow or require a comparison
     clause.  Such clauses consist of an expression, a comparison operator,
     and a second expression.  The comparison clause is evaluated as your
     program runs and, depending on the evaluation, control transfers
     within the control structure.

     Example:

          while  a < 5
               a = a + 1
          wend

     Here, the comparison clause "a < 5" determines whether control remains
     in the WHILE-WEND loop or transfers to the line following the WEND
     statement.

     All comparison clauses may contain one and only one comparison
     operator.  Multiple comparisons, such as:

          while a < 5 and c-1 = 3

     are illegal and will generate compilation errors.

     Note also that you do not enclose comparisons within parentheses.
     Doing so will result in a compilation error.

     WHILE-WEND is a conditional loop structure.  Control executes all
     statements between the WHILE statement and the WEND statement for so
     long as the comparison in the WHILE clause is TRUE.  When the
     comparison becomes FALSE, control exits the loop by transferring to
     the line following the WEND statement.

     Example:

          while  a < 500           ' loop while a is less than 500
               a = a + 1           ' increment a
          wend                     ' end of loop

     This example loops for so long as the value in A is less than
     (unsigned) 500.

     Note that WHILE-WEND is obsolete, even though SB still supports it.
     WHILE-WEND has been replaced by the more flexible DO-LOOP structure.
     DO-LOOP is a loop structure that may be either conditional or
     unconditional.  Control executes all statements between the DO


     SBasic User's Manual     SBasic Version 2.7             Page 28
     Printed:  December 5, 1999
     statement and the LOOP statement.  You may include an optional
     comparison clause in either the DO statement or in the LOOP statement.

     Examples:

          do                       ' start of a do-loop
               gosub process       ' do something useful
          loop                     ' end of loop

     The above example will loop forever, since it has no comparison
     clause.  An endless loop is often used as the core of a large program.


          do while a < 500         ' loop while a is less than 500
               a = a + 1           ' increment a
          loop                     ' end of loop

     This example mimics the WHILE-WEND loop above.


          do until a > b           ' loop until a is greater than b
               a = a + c/2         ' change value of a
          loop                     ' end of loop

     The above example loops until the value in A is greater (signed) than
     the value in B.


          do                       ' start of a do-loop
               a = peekb($1000)    ' read a value from an I/O port
          loop while a = 0         ' loop while a equals 0

     The above example loops for so long as the value read from the I/O
     port equals 0.


          do                       ' start of a do-loop
               a = peekb($1000)    ' read a value from an I/O port
          loop until a = $ff       ' loop until a equals $ff

     The above example loops until the value read from the I/O port equals
     $ff.


     The DO-LOOP provides great flexibility for loop control, because you
     can control when the comparison occurs in the loop.  If you place the
     comparison in the DO statement, the test is performed before the body
     of the loop is executed.  By placing the comparsion in the LOOP
     statement, you can force the body of the loop to execute before the
     comparison is performed.





     SBasic User's Manual     SBasic Version 2.7             Page 29
     Printed:  December 5, 1999
     The FOR-NEXT structure creates an iterated loop.  This means that a
     selected variable, called the index variable, controls exactly how
     many times the loop is executed.  Control executes all statements
     between the FOR statement and the NEXT statement until the value in
     the index variable EXCEEDS a specified limit.  The index variable is
     always tested at the top of the loop.  The comparison is signed for
     the usual FOR-NEXT loop, although you can use an unsigned comparison
     if necessary.

     Example:

          for n = 1 to 10
               a = a + n
          next

     Here, the variable N starts with a value of one.  The statement inside
     the loop is executed ten times, with N incrementing each time the NEXT
     statement executes.  Eventually, N holds the value 11 when the FOR
     statement executes.  At this point, the statement inside the loop is
     not executed.  Instead, control passes directly to the statement
     following the NEXT statement.

     Sometimes you must use a limit larger than $7fff.  Since SBasic uses
     16-bit math, numbers larger than $7fff are treated as negative in
     signed comparisons.  Therefore, the following example:

          for n = 1 to $9000
               a = a + 1
          next

     will exit immediately, as SBasic treats $9000 as a negative number,
     and 1 is already greater than a negative number.

     To change the above example to use an unsigned comparison, use the TO*
     operator.  The above example becomes:

          for n = 1 to* $9000
               a = a + 1
          next

     This loop will execute the expected $9000 times.

     Remember to leave room on your limit value so that the index variable
     can actually exceed the limit.  For example:

          for n = 1 to* $ffff
               a = a + 1
          next

     This loop will never end, since the value of N can never exceed the
     limit of $ffff.




     SBasic User's Manual     SBasic Version 2.7             Page 30
     Printed:  December 5, 1999
     Note that it is legal (but not good practice) to modify the index
     variable inside the loop.

     Normally, the index variable increments by one each time control
     reaches the bottom of the loop.  You can change the value by which the
     index variable increments with the STEP modifier.

     Example:

          for n = 1 to 10 step 2
               a = a + n
          next

     Here, the variable N starts with a value of one, and increments by two
     each time control reaches the NEXT statement.  Thus, N takes on the
     values 1, 3, 5, 7, 9, and 11.  When N becomes 11 at the top of the
     loop, control immediately passes to the statement following the NEXT
     statement.



     The SELECT statment marks the beginning of a SELECT-CASE control
     structure.  The SELECT-CASE structure allows your code to select one
     option out of a list, based on the value of an argument, called the
     selector.  Only the CASE clause associated with the matching selector
     value, if any, is executed.

     The general format of a SELECT-CASE structure is:

          select  foo                   ' use value of FOO as selector
               case  123                ' if FOO = 123...
               .                        ' execute this code
               .                        '
               endcase                  ' end of case 1

               case  456                ' if FOO = 456...
               .                        ' execute this code
               .                        '
               endcase                  ' end of case 2
          endselect                     ' end of select structure

     This structure replaces the older ON-GOTO construct, and allows
     creation of code that is easier to debug and maintain.

     The SELECT-CASE structure supports variations for handling special
     cases.  For example:

          select  foo + 3*j             ' use expression for selector
               case  1                  ' if selector = 1...
               case  n                  ' or N...
               case  'X'                ' or ASCII character X...
               foo = n + 3              ' change FOO
               endcase                  ' end of first case


     SBasic User's Manual     SBasic Version 2.7             Page 31
     Printed:  December 5, 1999

               case  2                  ' if selector = 2...
               case  3                  ' or 3...
               foo = n + 2              ' change FOO
               endcase                  ' end of second case

               foo = 4                  ' default action...
          endselect

     This example shows the use of multiple CASE statements within a CASE
     clause.  This feature comes in handy if your code must perform the
     same function for a group of selector values.

     This example also shows the method for performing a default action.
     The line FOO = 4 executes if no CASE clause matches the selector
     value.  Note that the default clause does not require an initial CASE
     statement or a terminating ENDCASE statement.

     Also, this example shows that the selector value for this example is
     an expression.  You can use any valid algebraic expression as the
     selector value in a SELECT statement.

     Note, however, that CASE statements only accept a numeric value, a
     constant, or a variable as an argument.  You cannot use an algebraic
     expression as the argument to a CASE statement!  Doing so will
     generate a compiler error.

     Finally, this example shows that you can change the selector value
     within a CASE clause, without affecting the actions of the SELECT
     statement.  This is because control passes to the ENDSELECT statement
     immediately after executing the code in any CASE clause.  Thus, any
     following CASE clauses do not evaluate the changed selector value.



     The EXIT statement allows you to leave a looping structure before the
     terminating condition, if any, is reached.  Control automatically
     jumps to the end of the currently active looping structure.

     You can also use EXIT to leave a SELECT-CASE structure.  In this case,
     control will jump to the corresponding ENDSELECT statement.

     Example:

          for n = 1 to 10
               if n = 5
                    exit
               endif
          next

     Here, control automatically leaves the FOR-NEXT loop when N equals 5.




     SBasic User's Manual     SBasic Version 2.7             Page 32
     Printed:  December 5, 1999
     Note that you can use EXIT inside DO-LOOP, WHILE-WEND, FOR-NEXT, and
     SELECT-CASE structures.  You cannot use EXIT outside of these looping
     structures.

     The IF-ENDIF structure selectively executes a block of statements,
     depending on a comparison at the beginning of the structure.  If the
     comparison is TRUE, the statements are executed, otherwise they are
     not.

     Example:

          if a = $12
               b = b * 2
          endif

     Here, the middle statement is executed only if the value of A is $12.

     You can use the ELSE modifier to provide greater flexibility to the
     IF-ENDIF structure.  Statements between the ELSE statement and the
     ENDIF statement are only executed if the comparison in the IF
     statement is FALSE.

     Example:

          if a = $12
               b = b * 2
          else
               b = -b
          endif

     Here, B is set to -B only if A is not $12.

     Note that you do not include parentheses around the comparison clause
     of any structure.  Doing so will cause SBasic to report an error
     during compilation.

     You can also use the ELSEIF modifier to simplify nested IF-ENDIF
     structures.  Consider the following example, in which three different
     conditions must be tested:

          if a = $12
               n = 1
          else
               if foo = w+2
                    n = 3
               else
                    if bar = a+w
                         n = 5
                    endif
               endif
          endif




     SBasic User's Manual     SBasic Version 2.7             Page 33
     Printed:  December 5, 1999
     This type of test sequence can be difficult to decipher.  Using the
     ELSEIF modifier simplifies the structure:

          if a = $12
               n = 1
          elseif  foo = w+2
               n = 3
          elseif  bar = a+w
               n = 5
          endif


     Note that the ELSEIF statement requires the same type of comparison
     clause used by the IF statement.









































     SBasic User's Manual     SBasic Version 2.7             Page 34
     Printed:  December 5, 1999
     Functions and statements


     SBasic supports several functions and statements useful for embedded
     control applications.

     Generally speaking, a function returns a value, while a statement does
     not.  All functions contain parentheses, though not all functions
     actually need an argument inside the parentheses.

     All statements, however, appear without parentheses.

     The SWAPB function exchanges the two bytes of the 16-bit argument and
     returns the new value.  It does not alter the original argument.  This
     operation is useful for sending both bytes of a variable to a byte-
     wide I/O port, such as the 68hc11's SPI.

     Example:

          j = $1234                ' prepare j
          pokeb spdr, swapb(j)     ' send $12 to SPI
          

     The RSHFT and  LSHFT functions shift the 16-bit argument one bit
     position, either right or left.  This operation can be used as a fast
     multiply or divide by 2.

     Example:

          n = %11000011            ' initial value of n
          n = rshft(n)             ' n now holds %01100001
          n = lshft(n)             ' n now holds %11000010

     Note that the shift functions move the argument one bit in the
     specified direction, moving a 0 bit into the vacated position.  Thus:

          x <- xxxxxxxxxxxxxxx <- 0 = LSHFT()
          0 -> xxxxxxxxxxxxxxx -> x = RSHFT()


     The RROLL and LROLL functions rotate the 16-bit argument one bit
     position, either right or left.  This operation can be used as part of
     a pulse-width modulation (PWM) function.

     Example:

          n = %1111                ' initial value of n
          n = rroll(n)             ' n now holds %1000000000000111
          n = lroll(n)             ' n now holds %0000000000001111

     Note that the roll functions move the argument one bit in the
     specified direction, placing the rotated bit into the position at the
     opposite end of the word.  Thus:


     SBasic User's Manual     SBasic Version 2.7             Page 35
     Printed:  December 5, 1999

          +-------------+
          |              | = LROLL()    |              | = RROLL()
          xxxxxxxxxxxxxxxx              xxxxxxxxxxxxxxxx



     The PEEK function returns the 16-bit value stored in a specific
     address.  This is the usual function for reading 16-bit I/O ports.

     Example:

          a = peek($1000)          ' get 16-bit value from address $1000

     You can make your use of PEEK easier to understand if you combine it
     with named constants defined with the CONST statement.

     Example:
          const porta = $1000      ' define address of port A
          a = peek(porta)          ' get 16-bit value at port A


     The PEEKB function returns the 8-bit value stored in a specific
     address.  This is the usual function for reading 8-bit I/O ports.

     Example:
          
          a = peekb($1020)         ' get 8-bit value from address $1020

     Recall that the = (assignment) operator writes a 16-bit value to a
     variable.  In the case of the PEEKB function, the top eight bits of
     the variable will always be written as 0.  Thus, reading a value of
     $45 in the above example results in storing $0045 in variable A.

     You can make your use of PEEKB easier to understand if you combine it
     with named constants defined with the CONST statement.

     Example:

          const portb = $1020      ' define address of port B
          a = peekb(portb)         ' get 8-bit value at port B


     The POKE statement writes a 16-bit value to a specific address.  This
     is the usual statement for writing data to 16-bit I/O ports.

     Example:

          poke $1000, a            ' write value in A to address $1000

     Note the difference in syntax between the PEEK function and the POKE
     statement; PEEK uses parentheses around the address argument, while
     POKE does not use parentheses.


     SBasic User's Manual     SBasic Version 2.7             Page 36
     Printed:  December 5, 1999

     You can make your use of POKE easier to understand if you combine it
     with named constants defined with the CONST statement.

     Example:

          const porta = $1000      ' define address of port A
          poke porta, a            ' write value in A to port A


     The POKEB statement writes a 8-bit value to a specific address.  This
     is the usual statement for writing data to 8-bit I/O ports.

     Example:

          pokeb $1000, a      ' write low 8 bits in A to addr $1000

     Note the difference in syntax between the PEEKB function and the POKEB
     statement; PEEKB uses parentheses around the address argument, while
     POKEB does not use parentheses.

     You can make your use of POKEB easier to understand if you combine it
     with named constants defined with the CONST statement.

     Example:

          const porta = $1000      ' define address of port A
          pokeb porta, a           ' write low 8 bits in A to port A


     The WAITWHILE and WAITUNTIL statements provide high-speed testing
     loops, for use with 8-bit I/O ports.  You can use these single
     statements to replace larger, less efficient wait-loops built from the
     PEEKB function.

     The WAITWHILE statement loops while the contents of an 8-bit port,
     ANDed with an 8-bit mask, yields a non-zero result.  The WAITUNTIL
     statement does the opposite; it loops UNTIL the contents of an 8-bit
     value, ANDed with an 8-bit mask, yields a non-zero result.

     Example:

          waitwhile $1000, $40     ' wait while bit 6 of $1000 is high

     This statement repeatedly reads the 8-bit value at address $1000 and
     ANDs that value with $40, for so long as the result is not zero.  When
     the result equals zero, the loop terminates.

     Example:

          waituntil j, n           ' wait until mask of value at j is not 0




     SBasic User's Manual     SBasic Version 2.7             Page 37
     Printed:  December 5, 1999
     This statement repeatedly reads the 8-bit value at the address
     contained in variable J and ANDs that value with the low eight bits in
     variable N, until the result is not zero.  When the result is not
     zero, the loop terminates.

     You must be aware of a few characteristics of the WAIT loops.  The
     first argument is always treated as an address, even if you use a
     variable.  In the second example above, the loop does not test the
     value in J, it uses the value in J as the address to test.

     Second, the WAIT statements always test an 8-bit address; you cannot
     test a 16-bit I/O port with these statements.

     Also, the WAIT statements always use the low eight bits of the mask
     argument.  Thus, if you specify a variable as the mask value, the WAIT
     statements will automatically use just the low eight bits in the loop
     test.

     Finally, you can improve the speed of the generated code by using only
     constants, numbers, or variables as arguments to these statements.
     Using an argument that contains math or logical operations will
     generate larger, slower test loops.

     Example:

          waitwhile j+4, n/q       ' this runs slowly

     will run slowly, since the two math operations will be performed
     inside each test loop.  A better way to write this is:

          adr = j+4                ' calc the address
          mask = n/q               ' calc the mask
          waitwhile  adr, mask     ' now do the loop



     The ADDR function returns the address of a specified label or
     variable.

     Example:

          a = addr(MyLabel)        ' put address of MyLabel in A

     You can use the ADDR() function to locate the first element in an
     array.  To do this, simply leave off the parentheses when supplying
     the array's name.  For example:

          declare  foo(5)

          a = addr(foo)

     causes A to contain the address of FOO(0).



     SBasic User's Manual     SBasic Version 2.7             Page 38
     Printed:  December 5, 1999
     You cannot use ADDR() to calculate the address of a selected array
     element; if you include a subscript after the array name, the compiler
     will report an error in the ADDR() function.

     This isn't really a problem, though, since all array elements occupy
     two bytes.  For example:

          a = addr(foo) + n * 2

     causes A to contain the address of FOO(N).  It does this by finding
     the address of FOO(0), then adding two to that address for each
     element named in N.  Thus, if N = 2, A will hold the address of
     FOO(2).

     See the discussion below on the INTERRUPT statement for a detailed
     example of using the ADDR function.


     SBasic supports a limited PRINT statement.  SBasic's PRINT statement
     sends characters to a default output device, based on the target
     system.  For the 68hc11, this is the Serial Communications Interface,
     or SCI.  For the 68hc12, this is the first of the asynchronous serial
     ports, equivalent to the SCI.

     SBasic supports the following variations of the PRINT statement:

          print "a constant string followed by a CR"
          print "a string followed by a space";
          print "a string followed by a TAB character",

          print                    ' prints a blank line

          print foo                ' prints the value of foo
          print "FOO ="; foo       ' prints a string, then a value
          print a; b; c            ' prints three values

     Additionally, SBasic supports two statements similar to PRINT that
     print values in slightly different formats.  The PRINTU statement
     prints any values in unsigned format and the PRINTX statement prints
     any values in hexadecimal characters.  The PRINTU and PRINTX
     statements behave exactly the same as the PRINT statement with regard
     to spacing, tabs, and quoted strings.

     For example:

          print   "-1 = "; -1      ' prints -1 = -1
          printu  "-1 = "; -1      ' prints -1 = 65535
          printx  "-1 = "; -1      ' prints -1 = FFFF

     SBasic also supports the C language's escape character for embedding
     special characters within a PRINT string.  You can embed any of the
     following special characters inside a PRINT string:



     SBasic User's Manual     SBasic Version 2.7             Page 39
     Printed:  December 5, 1999
          "\n" inserts a newline ($0a)
          "\r" inserts a carriage-return ($0d)
          "\f" inserts a form-feed ($0c)
          "\a" inserts an alert ($07)
          "\b" inserts a backspace ($08)
          "\t" inserts a horizontal tab ($09)
          "\v" inserts a vertical tab ($0b)
          "\\" inserts a backslash

     For example:

          print "Hello, world!\n\r\a";

     prints the string "Hello, world!" followed by a line-feed, a carriage-
     return, and a bell.


     Run-time support for SBasic's PRINT statements relies on several
     library files, included with the SBasic distribution.  These files are
     automatically added to the assembler source file created by SBasic,
     whenever your program invokes a variation of the PRINT statement.

     You may modify the PRINT statement library routines, if desired, to
     create support for other output devices.  However, you must keep the
     names of all subroutines defined inside a library file unchanged.

     This is because the assembler source created by SBasic uses fixed
     names for library functions.  If you change the names of the library
     routines, the assembler will report an undefined label error when it
     tries to find the library subroutines.

     Note that these library files are only included if your code uses a
     PRINT statement.  You can create smaller executables by eliminating
     any use of the PRINT statement, if appropriate.

          NOTE:  Your code must issue any setup instructions necessary
          to prepare the default I/O port for use with the PRINT
          statements.  For details on setting up the 68hc11's SCI,
          consult the section below, "Character I/O on the 68hc11."

     SBasic supports a version of the INKEY() function.  You can use
     INKEY() to receive characters from a default input device, based on
     the target system.  For the 68hc11, this is the SCI.  For the 68hc12,
     this is the first asynchronous serial port, similar to the SCI.

     Unlike the INKEY() function in traditional Basics, SBasic's version
     does not expect or allow an argument.

     If no character was received from the console, INKEY() returns 0.  If
     a character was received, INKEY() returns a value containing the
     character in the low eight bits; additionally, INKEY() sets bit 8 of
     the returned value.  Setting bit 8 allows your program to distinguish



     SBasic User's Manual     SBasic Version 2.7             Page 40
     Printed:  December 5, 1999
     between receiving a NULL (returned value = $0100) and not receiving
     any character (returned value = $0).

     For example:

          do
               n = inkey()
          loop while n = 0
          n = n and $ff

     This code loops until INKEY() returns a valid character from the
     console.  It then strips off the upper byte, leaving only the received
     character in N.

     INKEY() sets bit 8 to permit receiving any character, including NULLs,
     from the console input device.

     The actual code that supports the INKEY() function appears in the
     library files INKEY11.LIB (for the 68hc11) and INKEY12.LIB (for the
     68hc12).  You can edit the supplied INKEYxx.LIB source file to support
     using INKEY() with other devices.  Take care, however, to ensure your
     new version of INKEY() preserves the register usage of the original.

          NOTE:  Your code must issue any setup instructions necessary
          to prepare the default I/O port for use with the INKEY()
          function.  For details on setting up the 68hc11's SCI,
          consult the section below, "Character I/O on the 68hc11."


     Sbasic provides the OUTCH statement, used to send an 8-bit character
     directly to the console.  This statement provides the same
     functionality as the usual Basic phrase:

          PRINT CHR$(N);

     only the OUTCH statement takes much less space, both in the source
     file and in the final executable.

     For example:

          outch  n+2

     This example adds 2 to the current value in variable N, then sends the
     low eight bits of the sum directly to the console device as an ASCII
     character.

     The actual code that supports OUTCH appears in the library files
     OUTCH11.LIB (for the 68hc11) and OUTCH12.LIB (for the 68hc12).  You
     can edit the supplied OUTCHxx.LIB source file to support using OUTCH
     with other devices.  Take care, however, to ensure your new version of
     OUTCH preserves the register usage of the original.




     SBasic User's Manual     SBasic Version 2.7             Page 41
     Printed:  December 5, 1999
          NOTE:  The routine contained in OUTCHxx.LIB is used by all
          console output statements, including all variations of
          PRINT.  Changing the routine in OUTCHxx.LIB will also change
          the behavior of all variations of PRINT.

     OUTCH only sends the low eight bits of its argument to the console.
     Therefore, OUTCH can be used directly with the value returned by
     INKEY(), as shown:

          do
               n = inkey()
          loop while  n = 0
          outch  n

     This code loops until INKEY() returns a non-zero value for N,
     indicating that a character was entered at the console.  The value in
     N is then sent back to the console as an echo.  Since OUTCH ignores
     the upper byte in N, the character echoes properly; your code does not
     need to alter the upper byte of N before calling OUTCH.

          NOTE:  Your code must issue any setup instructions necessary
          to prepare the default I/O port for use with the OUTCH
          statement.  For details on setting up the 68hc11's SCI,
          consult the section below, "Character I/O on the 68hc11."


     The MIN and MAX functions return the smaller or greater of two
     arguments, respectively.  Both functions use signed comparisons.  You
     must supply two arguments for either function, with a comma separator
     between arguments.  You may use either constants or algebraic
     expressions for either or both arguments.  For example:

          print min(-4, 3); "is smaller than"; max(-4, 3)

     prints the correct result, as a signed comparison between -4 and 3
     will properly show that -4 is smaller than 3.

     The MINU and MAXU functions perform the same operations as MIN() and
     MAX, except these functions use unsigned comparisons.  For example:

          print minu(-4, 3); "is smaller than"; maxu(-4, 3)

     will print apparent nonsense, as -4, taken as an unsigned number, is
     larger than 3.











     SBasic User's Manual     SBasic Version 2.7             Page 42
     Printed:  December 5, 1999
     Subroutines, GOSUB, and USR()


     SBasic supports the traditional Basic concept of subroutines.  A
     subroutine is a block of SBasic statements that can be invoked, or
     called, from elsewhere in the SBasic program.  After these statements
     complete execution, control returns to the calling section.

     A subroutine contains a line label marking the start of the
     subroutine, and at least one RETURN statement, which transfers control
     back to the calling section.

     The calling section of SBasic code invokes, or calls, a subroutine by
     means of the GOSUB statement.

     Example:

          main:
          do                            ' start of an endless loop
               gosub foo                ' call subroutine FOO
          loop                          ' loop forever

          foo:                          ' start of subroutine FOO
          a = a + 1                     ' increment A
          return                        ' return to caller

     This example, while not very useful, shows how a subroutine is invoked
     and how it is defined.  Note that you can use a GOSUB to a subroutine
     before that subroutine is defined in your code.

     Note that code inside a subroutine has full access to all variables
     defined with the DECLARE statement.  Changes made to a variable from
     inside a subroutine remain in effect when control returns from that
     subroutine.

     All GOSUBs push a return address onto the target's return stack.
     SBasic's data stack resides a fixed distance below the return stack.
     Excessive nesting of GOSUBs could clobber values on the data stack.

     The address of the subroutine invoked must be either a label or a
     variable; you may not use algebraic expressions or functions as
     addresses for a GOSUB statement.

     GOSUBs may pass one or more arguments to the called subroutine.  Your
     code should include the arguments after the name of the subroutine
     invoked.  For example:

          main:
          do                            ' start an endless loop
               gosub foo, 3, j          ' call FOO with two arguments
          loop                          ' loop forever




     SBasic User's Manual     SBasic Version 2.7             Page 43
     Printed:  December 5, 1999
     SBasic automatically pushes all arguments onto the data stack, then
     calls the named subroutine as above.  Code in the subroutine can use
     the data stack operators, such as PICK(), to test or change the
     arguments.

     Pay careful attention to the order in which SBasic pushes the
     arguments; they are pushed in the order given.  For example:

          gosub foo, 3, j
                     ^  ^
                     |  +--------- This argument is on top of data stack
                     +------------ This argument is next on data stack

     This method of passing arguments means that a subroutine may be passed
     different numbers of arguments at any time.  SBasic performs no checks
     to see if you have passed the correct number of arguments.

     SBasic similarly does not "clean up" the data stack before returning
     control to the calling routine.  Your code must update the data stack,
     if necessary, to remove any arguments.  You can choose to do this
     within the called routine, or in the calling routine after the
     subroutine invocation.  Regardless of where you perform this cleanup,
     it must be done or your program will eventually corrupt the data
     stack, likely crashing.

     Note that GOSUBs make no allowance for the called routine returning a
     value.  Thus, code that uses a GOSUB to invoke a subroutine must rely
     on global variables to check the results of the GOSUB.  This can
     result in awkward code that can prove difficult to maintain.

     To return a value to the calling routine, use SBasic's USR() function.
     The USR() function is similar to GOSUB, in that it calls an SBasic
     subroutine.  It can also include one or more arguments.

     Unlike GOSUB, however, USR() returns a value from the called routine
     for later use.  For example:

          n = usr(foo, 3)               ' call FOO, put returned value in N
          j = usr(bar)                  ' call BAR with no arguments

     Note the difference between USR() and GOSUB.  The USR() function, like
     any other SBasic function, requires parentheses around its list of
     arguments.

     The address of the subroutine invoked must be either a label or a
     variable; you may not use algebraic expressions or functions as
     addresses for a USR() function.

     USR() functions use the data stack in exactly the same manner
     described above for the GOSUB statement.  Also, the first argument in
     the USR() list is always the address of the called subroutine.




     SBasic User's Manual     SBasic Version 2.7             Page 44
     Printed:  December 5, 1999
     The RETURN statement


     SBasic's RETURN statement serves two functions.  You can use it to
     return control from a subroutine, and you can use it to return control
     from an interrupt.  For details on processing interrupts, see the
     Interrupts section below.

     When used in main-line code (code not in an interrupt service
     routine), RETURN generates the proper code to return control from a
     subroutine.  For the 68hc11 and 68hc12 MCUs, this is an RTS
     instruction.

     Note that SBasic does not check to see if you are using a RETURN
     statement after a label.  A RETURN statement always generates a
                                                  ______
     Return-from-Subroutine instruction in main-line code, regardless of
     where it occurs.

     When used in an interrupt section, RETURN generates the proper code to
     return control from an interrupt or exception.  For the 68hc11 and
     68hc12 MCUs, this is an RTI instruction.

     Additionally, a RETURN statement in main-line code may optionally
     include a value that will be returned to the calling routine.  For
     example:

          return                        ' this statement just returns
          return  j+3                   ' this statement returns a value

     You may include a RETURN statement with a returned value at any point
     in your code, even inside an interrupt section.  However, the returned
     value will only have meaning if it occurs in main-line code, and even
     then only if control is returning to a USR() invocation.  Returned
     values to a GOSUB are ignored, as are returned values from an
     interrupt section.




















     SBasic User's Manual     SBasic Version 2.7             Page 45
     Printed:  December 5, 1999
     Interrupts


     SBasic provides support for processing interrupts on the target
     system.

     You can write interrupt service routines (ISRs) directly in SBasic,
     rather than having to drop down into assembly language for the target
     machine.  However, you must declare a block of SBasic code as an ISR
     by using the INTERRUPT statement.

     The INTERRUPT statement can accept a single argument, which is the
     address on the target system to use as an interrupt vector.  SBasic
     will determine the address of the ISR code, then write that address to
     the vector address you specify.

     Later, when your program is running on the target system, an interrupt
     will cause control to transfer to the address stored in the vector
     address.  This in turn starts execution of your SBasic routine.

     Example:

          interrupt $fff0          ' use $fff0 as the interrupt vector
          a = peekb(porta)         ' read 8 bits from port A
          end                      ' return from the interrupt

     Given the above example, an interrupt that uses $fff0 as its vector
     will cause control to jump to the statement containing the PEEKB
     function.  This small program will read a value from port A, then
     return from the interrupt.

     Note that your SBasic routine does not get written to address $fff0;
     only the address of your routine gets written there.  If necessary,
     examine the code created by the compiler to help understand how SBasic
     interrupts work.

     You must use an END statment to terminate all ISR code following an
     INTERRUPT statement.  When it processes this END statement, SBasic
     compiles the proper Return from Interrupt instruction for the target
     system.

     You sometimes need more than one exit from an ISR.  If so, simply use
     the RETURN statement to exit the ISR.  SBasic will automatically
     compile the proper instruction for leaving the interrupt section.

     Example:

          interrupt $fff0
          if n = $66
               return
          endif
          n = $10
          end


     SBasic User's Manual     SBasic Version 2.7             Page 46
     Printed:  December 5, 1999

     In the above example, control leaves the ISR immediately if N contains
     the value $66.  If not, then N is changed to $10 and control leaves
     the ISR through the normal END statement.


     In rare cases, you may need to combine a line label with the INTERRUPT
     statement.  This can happen in some variations of the 68hc11 MCU.  The
     'a1 variation, for example, often contains a form of the BUFFALO
     monitor in on-chip ROM.  BUFFALO takes full control of the interrupt
     vectors, so SBasic cannot modify any of the vectors.

     Instead, BUFFALO expects your program to use specific addresses in on-
     chip RAM as jump vectors to reach your ISR code.

     To get around this obstacle, you must combine a line label with use of
     the ADDR function.

     Example:

          interrupt                ' note that no address is used!
          rtiisr:
          if u 0                ' if u is not yet 0
               u = u - 1           ' decrement u
          endif
          pokeb tflg2, $40         ' rearm interrupt
          end


          main:
          pokeb $eb, $7e           ' write a jump instruction
          poke $ec, addr(rtiisr)   ' write addr of ISR


     Here, the code in MAIN modifies the RAM addresses used by BUFFALO.  It
     stores a JMP instruction ($7e) followed by the address of the jump
     target.

     When the RTI interrupt occurs, BUFFALO will jump to address $eb.  The
     code left there by MAIN will in turn pass control to the ISR at
     RTIISR, where the actual interrupt processing occurs.

     Note that the above example does not require an argument to the
     INTERRUPT statement.  This means SBasic will not create an entry in
     the target's vector area.  The above code, following the label MAIN,
     must be used to provide the target processor with access to the ISR.

     If necessary, you can use the /i option on SB's command line to
     surpress generation of all interrupt vectors, including the reset
     vector.  You can use this option if the target MCU already contains
     firmware for activating your program following reset.  Examples of
     such a situation include a 68HC11A1 with BUFFALO already in ROM, and
     the 68HC912B32 with its on-chip bootloader.


     SBasic User's Manual     SBasic Version 2.7             Page 47
     Printed:  December 5, 1999

     You can enable or disable system-wide interrupts by using the
     INTERRUPTS statment.  This statement takes a single argument that is
     ON to enable interrupts or OFF to disable them.  This statement only
     affects system-wide interrupts, and its exact implementation varies,
     based on the target system.

     For the 68hc11 and 68hc12 MCUs, INTERRUPTS ON is compiled into a CLI
     instruction and INTERRUPTS OFF is compiled into a SEI instruction.

     Example:

          INTERRUPTS ON            ' turn on system-wide interrupts

               








































     SBasic User's Manual     SBasic Version 2.7             Page 48
     Printed:  December 5, 1999
     The ORG statement


     Normally, SB generates all code so it occupies sequential addresses on
     the target machine, starting at the address named CODEBEG.  You can
     think of this range of addresses as SB's original code section.

     If necessary, you can force SB to compile code at other addresses, by
     using the ORG statement.  The ORG statement takes one of three forms:

          org                or
          org  code                or
          org    code

     where is the address where you want subsequent SB code to
     compile.  You can think of these other address ranges as alternate
     code sections.  For example:

          org  $200

     causes subsequent SB code to compile in an alternate section, starting
     at address $200.  SB will continue to compile all code into sequential
     addresses, until you end the program or change the compile origin with
     another ORG statement.

     If you use the keyword CODE as the argument to an ORG statement, SB
     resumes compiling at the last address in the original code section.

     Perhaps a larger example will clarify this.  Assume that the following
     program was compiled with a CODEBEG address of $8000:

     main:
          n = 14              ' this code compiles at $8000

          org  $400           ' change the origin
     table1:                  ' use a label at new origin
          datab  0,1,2,3      ' this code compiles at $400

          org  $500           ' change the origin
          interrupt $fff0     ' RTI ISR compiles at $500
          end                 ' bogus ISR, just for example

          org  code           ' return to original code section
          j = addr(table1)    ' sets j to $400

          end

     You may use as many ORG statements, and change between alternate code
     sections and the original code section, as often as you want.

     In rare cases, you might need to change the address of SBasic's code
     section inside your program.  Early versions of the 68hc912b32
     contained an on-chip bootloader that took over the vector area.  To


     SBasic User's Manual     SBasic Version 2.7             Page 49
     Printed:  December 5, 1999
     force the vectors to appear at the proper locations, and also to force
     the library routines to compile in the correct locations, I had to use
     the third variation of the ORG statement above.

     For example, I compiled the following portions of code using a /c
     option of $f700:

          org  $8000  code    ' redefine code section here
     main:
          n = 14              ' this is the mainline code
          ...                 ' rest of mainline code goes here

          org  $f7e8          ' address of RTI vector
          asm                 ' switch to assembly language
          jmp  _rtiisr        use an assembly JMP instruction
          endasm              ' back to SBasic

          org  code           ' return to code section

          end                 ' end of program

     The /cf700 option started compilation with the code section at $f700.
     This caused SBasic to write the startup library code at $f700.  The
     ORG $8000 statement then moved MAIN down to $8000 and also caused the
     code section to move to that address.  The rest of the mainline code
     (not shown here) compiled from there.

     Next, the ORG $f7e8 let me write a JMP instruction into the
     bootloader's vector area for use by the RTI interrupt.  Finally, the
     ORG CODE statement switched back to the code section, now somewhere
     above $8000.

     This last step is important.  SBasic automatically switches to the
     code section before adding any library files at the end of the
     compilation.  If I hadn't moved the code section to $8000, SBasic
     would have added the library files at $f700, which was the original
     code section.  The resulting executable file would have failed.


















     SBasic User's Manual     SBasic Version 2.7             Page 50
     Printed:  December 5, 1999
     The data stack



     SBasic supports a data stack, for temporary storage of data.  For the
     68hc11 and 68hc12 MCUs, the data stack resides about 32 bytes below
     the return stack.  Both stacks grow downward (towards lower addresses)
     as items are pushed onto them.

     Do not confuse the use of these two stacks.  The return stack holds
     all data used by the target MCU in servicing interrupts and subroutine
     calls.  Items placed on the return stack are not currently accessible
     by your SBasic code.

     The data stack, however, contains items explicitly placed by your
     program.  You are free to use the data stack in any manner you like,
     and items placed on the stack will remain until your code specifically
     removes or modifies them.

     You can push items onto the data stack by using the PUSH statement.
     The PUSH statement takes a single argument; the 16-bit value of that
     argument will be pushed onto the data stack.

     Example:

          push n+5

     adds 5 to the current value of N and pushes the sum onto the data
     stack.  The value in N does not change.

     The size of the data stack depends on where you place the return
     stack, using the /S option.  The data stack will grow downward in
     memory until it runs into whatever values, if any, lie below it.
     There are no runtime checks for pushing too many items onto the data
     stack.

     You can pull (or pop) items from the data stack by using the POP()
     function.  POP() returns the top (most recent) item pushed onto the
     data stack.

     Example:

          n = pop() + 5

     pops the top item off the data stack, adds 5 to that value, and stores
     the sum in variable N.

     There are no runtime checks for popping too many items from the data
     stack.  The data stack resides below the return stack, and popping
     items causes the data stack pointer to move upwards in memory.  If you
     pop more items from the data stack than you pushed onto it, you risk
     corrupting the return stack.  This in turn will cause your program to
     crash on a later RETURN statement.


     SBasic User's Manual     SBasic Version 2.7             Page 51
     Printed:  December 5, 1999

     You can also use the PULL() function to remove items from the data
     stack.  PULL() works exactly the same was as the POP() function; it is
     simply a synonym for POP().

     You can copy a value from within the data stack by using the PICK()
     function.  PICK() locates a specific item within the data, and returns
     that value.

     Example:

          n = pick(2)

     copies the third item in the data stack into N.  The size of the data
     stack does not change, and the value in the third item does not
     change.

     Note that the item on the top of the stack is item 0; the second item
     is item 1.  SBasic does not check to see how many items are actually
     on the data stack.  If you supply an argument to PICK() that is larger
     than the current data stack, SBasic will return a bogus but legal
     value.

     You can alter a value within the data stack by using the PLACE
     statement.  PLACE stores a 16-bit value into a specified item in the
     data stack.

     Example:

          PLACE  2, n

     stores the value in N into the third item in the data stack.  The
     value in N does not change, and the size of the data stack does not
     change.

     SBasic does not test the actual size of the data stack before
     executing the PLACE statement.  Using PLACE to modify an item beyond
     the actual data stack will corrupt that location in memory and could
     crash your program.

     You can combine PICK() and PLACE to create 16-bit variables local to a
     section of code, such as a subroutine.  For example:

          foo:
          do
               place  0, pick(0) + 1    ' increment the item
          loop while pick(0) < 5        ' loop until it hits 5

     This code uses an item, already stored on the data stack by previous
     code, as a local variable.  Changes to this variable occur only in the
     data stack, not in a DECLAREd variable.




     SBasic User's Manual     SBasic Version 2.7             Page 52
     Printed:  December 5, 1999
     In some cases, you want to remove items from the data stack without
     actually using the removed values.  The DROP statement serves this
     purpose.  It takes a single argument, which gives the number of items
     (NOT BYTES) to remove from the data stack.  For the 68hc11, DROP
     removes two bytes for each value.  For example:

          drop  3                       ' remove 6 bytes on a 68hc11

     SBasic does not check that you are DROPping a valid number of items
     from the stack.  If you DROP too many items, you risk corrupting the
     return stack, located immediately above the data stack on a 68hc11.
     If this happens, your program will likely crash.


     The SWAP statement makes it easier to manipulate items on the data
     stack.  It exchanges the values in the topmost and second cells on the
     data stack.

     Example:

          push  2                       ' first push a 2
          push  3                       ' stack has 3, then 2
          swap                          ' now stack has 2, then 3

     Note that SWAP does not alter the size of the data stack, only the
     contents of the top two cells on the stack.  SWAP always uses 16-bit
     cells.

     Do not confuse the functions of SWAPB, which exchanges bytes within a
     variable, and SWAP, which exchanges cells on the data stack.

























     SBasic User's Manual     SBasic Version 2.7             Page 53
     Printed:  December 5, 1999
     ASM and ENDASM



     The ASM and ENDASM statements allow you to imbed assembly language
     source inside your SBasic program.  Assembly language source lines
     between these two statements (with one exception) are not processed by
     SB; instead, they are passed directly to the output file for
     subsequent assembly.

     This feature allows you to drop down into assembly language when
     necessary, should you need to write code that must run faster or take
     up less space.  Additionally, imbedded assembly language gives you
     direct access to registers on the target system not currently
     supported by SBasic.  For example, you can gain access to the 68hc11's
     hardware stack register (S) by using imbedded assembly language.

     The following example shows how to imbed 68hc11 assembly language:

         foo:
         asm                            ' switch to assembly language

             ldx   #$1000               point x at i/o regs
             ldd   $0e,x                get 16-bit counter TCNT
             std   _time                save in variable TIME

         endasm                         ' switch back to SBasic
         return                         ' and return

     This example shows an SB routine named FOO that uses imbedded assembly
     language to access the 68hc11's TCNT register.  The value read from
     TCNT is stored in the SBasic variable TIME.  The example then uses the
     ENDASM statement to switch back to SBasic, where the RETURN statement
     returns control to the calling routine.

     Note that you will generally use an SBasic label at the start of an
     assembly section; other SBasic routines can use this label to pass
     control to your assembly section.  Note also that imbedded assembly
     language lines can (and should) have comments appended to them.

     With one exception, all source lines between an ASM and an ENDASM
     statement are passed unaltered to the output file for processing by
     the assembler.  Thus, you cannot use SBasic statements or functions
     within an assembly section.  Such statements or functions would be
     processed by the assembler, not by SBasic, and will result in
     assembler errors.

     The sole exception to the above involves an underscore character.  As
     shown in the example above, you can refer to SBasic variables,
     constants, or labels by prepending an underscore to the name.  Before
     SBasic passes each assembly source line to the output file, it scans
     the line for any underscores.  If SB detects an underscore, the
     following characters are parsed and tested against SBasic's list of


     SBasic User's Manual     SBasic Version 2.7             Page 54
     Printed:  December 5, 1999
     known variables, constants, and labels.  If found, the underscore and
     following characters are replaced with SBasic's internal name.  Since
     this internal name is what the assembler will use to resolve operands,
     the SBasic name will be understood by the assembler.  In the above
     example, SBasic would convert the string "_time" to something like
     "var009."

     SBasic can handle multiple occurences of underscores within a source
     line.  For example, it will properly resolve a line such as:

         ldx   #_main+2*_cons0               uses a label and a constant

     If SBasic cannot resolve the character string following an underscore
     into the name of a variable, constant, or label, the line is passed
     unchanged to the output file.  This will usually result in an
     assembler error message, but it will not cause an SBasic error!  This
                                  it will not cause an SBasic error!
     means that if you use inline assembly language, you must check not
     only for SBasic errors but for assembler errors as well.  SBasic will
     not know that the assembler could not resolve the label.

     It is easy to lose track of which addresses are known to SBasic and
     which are known to the assembler.  Remember that labels known to
     SBasic are automatically converted to an internal label before SBasic
     writes them to the output file.  Thus, your SBasic source may refer to
     a label WAMPUM, but it will be converted to something like lbl010
     before the assembler sees it.

     To refer to standard assembler labels such as I/O registers, make sure
     that you make them known to the assembler by including them within an
     ASM section.  The above example could have been written:

         foo:
         asm                            ' switch to assembly language

         iobase  equ   $1000            address of I/O regs
         tcnt    equ   $0e              offset to TCNT reg
                 ldx   #ioregs          point x at i/o regs
                 ldd   tcnt,x           get 16-bit counter TCNT
                 std   _time            save in variable TIME

         endasm                         ' switch back to SBasic
         return                         ' and return













     SBasic User's Manual     SBasic Version 2.7             Page 55
     Printed:  December 5, 1999
     The ASMFUNC statement


     The ASMFUNC statement gives SB access to labels and routines within a
     block of assembly language code.  See the section above on the ASM
     statement.  The format for the ASMFUNC statement is:

         asmfunc  foo

     This statement tells the SBasic compiler that subsequent references to
     the label FOO must be passed to the output file as FOO, not as a
     converted label.

     ASMFUNC adds tremendous power to SB, allowing you to write your own
     SBasic extensions in assembly language, then use them as if they were
     an integral part of SB.  For example:

         declare  stack                 ' declare a variable
         asmfunc  getstk                ' define an asm entry point

         main:                          ' enter here
         stack = getstk(0)              ' get addr of return stack
         do  loop                       ' silly loop

         asm                            ' switch to assembly language
         getstk                         ' entry point to getstk()
             tsx                        ' move addr of stack to x
             xgdx                       ' move addr of stack to d
             rts                        ' return addr of stack
         endasm                         ' back to SBasic

         end

     Here, the ASMFUNC statement tells SB that references to the label
     GETSTK are to be passed unchanged to the output file.  Thus, when the
     SB code invokes the function GETSTK() to get the current hardware
     stack address, SB generates a JSR to GETSTK, not a JSR to an address
     with an internal SB label.

     The actual code for subroutine GETSTK exists in the ASM block.  GETSTK
     moves the stack pointer into the 68hc11's D-register and returns.  The
     code generated by SB then stores the D-register into variable STACK
     and falls into the silly loop at the end of the program.

     This example shows how to set up an ASMFUNC statement and its
     associated assembly language.  It also shows how to use an ASMFUNC
     label as a function.  In this case, you must adhere to SBasic's
     general rules regarding functions.  Functions, which return a result
     in the D-register, must be called with an argument.  Since the GETSTK
     routine doesn't need an argument, anything will work, but you must
     include an argument of some kind.  That's why I show an argument of 0
     for GETSTK.



     SBasic User's Manual     SBasic Version 2.7             Page 56
     Printed:  December 5, 1999
     You can also use ASMFUNC to create statements.  Remember that an
     SBasic statement doesn't return a value, but simply performs an
     operation.  For example:

         asmfunc  setstk                ' define an asm entry point

         main:                          ' enter here
         setstk  $0060                  ' change hardware stack addr
         do  loop                       ' silly loop

         asm                            ' switch to assembly language
         setstk                         ' entry point to setstk
             tsx                        ' get current stack addr
             ldx   0,x                  ' get return addr for SB in x
             jsr   _pull                ' get new stack addr in d
             xgdx                       ' new stack in x
             txs                        ' move new stack addr to s
             xgdx                       ' put return addr back in x
             jmp   0,x                  ' return through x
         endasm                         ' back to SBasic

         end

     This example is more advanced and shows how to change the return stack
     pointer from inside SBasic.  The SB program uses the SETSTK statement
     to set the return stack pointer to $60, essentially moving the
     hardware stack.  The tricky part here is that SB will execute this
     statement via a JSR to SETSTK.  If the assembly language code simply
     moved the new stack pointer into the S-register and returned, the
     program would crash since the return address would be undefined.  The
     code above changes the S-register, but saves the return address in the
     X-register.  It finally returns by jumping through the X-register.

     Here you can see how SBasic processes the arguments to a statement.
     The argument $0060 for the SETSTK statement is pushed onto SB's data
     stack; it is NOT passed in the D-register.  Thus, before the assembly
     language code in the SETSTK routine can do anything with the argument,
     it must first execute a JSR to the SB internal routine _PULL.  _PULL
     pulls the top element from SB's data stack and returns it in the D-
     register.  Refer to the GOSUB statement above for details on how
     SBasic parses arguments to statements.

     Note that you don't have to use a JSR to _PULL just to get an argument
     into the D-register.  Advanced programmers can directly access
     arguments using offsets to the Y-register.  Regardless of how you
     access the arguments, however, your assembly language routine MUST
     remove all arguments from the data stack before returning!  If not,
     repeated invocations of your routine will eventually crash the target
     system.

     This brings up another element of the ASMFUNC usage.  SBasic does no
     error checking to make sure your program uses an ASMFUNC label
     consistently.  Thus, you could use the same assembly language routine


     SBasic User's Manual     SBasic Version 2.7             Page 57
     Printed:  December 5, 1999
     as both a function and a statement, if you so choose.  What's more,
     you could pass varying numbers of arguments to the same ASMFUNC label
     as a statement.  You are responsible for ensuring your assembly
     language routine behaves properly in all cases.  SBasic will blindly
     load up the arguments and perform the JSR; your code has to deal
     properly with any variations in argument count.

     Note that the second example is not completely general, since it can
     be called only from the top level (main) of your SB program.  If, for
     example, you tried to do a SETSTK from within an SB routine, that
     routine would crash when it executed a RETURN statement, since its
     return address had moved when the stack pointer changed.

     When writing assembly language code invoked with ASMFUNC labels,
     remember to preserve SB's registers.  For the 68hc11 and 68hc12, the
     Y-register holds the data stack pointer and the S-register holds the
     return stack pointer.  Additionally, any argument returned to the
     calling routine is passed back in the D-register.

     To summarize, you can use an ASMFUNC label as either a statement or a
     function.  If used as a statement, you can supply zero, one, or more
     arguments; any arguments will be pushed left to right onto the data
     stack before the JSR to your label is executed.  If used as a
     function, you MUST supply one and only one argument to the function.
     This argument will be passed to the called routine in the D-register,
     though your routine can ignore it.  Upon returning from your routine,
     the contents of the D-register will be used as the returned value of
     the function.

     Additionally, remember that ASMFUNC labels do not exist as SBasic
     labels.  You cannot do a GOSUB to an ASMFUNC label, since that label
     only exists in the assembly language module.

     Since the ASMFUNC statement only affects subsequent references, the
     statement must appear in your source file before any references to the
     target label appear.  Thus, it's best if you put all of your ASMFUNC
     statements near the beginning of your source file.


















     SBasic User's Manual     SBasic Version 2.7             Page 58
     Printed:  December 5, 1999
     ASMFUNC, _INKEY, and _OUTCH



     Generally, you should not use ASMFUNC to define labels used internally
     by SBasic run-time routines.  Doing so will cause the assembler that
     processes the resulting output file to report an error.  This happens
     because SBasic will create two identical labels in its output assembly
     language file, one label that you defined in your ASM section and a
     matching label in an SBasic library file.

     The exceptions to this rule involve the labels _INKEY and  _OUTCH.
     SBasic reserves these labels for internal routines that handle
     character I/O.  By default, the _OUTCH routine sends the character in
     the A-register to the 68hc11's SCI port, and the _INKEY routine
     returns a character from the SCI in the D-register.  SBasic
     automatically appends a library file containing the assembly language
     source for these routines whenever it processes a statement that
     requires them.

     In this one case, SBasic permits your source file to override the
     normal inclusion of a library file.  For example, if SBasic detects an
     ASMFUNC statement defining the label _OUTCH:

         asmfunc  _outch

     SBasic does not append the _OUTCH library file.  Instead, SBasic
     relies on whatever _OUTCH assembly language routine you define in your
     SBasic source file to handle all character output.

     This feature allows you to redirect the output from all SBasic PRINT
     and OUTCH statements to an alternate device.  Similarly, you can
     redirect the input for the SBasic INKEY function from an alternate
     device.  This makes it easy to add SBasic support for formatted output
     to devices such as LCDs, or character input from custom keyboards.
     For example:

          asmfunc  _outch

     asm
     _outch
          staa      $1004               send char in A to port b
          rts
     endasm

     main:
          print "2 + 2 ="; 2+3
          end


     This sample program sends a mathematical statement to port B that
     should convince anyone your computer is loony.



     SBasic User's Manual     SBasic Version 2.7             Page 59
     Printed:  December 5, 1999
     Note that the labels _OUTCH and _INKEY must appear within an ASM-
     ENDASM block.  Also note that the argument to these ASMFUNC statements
     include the assembly-language (underscored) version of the routine
     name, NOT the normal SBasic representation.



















































     SBasic User's Manual     SBasic Version 2.7             Page 60
     Printed:  December 5, 1999
     Character I/O on the 68hc11



     The PRINT and OUTCH statements generate code for sending characters
     and text to some type of host, using library routines.  For the
     68hc11, this defaults to routines that use the SCI.

     Note, however, that SBasic does not actually set up the SCI for serial
     transfers.  Thus, it is not usually enough to simply PRINT a string;
     your code must first (as a minimum) enable the SCI transmitter and set
     the SCI baud rate.

     This same requirement exists for the INKEY() function.  Before your
     code can successfully invoke the INKEY() function, it must first
     enable the SCI receiver and set the SCI baud rate.

     Fortunately, this is a simple task.  Assuming the 68hc11 target system
     uses an 8.0 MHz crystal, the following statements will set up the SCI
     for 9600 baud and enable the SCI receiver and transmitter:

          include  "regs11.lib"

          main:
          pokeb  baud, $30              ' 9600 baud
          pokeb  sccr2, $0c             ' enable rcvr and xmtr
          print  "Hello, world!"        ' now say something

     If your 68hc11 target system uses a crystal frequency other than 8.0
     MHz, consult the Motorola technical literature for the proper data
     value to POKEB into the BAUD register.























     SBasic User's Manual     SBasic Version 2.7             Page 61
     Printed:  December 5, 1999




                                 Table of Contents
       Introduction                                               3
       History of SBasic                                          4
       Invocation                                                 6
       Command-line options                                       7
       Environment variables                                     10
       Library files                                             11
       Features                                                  12
       Remarks                                                   15
       Include files                                             16
       Labels                                                    18
       Numeric constants                                         19
       Variables, arrays, and named constants                    20
       Data tables                                               22
       COPY statement                                            24
       Operators                                                 25
       Comparisons                                               27
       Control structures                                        28
       Functions and statements                                  35
       Subroutines, GOSUB, and USR()                             43
       The RETURN statement                                      45
       Interrupts                                                46
       The ORG statement                                         49
       The data stack                                            51
       ASM and ENDASM                                            54
       ASMFUNC                                                   56
       ASMFUNC, _INKEY, and _OUTCH                               59
       Character I/O on the 68hc11                               61




                                        Index
     $ prefix                                                  19
     % prefix                                                  19
     /b option                                                  7
     /c option                                                  7
     /i option                                              9, 47
     /m option                                                  8
     /s option                                              7, 51
     /v option                                                  7
     68HC118, 11, 12, 22, 25, 39, 40, 41, 45, 47, 48, 51, 54, 58, 61
     68HC12             8, 12, 25, 39, 40, 41, 45, 47, 48, 51, 58
     Addresses
       CODEBEG                                              7, 49
       STKBEG                                                   7
       VARBEG                                               7, 20
     Arrays                                                20, 38
     ASCII constants                                           19
     Binary numbers                                            19
     Blank lines                                               15
     BUFFALO                                                   47
     Comparisons                                       27, 28, 30
     Data stack                                        43, 51, 52
     ERRORLEVEL                                                 6
     Executing SBasic                                        6, 7
     Hexadecimal numbers                                       19
     Include files                                             16
     Keywords
       ' (single-quote)                                        15
       <                                                       27
       <*                                                      27
       <=                                                      27
                                                             27
       =                                                   27, 36
       >                                                       27
       >*                                                      27
       ><                                                      27
       >=                                                      27
       ADDR                                            23, 38, 47
       ASM                                             54, 56, 59
       ASMFUNC                                             56, 59
       CASE                                                    32
       CONST                                           21, 36, 37
       COPY                                                    24
       DATA                                                    22
       DATAB                                                   22
       DECLARE                                         20, 43, 52
       DO                                              27, 28, 29
       DROP                                                    53
       ELSE                                                    33
       ELSEIF                                                  33
       END                                                     47
       ENDASM                                                  54
       ENDCASE                                                 32
       ENDSELECT                                               32
       EXIT                                                    32
       FOR                                                     30
       GOSUB                                               43, 57
       GOTO                                                    12
       IF                                                  27, 33
       INCLUDE                                             10, 16



       INKEY                                       40, 42, 59, 61
       INTERRUPT                                       39, 45, 46
       INTERRUPTS                                              48
       LROLL                                                   35
       LSHFT                                                   35
       MAIN                                                    18
       MAX                                                     42
       MAXU                                                    42
       MIN                                                     42
       MINU                                                    42
       NEXT                                                    31
       ORG                                                     49
       OUTCH                                           41, 59, 61
       PEEK                                                23, 36
       PEEKB                                               23, 36
       PICK                                                44, 52
       POKE                                                    36
       POKEB                                                   37
       POP                                                     51
       PRINT                                       39, 42, 59, 61
       PRINTU                                                  39
       PRINTX                                                  39
       PULL                                                    52
       PUSH                                                    51
       REM                                                     15
       RETURN                                          43, 46, 51
       RROLL                                                   35
       RSHFT                                                   35
       SELECT                                                  31
       STEP                                                    31
       SWAP                                                    53
       SWAPB                                               35, 53
       TO*                                                     30
       USR                                                     44
       WAITUNTIL                                               37
       WAITWHILE                                               37
       WHILE                                                   28
     Labels                                        18, 23, 43, 47
     Library files                          9, 10, 11, 25, 40, 41
     Operators
       *                                                   11, 25
       +                                                       25
       -                                                       25
       /                                                       25
       =                                                       25
       ~                                                       25
       AND                                                     25
       MOD                                                     25
       OR                                                      25
       XOR                                                     25
     Parentheses                                   28, 33, 36, 37
     SB_INCLUDE                                            10, 16
     SB_LIBRARY                                                10
     START11.LIB                                               11
     START12.LIB                                               11
     Subroutines                                           43, 45
     Variables                                                 20