The Basics of Vesta Basic
The Anatomy of Vesta BasicThe Anatomy of Vesta Basic
There are two software components of Vesta Multi-tasking Basic that reside on
the SBC2000 - the Boot Monitor which takes control at power-up, and the Runtime
Engine, to which the Boot Monitor will transfer control. This design makes it
possible to upgrade the version of Vesta Basic on your SBC without replacing
any chips. All that is required is a serial connection to the DEV port.
The Integrated Development Environment (IDE) resides on the PC and allows you
to enter and edit programs. The IDE invokes the Compiler to produce a task image
from the source code in the active task window. This task image can be downloaded
to RAM or Flash on the SBC, or loaded onto a ROM chip with a device called a
ROM programmer.
The IDE communicates via a serial connection to the IDE Monitor in the VMTB
Runtime Engine on the SBC2000. When a task has been downloaded, the Runtime
Engine will execute it. The IDE can cause the Monitor to control tasks in RAM
(run, stop, step, etc.) and to obtain information about tasks, such as execution
state and the values of variables.
SBC2000
Memory
There can be several different kinds of memoryon your SBC, proper use of which has important
ramifications.
For more information on the Vesta Basic keywords pertaining to memory, see Memory
Commands .
Battery Backable RAM
The onboard RAM is a large-capacity, volatile memory device that may be battery
backed.
RAM is available in three sizes on the SBC2000-332: 64Kbyte, 256Kbyte and 1Mbyte,
and 32k, 128k and 512k bytes on the SBC2000-188.
Battery backing is not enabled on your board by default. Unless you provide
battery backup power, data will not be preserved when power is removed. Consult
your Vesta Engines manual for more information on your SBC2000 controller.
Real
Time Clock RAM
There are about 240 bytes of RAM available in the Real Time Clock (RTC) clock/calendar
chip. The RTC will hold its values through power cycles if battery backup power is supplied
to the clock. There is no limit on the number of times a byte in RTC RAM may be written.
The RTC RAM device is accessed via a serial I/O protocol, and has a relatively slow access
time. There is no extra delay necessary for writes beyond that imposed by the serial
access. VMTB provides routines for reading and writing to individual locations of RTC
RAM. See RTC.
EPROM
EPROM is a large-capacity nonvolatile memory type that can only be written using an EPROM
programming device. The SBC2000 boards do not have the capability to program EPROMs.
On the SBC2000-332, access to information in EPROM occurs at approximately half the speed
of accessing information in Flash or RAM.
The boot ROM is a socketed byte-wide device that sits in the EPROM slot. Boot ROM can
be 128k, 256k, or 512k bytes (the SBC2000-332 may also use a 1M boot ROM).
The boot ROM on the SBC2000-332 is active for addresses 0x000000 to 0x0FFFFF (or the
first megabyte) of address space, corresponding to its size. On the SBC2000-188, the
boot ROM occupies addresses 0x80000 (or 0xC0000, or 0xE0000, depending upon size) to
0x0FFFFF.
All Vesta ROMmed languages use one wait state in the boot ROM. The access time requirement
for boot ROM is tabulated below.
ROM Speed | Min. Wait State |
80 ns or faster | 0 |
120 ns or faster | 1 |
180 ns or faster | 2 |
Flash Memory
Flash memory is large-capacity nonvolatile storage with fast read access. A single location
can be written multiple times, but there are restrictions on subsequent writes.
On the SBC2000-332 Flash memory is available in sizes ranging from 512Kbyte to 1Mbyte.
On the SBC2000-188 Flash is available in 512K devices and is accessible as an 8 bit byte
read or write.
Each sector of the flash is 0x10000 (64k) in size. Flash starts at 0x200000 in the SBC2000-332
and 0x80000 in the SBC2000-188. Vesta Basic is stored in the lowest two sectors (0, &
1) on the SBC2000-332 and the highest three sectors on the SBC2000-188 (5, 6, & 7).
Flash memory is similar to EPROM in that "1" bits may be changed to "0"
but a "0" cannot be individually changed to "1" until the sector
is erased. Although any 16 bit word is accessible as a write operation, erasing must
be done on a sector basis. Vesta software drivers organize the different sized physical
sectors into 64k byte logical sectors. Erasing a sector typically takes less than 2 seconds,
but may take as long as 30 seconds.
Besides providing routines to read and write individual locations, VMTB supports placing
tasks and arrays in flash.
Flash memory is primarily used as a convenient method of storing application tasks.
Because Flash is 16 bits wide on the SBC2000-332, Vesta Multi-Tasking Basic will run
about twice as fast when the execution engine is installed in Flash instead of 8bit wide
ROM.
Flash may also be used to store data gathered by the application program. The programmer
must be aware of several issues when designing a program using flash as data storage.
· Flash memory is organized as 65,536 byte sectors.
· Once an element of a sector is written, the entire sector must be erased in
order to re-write that element.
· A flash memory location may be written and erased a maximum of 100,000 times.
The number of sectors available depend on the size of the flash device. The SBC2000-188
has one socket that can be occupied by either a 512k flash device, or a ROM device of
up to 512k. The SBC2000-332 may have a 512k or 1 Megabyte flash device installed.
Vesta Basic occupies the first two sectors of flash on the SBC2000-332 and the last three
sectors of flash on the SBC2000-188.
Sector | SBC2000-332 | SBC2000-188 |
0 |
Vesta Basic | Task storage |
1 |
Vesta Basic | |
2 |
Task Storage | |
3 |
||
4 |
Array data storage | |
5 | Vesta Basic | |
6 | Vesta Basic | |
7 | Vesta Basic (last sector of 512k) | |
8 | ||
9 | ||
A | ||
B | ||
C | ||
D | ||
E | ||
F | Array data storage |
The flash memory on the SBC2000-332 is rated at a minimum of 100,000 write cycles.
Warning! Flash memory has a life of approximately 100,000 program cycles. The smaller
serial EEPROM on your Vesta single-board computer has a life of 1,000,000 program cycles.
This limitation is important to keep in mind if you create a program that stores repetitive
data, such as tracking operations at one-second intervals. At this rate the EEPROM will
reach the end-of-life in less than 2 weeks. Store frequently updated values in battery-backed
RAM.
EEPROM
Memory
The serial EEPROM is a small-capacity nonvolatile storage device intended for small amounts
of data that does not change often, if at all. It is designed to hold things like serial
numbers and infrequently updated operational parameters such as last operator settings
or calibration factors.
EEPROM is available in various sizes ranging from 128 bytes to 8K bytes. If you use the
EEPROM in your application, you must specify the size of the EEPROM on your board in
your application, using the EEPROM_SIZE() command. See EEPROM_SIZE.
Each location holds one byte of data, and can be written approximately 1 million times
before it reaches the end of its useful lifetime. This device is accessed via a serial
I/O protocol, so access is slow compared to RAM, EPROM, or Flash. Writes to EEPROM take
several milliseconds to complete. There are no restrictions on the data values of successive
writes to the same location.
Besides providing routines to read and write individual locations, VMTB supports placing
numeric arrays in EEPROM. See Arrays
in EEPROM.
External Memory Devices
The design of Vesta SBCs allows for additional memory devices such as PCMCIA
RAM cards to be used. The MEM_PEEK, MEM_POKE, MEM_DPEEK, and MEM_DPOKE are provided
to control these devices. However, detailed instructions on how to attach and
manipulate such devices are beyond the scope of this manual.
Working
with Tasks
Vesta Multi-tasking Basic provides seven tasks, named Task1 through Task7, for your application.
These seven tasks are available for edit through the Tasks menu of the Vesta Basic IDE.
The IDE monitor is Task0 and is not available to the programmer as a task resource.
Each task is an independent entity. There are no distinctions among the tasks, such as
execution priority or placement in memory. Tasks are not launched in any particular order,
however Vesta Multi-Tasking Basic provides several keywords and constructs that allow
you to synchronize the operation of separate tasks. See Starting
and Stopping Tasks .
Task Size Limitations
Task size is limited to 192k bytes of compiled application code and constant
data. Variable storage and stack space is limited by the amount of installed
RAM, which may range from 128k bytes to 1 megabyte.
You can use the Tools|Task Memory menu to set compile time limits for various
types of memory on a task-by-task basis.
Where to Store Tasks
Tasks may be stored in RAM, Flash, or boot ROM.
The IDE compiles, links and downloads the current task to RAM when you click
the Go button. Tasks in RAM are only executed through the IDE, and are discarded
on reset.
Tasks stored in boot ROM will automatically execute upon reset, unless there
is a task with the same name (Task1-Task7) in Flash. This allows finished applications
that have been programmed in Boot ROM to be easily updated with new tasks downloaded
to Flash or RAM.
Tasks stored in Flash will also automatically execute upon reset. On the SBC2000-332,
tasks stored in Flash will execute approximately 50% faster than tasks stored
in RAM or boot ROM.
The IDE compiles and downloads the current task to Flash when you select Flash|Move
Current To Flash, or all open tasks to Flash when you select Flash|Move All
To Flash.
The IDE creates a boot ROM image suitable for programming directly into an appropriately
sized EPROM device, when you select Tools|Build ROM.
When the IDE downloads a task to a device on the SBC, the new task supercedes
any task of the same name that currently resides on that device.
Note: tasks stored in Flash or ROM cannot be directly controlled (stopped, animated,
etc.) by the IDE. If you wish to interact with a Flash or ROM task via the IDE,
you must recompile and download that task into RAM.
Task
Switch Timing
The Multi-tasker uses a list of active tasks to determine the next task to execute following
completion of the current time slice. Tasks that have not been loaded or have been STOPped
are not on the list. This prevents completed or unused tasks from wasting processor time.
The Vesta Basic system clock is used to keep track of execution time for each task. By
default, each task is allocated five 10-millisecond ticks of the system clock, which
comes out to 50 milliseconds. A task can assign itself more (or fewer) ticks by using
the Set Timeslice To n command. See SET
TIMESLICES TO n.
The time between power on reset and execution of the first Vesta Basic statement is about
0.4 seconds on the SBC2000-332 and about 2.3 seconds on the SBC2000-188.
Starting and Stopping Tasks
Vesta Basic keywords START, STOP, SUSPEND and RUN, allow any task to control
other tasks, including itself.
START [task#] Executes the task from the beginning.
STOP [task#] Suppresses the Multi-tasker from allocating time to the specified task.
RUN [task#] Allows the Multi-tasker to resume allocating time to the specified task.
SUSPEND Relinquishes control of the remainder of the current time slice to the next task.
Application tasks are numbered 1 through 7. If the task number is not specified, the
task will restart or stop itself. For example, if Task1 needs to start Task2, use the
following statement in Task1:
START 2
Note: START does not initialize kernel variables and does not de-allocate memory.
For these reasons REBOOT may offer a more all-encompassing error recovery opportunity.
If the Multi-tasker reaches the end of executable code in a task without encountering
an END statement, it will effectively STOP the task. This is especially important
in that the Event-handler cannot execute a procedure in a STOPped task, but
it can execute a procedure in a task that has ENDded.
Task Structure
The simplest Vesta Basic task can be organized into five sections.
Section 1 contains remarks describing the program's purpose and document design.
Section 2 is comprised of procedures, arrays and forward procedure declarations.
Section 3 contains all function and subroutine declarations as well as local
and static variable declarations.
Section 4 is comprised of all the global variable declarations.
Section 5 begins with the first executable statement and is considered the main
procedure.
REM Name and description goes here REM Com.txt - Handles COM Events REM 4-1-2001 by Amed O'Reily
REM Declare forward reference here DECLARE x AS INTEGER ARRAY
REM Define any subroutines and functions INCLUDE "./thingy.txt" FUNCTION zero () AS INTEGER zero=x [0] END FUNCTION value (num AS INTEGER) AS INTEGER LOCAL a AS INTEGER STATIC b AS FLOAT a = num + a b = a / 256 value=num + a END SUBROUTINE report (num AS INTEGER) PRINT num END
REM Kernel and Global variable declarations: KERNEL index AS bleep, sum AS INTEGER GLOBAL index AS int2, sum2 AS INTEGER
REM the main routine starts here with the first executable REM statement. Certain statements such as procedure REM definitions and global variable declarations cannot occur REM after this first executable statement. DIM x[10] AS INTEGER FOR index=0 TO 2 SELECT index CASE 0 sum = zero() CASE ELSE sum = value(index) ENDSELECT report(sum) NEXTTasks are subdivided into various constructs, such as declarations and procedures. Declarations define the names and types of variables that will be used in the task, and must be declared before any code that uses them. See Classes of Variables and Variable Declaration.
Line Format
None of the keywords that make up the statements in Vesta Basic are case sensitive.
In other words, "IF," "If," and "if," are all
equivalent. In addition, all built-in procedures and user-defined procedures
are not case sensitive. To make code more readable, we recommend entering all
keywords and built-in procedure calls in upper case and all user-defined procedures
and variables in lower-case.
Spaces are ignored.
Vesta Basic allows more than one statement to share a line of code, if the statements
are separated by colons.
Some statements may not share a line even if separated by colons. They are:
IF INCLUDE ELSE ENDIF WHILE SELECT CASE FOR FUNCTION END DO LOCAL STATIC GLOBAL KERNEL ENDSELECT UNTIL NEXT SUBROUTINE LOOP DECLARE CONSTANTThe REM statement identifies the text that follows on the line as a remark. The compiler will ignore all text to the right of the REM keyword. The REM and the text that follows will not affect the size of the compiled code. A REM statement may follow another statement on the same line, but the two statements must be separated by a colon.
Procedures
Vesta Basic provides several types of procedures that make your program easier to read
and debug. Functions and subroutines are the building blocks of your program, where most
of the work is done. External routines are procedures that are defined in separate files
and are associated with your program using the INCLUDE statement. Functions and subroutines
are executed when called by the main routine or by other routines and must be defined
or declared before any code may call them.
Functions are procedures that can receive data passed to them and return a value (See
FUNCTION
). Subroutines are procedures that can receive data passed to them but do not return
a value (See SUBROUTINE
). Extensions are external procedures that are associated with your program through the
INCLUDE statement (See INCLUDE
).
Vesta Basic Procedures allow you to encapsulate code for individual tasks, making is
easier to program and debug. The variables from each encapsulated procedure can be isolated
from the rest of the program as local variables. By passing a copy of the variables to
serve as its list of arguments, the procedure cannot modify the original variables. With
this method, program behavior is more structured and self-contained.
Many very useful routines are included on your VMTB CD-ROM in the form of examples and
extensions that you can either copy into your application or INCLUDE as part of your
compiled application. The ROADMAP document lists and describes the examples.
The keyword VITAL may be used to protect procedures from event interruptions. The Vesta
Basic event handler monitors various types of events and temporarily diverts control
to the event routine specified by your program when the particular event occurs (see
VITAL).
These event routines and all routines called by the event routine must be defined using
the VITAL keyword. Any routines that must execute without event interruption should use
the keyword VITAL in their definition.
Subroutines
Subroutines are defined using the SUBROUTINE statement, followed by the statements
that make up the subroutine and ending with the END statement. An early exit
to the subroutine may be defined at any point with the RETURN statement.
Subroutines are designed to "encapsulate information." The data passed
as arguments are copies of the variables from the calling procedure. The subroutine
cannot modify the original variables. This keeps program behavior more structured
and self-contained.
Subroutines do not return a value, and therefore are best suited for output
routines such as PRINT, BEEP, or POKE. If you want to give a subroutine access
to a global variable, the global variable declaration must precede the subroutine
definition.
SUBROUTINE tone (freq AS INTEGER, duration AS INTEGER) LOCAL I AS INTEGER BEEP(freq) :REM Beep at frequency FOR I = 1 TO duration REM NEXT I BEEP (0) :REM shut off beeper ENDInvoke the subroutine with the subroutine name or the optional CALL statement, followed by the subroutine name.
CALL tone(333, 400) REM generates a short beep at 333Hz CALL tone(333.0, 400) REM converts the float constant to REM an integerSubroutines must be called with arguments whose types correspond to those described in the definition of the subroutine. Vesta Basic will attempt to convert arguments to the correct type, however conversions between strings and numeric values are not automatically possible.
DECLARE SUBROUTINE nameNeither the keyword SUBROUTINE nor the name you assign to the subroutine are case sensitive.
Functions
Functions are defined using the FUNCTION statement (which indicates the names
and data types of any arguments passed to the function, and the value the function
will return) followed by the statements that make up the function and ending
with the END statement. An early exit to the function may be defined at any
point with the RETURN statement.
Functions can accept more than one value as data but can only return a single
value to the calling procedure.
FUNCTION square_root (num AS FLOAT) AS FLOAT square_root = num ^ 0.5 END
There are two ways to invoke the function:
1. Assign its return value to a variable.
result = square_root (x)
2. Use the return value in an expression.
result = 7+square_root (9)
Functions must be called with arguments of the corresponding types.
Example of what not to do:
FUNCTION sq (value AS INTEGER) AS INTEGER sq=value*value END VAR=sq("ABC")Functions may invoke other functions, subroutines, or themselves. In order for another procedure to invoke a function, the function must either be placed before the invoking procedure in the task code, or the function must be declared at the beginning of the task, using the following syntax:
DECLARE FUNCTION <name> AS <type>
Neither the keyword FUNCTION nor the name that you assign to the function, are case sensitive.CRITICAL and VITAL Procedures
There are occasions when it is necessary to ensure that a procedure will complete
without interruption. Vesta Basic provides two keywords for such situations:
VITAL suppresses the execution of the Multi-tasker and the Event-handler.
CRITICAL suppresses the execution of the Event-handler only.
The Multi-tasker is the portion of the Runtime engine that controls time sliced
task switching. The CRITICAL declaration will prevent Vesta Basic's Multi-tasker
from swapping tasks before the procedure is completed.
The Event-handler is the portion of the Runtime engine that passes control to
the appropriate routine in response to certain conditions such as an error condition.
The VITAL declaration will prevent the Multi-tasker from swapping tasks and
the Event-handler from responding to ON events before the procedure is completed.
Sources of events that may be deferred until the procedure completes are: interrupts,
communication events, timer events and run-time errors such as division by 0.
Data
Types
Vesta Multi-Tasking Basic recognizes four data types. The data types and their capacities
are listed in the chart below.
SBC2000-332 and SBC2000-188 | ||
Type | Storage | Range |
Integer | 16-bit signed integer | -32,768 to 32,767 |
Long | 32-bit signed integer | -2,147,483,648 to 2,147,483,647 |
Float | Single precision float, 7 significant digits | +/-1.7 x 10 +/-38 |
String | Alphanumeric string | 254 characters |
Each string variable is allocated 256 bytes of memory no matter what length the value
assigned to that variable may be. The maximum length of a string's value is 254 characters.
By default, numbers are assumed to be in decimal format. The assumed format can be changed
to hexadecimal using the HEX command (see HEX),
and can be changed back using the DEC command (see DEC).
When the format is decimal, numbers will be interpreted as hexadecimal, when preceded
by the symbol 0x ("zero, x"), followed by up to four hexadecimal digits for
integer values and 8 digits for long values. These digits may be 0 thru 9 or A though
F. The A though F are not case sensitive.
When the format is hexadecimal, numbers will be interpreted as hexadecimal even when
expressed without the preceding "0x", and the letters A though F are allowed
with out generating an error.
Naming Conventions
The names of variables, subroutines and functions must conform to these rules
Classes of Variables
Variables must be declared before they are used and in each task where they
are used. Declaration establishes the data type of the variable, and where the
variable will be used: There are four storage classes:
GLOBAL var1 AS INTEGER SUBROUTINE foo() LOCAL var1 AS INTEGER :REM Distinct from :REM global var1, but confusing var1 = 1 :REM Only changes local var1, :REM global var1 unaffected END
Global Variables
Global variables must be declared before any executable code in the task. When
Globals are declared after all subroutine or function definition, the programmer
assures that information contained in those procedures will not be shared with
the rest of the task.
If you need to access to a global variable within a procedure, that variable
must be declared before the first procedure that references it.
A good practice is to designate, at the beginning of your code, a small set
of global variables that must be accessible to all procedures. Declare the remainder
of the global variables just before the main procedure. Instead of using global
variables in procedures, pass values to procedures as needed.
Kernel Variables and Inter-task Communication
Inter-task communication is accomplished through the use of Kernel variables.
A common inter-task protocol uses a flag variable and separate variables that
hold the data to be passed.
In the example below, Task1 is sending data to Task2. The variable called "info"
contains the data to be exchanged. The "flag" variable controls the
exchange.
Task 1
GLOBAL loopcntr AS INTEGER KERNEL info AS INTEGER, flag AS INTEGER FOR loopcntr = 0 TO 9 info = loopcntr flag = 1 :REM flag tells Task2 that :REM Task1 is waiting for data DO :REM wait for task2 to execute SUSPEND :REM SUSPEND hands control to :REM the next task LOOP UNTIL flag = 2 :REM when flag=2, task2 is done NEXT loopcntrTask 2
KERNEL info AS INTEGER, flag AS INTEGER DO WHILE 1 DO :REM wait for task 1 to change the :REM flag variable to 1 LOOP UNTIL flag = 1 PRINT info :REM This is where Task2 :REM uses info. flag = 2 :REM Set flag to tell Task1 :REM that Task2 is ready for :REM more data. LOOPWhen several tasks are monitoring the same flag, the test/set sequence must not be interrupted by another task.
The following example illustrates how to prevent more than one task from accessing a shared resource.
KERNEL lock AS INTEGER VITAL FUNCTION lockit() AS INTEGER IF lock=0 lockit=1 lock=1 ELSE lockit=0 ENDIF END SUBROUTINE lock_resource() DO WHILE lockit()<>1 SUSPEND LOOP END SUBROUTINE unlock_resource() lock=0 END ... REM any task accesses the resource thus REM wait until resource is available lock_resource() REM use resource access_shared_resource() REM release to other tasks unlock_resource()These issues are especially important during the allocation of memory resources. The DIM statement allocates memory and assigns arrays to specific memory addresses. If an array assignment in a task relies on the results of a DIM statement in another task, it is imperative that the first DIM statement executes before the second. This can be controlled by using a kernel variable as a flag.
Variable Initialization
Numeric variables are initialized to zero. String variables are initialized
to an empty string.
Array variables are never initialized by Vesta Multi-Tasking Basic; they must
be initialized by application code.
Global and static variables are initialized only once, at task startup. Local
variables are initialized on every invocation of the procedure that declares
them. Kernel variables are initialized when the first task that declares them
first references them. They are not re-initialized until the SBC2000 is reset.
Arrays
Vesta Multi-Tasking Basic supports arrays of integers, longs, floats and strings. Arrays
may be stored in RAM, FLASH, ROM or EEPROM.
SBC2000 | |||
Array Type | -332 | -188 | element size |
Integer | * | * | 2 |
Long | * | * | 4 |
Float | * | * | 4 |
String | * | * | 256 |
Arrays may be of either one or two dimensions. Square brackets are used to denote array
indices.
Array indices start at 0 and are of type LONG. The DIM statement establishes the range
of the index or indices. If a reference to an array is outside this range a run-time
error will result.
Individual array elements may be passed to procedures as arguments.
Array data is not zeroed upon reset. Array variables are never initialized by Vesta Multi-Tasking
Basic.
Creating an Array
The programmer has the choice of creating arrays in flash or RAM as well as
the choice of data type. The creation of an array is a one or two-step process.
DECLARE x AS INTEGER ARRAY (... any procedures ...) DIM x[256] AS INTEGERThis creates an array of 256 elements whose index is 0 to 255 has been created in RAM. An attempt to access array elements with an index is less than zero or greater than 255 will result in a run-time error.
Two
Dimensional Array in RAM
Creation of a two dimensional array is straightforward.
DIM xyarray[10,20] AS INTEGER
Creating the Largest Possible Array
Vesta Multi-tasking Basic allows you to use the largest available block of contiguous
RAM to create an array for applications such as data logging.
DIM x[RAM_AVL()/2] AS INTEGERRAM_AVL() returns the number of bytes of the largest block of RAM currently available. See RAM_AVL.
String Arrays
Creation of a string array is easy
DIM z[1000] AS STRINGEach element requires 256 bytes, so a string array with these dimensions would take a quarter Meg of RAM. However, creative programming can be used to access data within the string and allow you to squeeze more information into each array element.
Arrays in EEPROM
Arrays in EEPROM are the ideal place to store configuration parameters, operating
set points, sensor linearizing curves or other infrequently changed operating
data. Arrays in EEPROM are non-volatile and will be retained throughout a power
cycle. Individual bytes of the EEPROM may be modified without the concern of
erasing an entire sector like in Flash memory. The number of write cycles of
an EEPROM byte is 1,000,000, so do not create array elements in EEPROM whose
values are modified frequently. The size of your onboard EEPROM is dependent
on the product that you purchased, typically 4k or 8k bytes.
DIM language [4] as INTEGER IN EEPROM
Arrays in Flash
Data stored in flash memory is secure throughout a power cycle of any duration.
DIM temperature[100] AS INTEGER IN FLASHUnfortunately, any element of an array in flash may only be written once before the entire 64k byte sector must be erased. The challenge is to identify and erase the sector in which an array resides.
start-of-flash = 0x80000 on SBC2000-188 start-of-flash = 0x200000 on SBC2000-332 sector = (ADDR_OF(arrayname) - start-of-flash)/65536SIZE_OF_FLASH() returns the capacity in bytes of the flash device installed on your SBC2000.
Placing an Array at a Specific Location in Flash
Vesta Basic allows you to assign an array to a specific location in Flash. To
do this, you must know the size of the tasks you will be putting in flash (so
that you don't place an array in the middle of code space) and the size of the
flash device.
Each sector of the flash is 0x10000 (64k) in size. Flash starts at 0x200000
in the SBC2000-332 and 0x80000 in the SBC2000-188. Vesta Basic is stored in
the lowest two sectors (0,1) on the SBC2000-332 and the highest three sectors
on the SBC2000-188 (5, 6, & 7).
For example, to place our array at the beginning of the 4th sector on an SBC2000-332,
execute the following dimension statement:
DIM x[32767] AS INTEGER = 0x240000On the SBC2000-332, Flash starts at 0x200000, and to get to the forth sector we would add 0x40000 to get the 0x240000.
DIM x[32767] AS INTEGER = 0xC0000Notice that an entire sector has been allocated to the x array. To erase the sector use the following statement.
FLASH_ERASE(4)
Sharing
Array Data Between Tasks
The ability to place an array at a specific location in memory can be used to share array
data between tasks. The array is created in the normal fashion by the first task, the
location of the array is passed to the second task in a kernel variable and the second
task dimensions an array at the same specific location.
Task 1
KERNEL array_location AS LONG DIM shared_array[100] AS INTEGER array_location = ADDR_OF(shared_array)Task 2
KERNEL array_location AS LONG DO REM this is very important you must wait for the other task REM to allocate memory for the array LOOP UNTIL array_location <> 0 DIM shared_array[100] = array_locationTo learn how to ensure that a procedure will complete without interruption, see CRITICAL and VITAL Procedures.
Constant Data
The keyword CONSTANT identifies data that will not change during the execution
of the program. Constant variables are saved differently than ordinary data,
and the compiler has a few tricks for speeding up the code when constant variables
are used.
The Vesta Multi-tasking Basic compiler handles constant strings, numbers and
arrays differently, so each is covered in it's own section below.
Numeric Constants
The range of an integer constant is -32,768 to 32,767. Integer constants can
be expressed in decimal or hexadecimal format. When expressed in hexadecimal,
the number must be preceded by a zero and a lower case "x", followed
by up to four hexadecimal digits. These digits may be 0 thru 9 or A thru F.
The A thru F are not case sensitive.
The range of a long constant is -2,147,483,648 to 2,147,483,647. Long constants
can also be expressed in decimal or hexadecimal. When expressed in hexadecimal,
the number must be preceded by a zero and a lower case "x", followed
by up to eight hexadecimal digits.
Floating point constants may be expressed in two ways: In standard exponential
form (scientific notation (e.g., +3.14159 E+0), or standard decimal format (e.g.,
3.14159). The range of floating point constants is +/-1.7 x 1038. The accuracy
of floating point numbers is about 6.5 significant digits. For example, if the
number 12345678 is assigned to a floating point variable, the result will be
greater than 12345650 and less than 12345700.
Enclose a single character in single quotes to return the ASCII value of that
character (x='A' would result in x containing 65).
IF key='A' OR key='a' IF key=65 OR key=97Both statements are logically equivalent, but the first one is easier to understand.
String Constants and Literals
A literal string is anything enclosed in double quotes.
CONSTANT arrow AS STRING="->"
A string constant is assigned to a string variable with an assignment statement.
string1=arrowAny ASCII character, including control characters, may be embedded into a string by using a backslash character followed by the ASCII code in the range 0-255, that represent the character.
string1="abcdefgh"
CONSTANT crlf AS STRING = "\013\010" PRINT x, j, z, crlfSome common control characters:
Sequence Meaning \010 line feed \013 carriage return \012 form feed \009 tabFor a complete list of the ASCII character set, see Appendix A.
Arrays of Constant Data
Arrays of Constant Data may be created, and require less memory space than providing
the same information using READ/DATA statements would.
REM the following is on one line DIM array_of_constants[10] AS INTEGER CONSTANT = [0,1,2,3,4,5,6,7,8,9,]The contents of the array can appear on multiple lines, but the first portion of the statement (from "DIM" through "[") must be on a single line.
Assignments Using Mixed Data Types
It is possible to assign an expression of one data type to a variable of a different
data type. The only limitations are based on the ability of the receiving variable
to hold the value of the expression. For example, a long constant value cannot
be assigned to an integer variable if the long constant value is outside the
limits of the maximum possible integer value. The rule holds true, similarly,
for float constants assigned to integer or long variables. Both of these events
will generate a compiler error.
intvar = 1000000 :REM results in a compiler errorAssigning a float constant to long or integer variables is permitted, but the variable will contain only the integer portion of the truncated floating constant. The floating point number is not rounded to the nearest integer before the value is truncated.
intvar = 3.9 :REM results in intvar containing 3During run time, a mixed data-type assignment will produce the same results as during compile time. No errors will be generated if the receiving variable is not large enough to hold the assigned data. Instead, the upper or lower limit of the data type will be stored.
longvar = 1000000 intvar = longvar REM results in intvar containing 32,767Conversely, if an integer variable is assigned to a long, the integer value will be sign extended.
floatvar = 2/3results in floatvar containing 0.0 because the result of the integer division is 0.
floatvar = 2/3.0will result in floatvar containing 0.666 . . . because the integer 2 will be promoted to a float 2.0, and the division will have a floating point result.
Expression Operators
Vesta Multi-Tasking Basic supports the following math operators:
+ add
- subtract and unary minus
* multiply
/ divide
\ modulus (remainder)
^ exponentiate
Programmers must remember to take into account the data range when using math
operations on integer and long data types. These data types are stored as 16-
and 32-bit signed integers. Operations are performed as 2's complement. Adding
1 to +32,767 will result in -32,768 for an integer variable.
Dividing by zero results in a run-time error. A run time error also will result
if an attempt is made to exponentiate a negative number to a fractional exponent
(e.g., take the square root of -1).
Expressions with Mixed Data Types
When data-type expressions are mixed, lesser data types are sign extended to
wider data types. The result is expressed in the widest data type involved in
the expression.
For example:
intvar + floatvar will have a float result longvar + intvar will have a long result
Logical Operators
Vesta Multi-Tasking Basic supports the following bitwise logical operators:
AND returns TRUE if both corresponding bits are true
OR returns TRUE if either corresponding bit is true
XOR returns TRUE if either but not both corresponding bit is true
NOT inverts all bits and returns the result
These operators can only be used on integer and long values.
Relational Operators
Vesta Multi-Tasking Basic supports the following relational operators:
Combining Relational and Logical Operators
Relational operators and logical operators are designed to work together as
well as independently.
IF (a<b) OR (c<>0)combines the logical operator "OR" with the relational operators, "<" and "<>".
"came" >= "cameo" AND 3.0 = 3.This expression evaluates to a false, (represented by the number 0). The two relational expressions are evaluated first because relationals take higher precedence. The string expression evaluates to an integer of zero because "came" has an earlier spelling than "cameo." The number expression evaluates to true, which is the number 0xFFFF (-1) because 3.0 = 3. The results of both comparisons are bitwise ANDed.
Operator Precedence
Unary and special operators and (- and NOT) have the highest precedence, followed
in order by:
MIN MAX ABS SIZE_OF ADDR_OF ROW_OF COLS_OFand have equal precedence to "-" and" NOT".
String
Functions
Vesta Basic provides the following string functions:
Substring Pointers
Substring position pointers allow easy manipulation of text within a string.
Vesta Multi-Tasking Basic supports a complete range of string operations using
substring pointers AND the curly brace operator to identify a substring and
what to do with it:
string1{3} :REM Refers to the 4th position in the string string1{4,8} :REM Refers to the 5th through 9th position in the string.The first element (character or symbol) of a string is position 0. The position following the last is identified with a "$".
Substring pointers may be used on either side of the equals sign with a subtle difference in meaning:
string1 = "01234567" xx1 = string1{2} :REM xx1 is "2" xx1 = string1{2,5} :REM xx1 is "2345" string1{2} = "x" :REM string2 is "01x234567" string1{5,6} = "x" :REM string2 becomes "01x23x67"When the substring pointer is on the right side of the equals sign, it refers to a character or characters that something can be set to. When it is used on the left side of the equals sign, a single pointer refers to an insertion position, and double pointers refer to a span of characters to be replaced.
Substring Insertion
When a single pointer is used to identify the insertion point in the string,
the text from the insertion point to the end of the string will be shifted to
the right of the inserted text:
string1 = "0123456" string1{2} = "abc" REM string1 now equals "01abc23456"
Substring Replacement
When two pointers are used to identify the beginning and end positions of the
characters to be replaced, the characters from the first position to the last
will be deleted and the new text inserted in its place:
string1 = "0123456" string1{2,3} = "abc" REM string1 now equals "01abc456"Note that the number of characters deleted need not equal the number of characters inserted.
Substring Removal
When a character or a set of characters is replaced by a null or space, the
effect is to delete the characters:
string1 = "0123456" string1{2,3} = "" REM string1 now equals "01456" string1 = "0123456" string1{2,3} = " " REM string1 now equals "01 456"
Substring Reversal
A substring will be reversed if the first of the two pointers is greater than
the second:
string1 = "0123456" string1{4,2} = "abc" REM string1 now equals "01cba56"
Pointer Rules
Pointers may be an integer, a variable, an expression or a special pointer (the
$ symbol). The $ symbol represents next available position in a string (LEN(string)+1).
The $ symbol may not be used as part of an expression.
string1 = "" FOR index = 0 to 5 string1{$} = STR(index) Next REM string1 is now " 0 1 2 3 4 5"The maximum length of a string variable is 254 characters. The permitted range of substring pointers is 0 to the position following the last defined element (LEN(string)+1). Values outside are forced into this range:
string1 = "0123456" string1{12,14} = "abc" REM string1 now equals "0123456abc"Insertion of a substring that creates a result greater than the maximum string size will cause the last characters of the destination string to be dropped.
Substring Pointers and String Functions
Substring pointers may be used with string functions such as LEN() and ASC()
to perform some very powerful operations:
String1 = "abcdefg" num1 = LEN(string1{5,$}) REM NUM1 now equals 2 string1 = "123456" num1 = VAL(string1{0,3}) REM num1 now equals 123 x = string1{LEN(string1)-4, LEN(string1)-1} REM x becomes "3456"
String constants, literal strings, and string array elements cannot be operated
upon or use substring position pointers directly. However, this limitation can
easily be overcome by using a string variable as a holder of data to be operated
upon. Array data can then be moved into an array element.
Vesta Basic Extensions
Vesta Basic Extensions are external procedures written in C that extend the
Vesta Multi-tasking Basic language. There are a total of 256 "slots"
built into the Vesta Basic architecture and reserved for external procedures.
Some of these slots are used by the external procedures discussed in this section.
Many others are used by Vesta Basic "internals", and 32 slots, numbered
0-31, are reserved for programmers who want to write a few specialized routines
in C to extend their Vesta Basic program.
In order to write your own extensions you will need the Vesta C Library and
a C compiler. You can download your extensions and incorporate them into a new
flash image from the Vesta Basic IDE using the Tools|Extensions menus.
For more information on how to write extensions, consult the Vesta C library
manual.
Using Extensions
Vesta Basic extensions are usually declared at the beginning of the source code
for any task that makes use of them. External procedures are declared like any
other procedure, except that you must specify the slot number of the extension.
This is done by following the declaration with a colon and an integer that indicates
the slot number of the extension. You can call the extension procedure anything
you like, but we suggest that for clarity, you use the names provided here.
Names of extension procedures are not case sensitive.
Example:
SUBROUTINE Mynewthing(bit AS INTEGER):43 FUNCTION Mydoodad(bit AS INTEGER) AS INTEGER:45