Crashcourse: How to programm 'Avise 4.3':
(updated 11 December 2005)

 

1. Installation, Startup: This crashcourse assumes that you have a completely assembled hardware and a microcontroller programmed with 'Avise' firmware.

Start a terminal program with following preset:
19200 baud; 8 data bits, no parity, one stop bit (8N1); no handshake; local echo OFF; 1:1 direct data transfer (i.e. no transfer protocol, no call procedure). Select that COM port you wish to connect with 'Avise'.
To send data from the terminal to 'Avise', a new line should be entered only with 'Carriage Return' (hexD). To display received characters properly, however, the terminal must add a 'Line Feed' (hexA).
As a standard solution we recommend the special terminal programm 'Atool', which is included in the 'Avise' download package.

Connect your 'Avise' hardware to the seleceted COM port of your PC and finally switch on the power supply.

Now you should see the start prompt on your display: "Avise 4.3 ok" (or similar). Then type some arbitrary characters and finish the line with <RETURN>. Every typed character should reappear immediately on the PC display. After <RETURN> a text should appear, which contains "ok" or a question mark. Then you may assume that hardware and firmware installation work correctly.
When strange signs appear on the screen, check the baud rate. If nothing appears on the PC screen, first check the COM port and cable with a loopback and the supply voltage. If all that works, the problem seems to be the 'Avise' module: defective hardware or faulty programming.

'Avise' does not distinguish between uppercase and lowercase letters. The following examples are typed in uppercase letters due to the 'official' notation. Typing lowercase letters is more comfortable, of course.

If unexpectedly startup messages of 'Avise' appear during program execution, probably the program hang up and 'Avise' was reset by the watchdog timer of the microcontroller. Another reason may be a very unstable or noisy power supply which influences the brownout detector.
If the program hangs up without sending the reset message, control can be re-established at any time by typing the 'tilde' key ('~' = hexFE) on the terminal keyboard. This character is catched and evaluated at very low system level by the UART interrupt handler. As a consequence, the 'tilde' never may be used in names of user functions.

2. The Operators ('Words', Commands, Functions, Subroutines) of 'Avise':

Working with 'Avise', you can enter simple commands directly from the keyboard. But you can write and compile complex structured programs, too.
Due to its simple stack oriented parameter transfer, 'Avise' technically does not distinguish between 'operators', 'commands', 'functions', 'procedures' or simply 'words'. As a lingual convention in this text, commands built into the kernel shall be called 'operators' and commands programmed by the user shall be called 'functions'.
To display a list of all currently available "operators" and "functions" at your terminal screen, type "OPS <RETURN>". You find a detailled description of all operators built into the 'Avise' kernel in the glossary. Alternatively you can click into every operator name at the left border frame to get the description.

Commands are entered at the terminal program as text lines or command lines. 'Avise' does echo every character. But execution of the command line is not started before the line is entered completely and finished with <RETURN>. A command line may contain max. 80 characters.

Disgression:
Generally in programming languages, a 'token' is an elementary unit of meaning. At user level a 'text token' is a word, i.e.a piece of text which is enclosed by space characters - or formulated more generally - enclosed by 'delimiters'. At runtime a 'token' is a specific byte code or cluster of some bytes to identify a specific operation. As will be shown below, the actually executed sequence of tokens may differ considerably from the sequence of text tokens in the source code! Avise 4 is "subroutine threaded" which means that any compiled token is represented by a call of a subroutine, which contains the specific runtime code of that token.

'Avise' can operate in two different states of operation: "direct execution" or "compiling". In the state of direct execution every text token is processed immediately. In the compiling state the corresponding sequence of token codes is generated out of the source code and integrated into the system as a new function, which has its own token code and its own unique name as a text token. From now on this token can be mounted as a brick into new functions with higher complexity... and so on. The maximum depth of nested calls ist limited only by the size of the AVR processor return stack. As a simple rule it can be stated that normally a depth of 10 calls is safe. But especially every FOR...NEXT structure takes 5 extra entries in the return stack, which may reduce the maximum depth of nested calls considerably.

With 'Avise', complex programming tasks are preferably solved 'bottom up'. This means: Elementary routines like hardware handler are developed and tested each first. These are mounted ascendingly into more complex sequences. The resulting product finally is the "main program".

A significant difference exists between the operators which are basically integrated in the 'Avise' kernel (as fast running assembler routines) and the user programmed functions: the latter ones need more CPU time for execution, but are still quite fast due to the subroutine threading.

3. Numbers, Constants and Variables

The (virtual) numeric processor of 'Avise' exclusively operates with 16bit integer numbers. The range of (signed) numbers is -32768(hex8000) to +32767(hex7FFF). -1 is represented as hexFFFF. This technique of cyclic representation of numeric values may be confusing at a first glance, but is common use in computers. In some cases numbers are regarded unsigned, then the 16bit range is 0 to 65535(hexFFFF)
After start, 'Avise' operates with decimal numbers. The dollar operator $ switches to hex numbers. The ampersand operator & switches back to decimal calculations.

Note: in normal use, $ and & are commands which change the number base until the next respective command. Like every command, they have to be delimited by spaces. As an exception, $ can be used as a prefix (without space) to enter a single number in hex format. As another exception, with the command .$ a single number can be sent as an ASCII formatted hex number to the terminal, independent of the active number base.

When $ and & are used during compilations, there arises a problem: are these operators effective at compile time or at runtime? 'Avise' does handle them as follows: When $ and & are used in definitions of user functions, they have no influence at compile time. They only switch the number base at runtime. During compile time generally the previously active number base remains active. If the number base shall be modified during compile time, we suggest to use $ as prefix where appropriate.

Constant numbers, which are used more than one time in a program, should be called by symbolic names. In 'Avise', you can declare a CONSTant:
  2413 CONST BASIS
The declaration must be done BEFORE the first use. The value of the CONSTant has to be entered first. It even can be the result of a calculation.
The name must not be identical with another operator or another user defined function or with a numeric expression. (Attention, words like AFFE, DEC, FACE, DEAD are valid hexadecimal numbers!). The same applies to all names of variables and functions!

A constant cannot change its value at later time. To store intermediate results e.g., VARiables (16 bit integers) are used, which are declared as follows:
  VAR OFFSET
Directly after declaration and after system (cold-)start, every variable is initialized with value 0.

Variables declared this way are 'global', i.e. can be called from any function. This is simple and compact but has some disadvantages for instance when functions are calling themselves recursively. In complex programs you may forget, that you have already used the same 'unimportant' variable perhaps as loop counter in another function. Parameter handling by stack is less clear but avoids these problems.

'Avise' knows only one type of variable: 16 bit integer. With the operators BSET, BLCR, BTST (details see glossary) the user can administrate his own bit flags within variables.

After a variable is declared, it returns the ADDRESS !! of its data memory when called by name. See below "Read and Write random Memory Cells".

3. The data stack:

Almost all interpreter languages internally work with a 'data stack' memory. The classical textbook example for a stack is the stack of plates in your kitchen cupboard: for a meal you take the uppermost one, the cleaned plats are put back on top. The latest cleaned plate is always the top one.
Though you can calculate quite elegantly with stack mathematics - especially without the need of parentheses - it didn't succeed. Possibly because it does not correspond with the way of solving equations people have learned at school. Standard is instead a variable (=register) oriented programming paradigm. But inside the computer (when running an interpreter language) still a stack is working to load data from variables, combine them and store them back to variables. This way, Avise 4.2 works very near at the root of machine computing.

The number put last on the stack is called "top of stack" (shortened TOS). The second element of the stack is called "next of stack" (shortened NOS). When a number, a variable or a constant is called, its actual numeric value is put on the TOS, this way the former TOS becomes NOS.

In its basic operation, a stack engine combines the TOS with the NOS, deletes the NOS and returns the result on the TOS. (The stack shrinks.)
There is a set of operators too, which only manipulate the TOS, e.g. INK, DEK, ABS and NOT.

4. Arithmetics, Logical Operations and Comparisons

Arithmetic operators combine 16 bit integer numbers to resulting 16 bit numbers. Addition and subtraction show cyclic overflow behaviour, i.e. are applicable to signed and unsigned numbers. Multiplication and division are processed "signed".

  • + (Addition)
        Example: 2 3 +
  • - (Subtraction: left argument is subtracted from right argument)
  • * (Multiplication)
  • / (Division: the NOS is divided by the TOS. The remainder is suppressed)
  • MOD (Modulo operator: executes a division but returns only the remainder. The quotient ist suppressed.
  • To optimize calculations of the rule of three the special operators */ and */MOD are provided.
Bitwise logical operations are executed with 16 bit binary numbers. Every bit of the left operand is combined with the respective bit of the right operand. No carry or borrow between the bits.
  • AND (bitwise AND operation)
        Example: $A5 $B3 AND
  • OR (bitwise OR operation)
  • XOR (bitwise EXCLUSIVE-OR operation)
Compare operations have the result 1 when the result of the comparison is TRUE and the result is 0, when the result is NOT true (i.e. FALSE).
    Example:
   2 3 <   returns 'TRUE'=1, but
   4 4 <   returns 'FALSE'=0 to the TOS.
  • Compare operators:
    • Ø=  TRUE if TOS is equal to zero (Boolean inverter)
    • =   TRUE if NOS equal TOS
    • <>  TRUE if NOS unequal TOS
    • >   TRUE if NOS is greater
    • >=  TRUE if NOS is greater or equal
    • U>  TRUE if NOS is greater (unsigned)
    • <   TRUE if NOS is less
    • <=  TRUE if NOS is less or equal
    • U<  TRUE if NOS is less (unsigned)
All comparisons are done with signed numbers except U> and U<, which take operands as unsigned.

5. Read and Write random Memory Cells:

Differing from previous versions of 'Avise', we have a set of BYTE and WORD read and write operators now.

  • WR and RD are WORD operations, which are most useful to write into and read from VARiables. To get consistent results, only use EVEN addresses.

  • WB and RB however are BYTE operations, which may be used to manipulate CPU internal registers for special user specific variations of the standard behaviour of 'Avise'.

  • In a similar way the operators ERB and EWB are used to read one single byte out of the CPU internal EEPROM or to write (burn) it there. As the symbol table of 'Avise' is placed in the EEPROM, these commands have to be used with care.
Any of these write operations is used as follows:
First enter the value to be written (becomes NOS), then enter the address where written to (becomes TOS). Both stack entries are deleted during the write operation.
    Example:
  VAR BACKUP
  374 BACKUP WR

Any of these read operations is used as follows:
Enter the address from where to read (is TOS). After the read command is executed, the read value is TOS, too.
    Example:
  VAR BACKUP
  BACKUP RD .

6. The 'Avise' Compiler:

A great advantage of 'Avise' is the possibility for the user to program his own functions. These may not only call the kernel operators, even previuosly written user functions can be called. Every function wears its own name.

As in 'Avise 4.2' the symbol table is built into the CPU internal EEPROM, it is strongly advised to create short names, because the maximum number of user definitions depends on the limited EEPROM space. Every entry in the symbol table takes (name length + 3)bytes. So into 512 bytes of EEPROM will fit about 63 definitions, when the average name length is 5 characters.

The colon operator :   - separated with a space from the following - starts the compiler.
The first word in the source code will be the name of this new function.
Subsequent text tokens (numbers, constants, variables, operators and functions) are not executed directly but they are restructured and compiled as token code.
First, the code is built temporarily in the microcontroller SRAM. When the compilation is terminated successfully, the complete code block is burnt into the microcontroller flash memory.
The operator RET always must be the last of a user function because it finishes the compilation process and switches back to the mode of direct command execution. The programmed functions are kept stored even when the CPU power is switched off.

As 'Avise' contains its own mini operating system in the AVR program flash, compilation may be done 'incrementally' following the "bottom up" method. Starting from elementary hardware handlers and specially needed basic routines little by little more complex routines are created. The final product is the 'main prgram'. References are only possible 'backwards' to functions, variables, constants which are already burned into the memory. No 'forward references' are possible. When a name is used double, subsequent calls of this name refer to the youngest definition or declaration. But references programmed before remain valid, even when the elder name is overwritten.

Of course, it is possible to program 'Avise'in a way "top town", i.e. the set of program modules is first written as dummies which by and by are fillid up with content. But then a completely new compilation is necessary for every program update like ist is performed with other single chip interpreters, too.

7. Structuring Techniques:

Structuring techniques only can be applied with compilation, not during direct execution of a command line. But user programmed functions which contain structured code sequences can always be called directly by name.

Conditional execution of program parts:

IF... ELSE ... ENDIF
The ELSE alternative is optional.

First in this construction, IF checks the TOS. If it is 'TRUE', i.e. unequal 0, the code between IF and ELSE (respectively IF and ENDIF) is executed. If the TOS is 'FALSE', i.e. exactly equal 0, the code between ELSE and ENDIF is executed (respectively nothing is executed when the ELSE part is not present). Differing from other programming languages, there is no THEN and no formal block marks like BEGIN ... END or {...}.
Example:
VAR STATUS
: TEST STATUS RD IF ." TRUE" ELSE ." FALSE" ENDIF RET

<start> <stop> FOR <variable> ... NEXT (counted loop):

<variable> is the name of a previously declared variable, which serves as loop counter. <start> is a number, variable or constant or even a function, which describes the start index of the loop, <stop> accordingly supplies the index of the last loop turn, after which the loop is finished. Via signed compare of the start and stop index automatically is determined if the loop is run with ascending or descending loop counter.
After each loop turn, NEXT adds (or subtracts) 1 to the counter variable . Other loop steps are created by changing the loop counter variable within the loop.
When the operator LEAVE is called within the loop, it is quitted immediately. If several loops are nested, LEAVE always causes the innermost loop to be terminated.
Example:
VAR LUPO
: TEST
   1 100 FOR LUPO
      LUPO RD DUP . 28 = IF LEAVE ENDIF
   NEXT
RET

REPEAT ... UNTIL (uncounted loop with open end):

Example:
VAR COUNT
: FOREVER
   REPEAT
      COUNT RD DUP DUP INK COUNT WR .
   100 = UNTIL
RET

This type of loop is very useful when the stop criterion shall be evaluated within the loop.
The sequences of token codes, which are constructed by structuring techniques do differ considerably from the source code. This can easily be checked with the command SEE <name>. Structuring operators are not directly compiled. Instead when called at compile time they immediately execute short sequences of commands, which perform the compilation of the corresponding runtime code. The latter contains some runtime primitives GO, IFNOTGO, DOFOR, DONEXT. REPEAT and ENDIF don't leave any visible trace in the compiled code.

8. Debug Features of 'Avise':

  • OPS shows a list of all kernel operators and user functions, variables and constants, which are available in the system at present time together with their respective token codes (as hex number).
    Kernel operators are shown without a numeric code. The token code of a user programmed function is the real address of its runtime code.
    The token code of a variable is the SRAM address of its data memory, which is much smaller than the token value of any user function.
    The token code of any constant is its value preceeded with a '#'. So the type of any entry can be recognized easily.
    If the list is too long, it can be stopped at any time by typing the TAB key. Hit any key to continue the output.

  • .S lists all actual enteries of the data stack without changing them (TOS is displayed last on the right side). Furthermore, .S displays the values of the 10 first declared variables (first declared variable on the left).
    When program excution halts at a breakpoint, .S is called automatically and displays the name and code of the token to be executed next, too.
    Furthermore, .S can be called directly at any time and can be mounted into functions (does not interrupt the program flow).

  • SEE lists the token content of a user programmed function and this way it does disclose its intenal construction.
    The list is displayed token by token. First the physical (absolute) address is shown where the token code is stored in the Flash memory. Then, separated by a colon, the name of this token is displayed. Some of the tokens are followed by a supplementary parameter. Together with DOLIT this is the numeric value to be put on the data stack at runtime. (Together with a call of a variable DOLIT pushes the address.) GO, IFNOTGO, DOFOR and DONEXT are followed by the (absolute) target address of the jump to be performed at runtime. Because ahead of each token its address is displayed, it is easy to follow the path where jumps are going to. DOSTR is followed by the text to be sent at runtime.

  • SEETEMP is a variant of SEE, which can be called immediately after a compilation was failed. It displays the temporary code fragment compiled into SRAM until the moment of breakdown.
    SEE and SEETEMP may only be called directly.

  • DEBUG(1) starts debug mode, DEBUG(0) switches debug mode off. This can be performed directly via terminal before calling a function or can be performed at runtime by mounting the DEBUG operator into a function when the debugger shall only be active under certain conditions. The DEBUG operator enables or disables execution of 'breakpoints' (see below). When debug mode is switched off, BREAK operators are still executed (like dummy operators) but consume very few CPU avtivity.

  • BREAK can be mounted into user functions sets a 'breakpoint' there. When debug mode is on, program execution is halted when a breakpoint is met and .S is called automatically. When the TAB key of the terminal is hit, normal program execution continues until the next BREAK is reached. Differing from previous versions, 'Avise 4.2' does not support single step mode.

9. Warmstart, Coldstart, Erase Functions:

  • ABORT forces a WARM start of 'Avise': All control parameters are reset to their default values, all stack entries are deleted. Any pendig compilation is stopped and control is forwarded to the console interface. But present values of variables and I/O configurations stay untouched.

  • INIT forces a COLD start i.e. a CPU reset initiated by firmware. All variables will be set to zero, I/O configuration is reset to default. Based on this, if activated, the AUTOEXE function will be executed first.

  • FORGET <name> erases the named function, variable or constant and funktions, variables and constants which were definet at later time.
    FORGET may only be called directly.

10. Use of the 'Atool' Terminal Program:

Source Loader

To make compilation of longer programs more comfortable, 'Atool' provides a 'source loader'.
First you have to write your source code on an ASCII text editor. Then you are able to upload it automatically line by line to 'Avise'. It has to be remarked that there is no structural difference between manual and automatic upload of source code. No hidden control characters, no special handshake. As the only visual difference, the source loader does suppress (optionally) the display of source which comes echoed from 'Avise'. 'Avise' needs a certain time to compile a command line. Consequently 'Atool' does interpret the 'carriage return' (which is echoed when processing of a command line is ready) as a sign to proceed with the next line. As any error message contains a 'tilde' character (~, hex FE) however, this terminates further upload.

Automatic loadup is not restricted to compilation of programs. It can be used for direct command entry, too, like this is possible manually. Which part of a source code is executed directly and which part is compiled depends only on the structure of the source code. In a real project normally both modes will be mixed together.

'Atool' suppresses upload of empty lines of source, comments and multiple space characters.
The behaviour of the source loader can be influence with some directives, which are formally integrated into comments:

  • { ### suppresses upload of subsequent source code to 'Avise'

  • { >>> finishes suppression of upload. From the next line of source code upload is restarted.

  • { ### and { >>> can be used multiply in sequence. Always the last directive is valid.

  • { kkk makes the source loader halt until any key is pressed. This is intended as a tool to synchronize preformulated blocks of direct command entry with live performances.
Another way to save and reload user programs is to read the complete FLASH (kernel and user code) and EEPROM (symbol table and some system pointers) of the CPU with a in-system programmer and reprogram it with the same tool.

Hotkeys used by 'Avise 4.2'

In general, 'Avise' accepts only 'printable characters'. These are: ASCII codes between hex20 and hex7D, furthermore 'carriage return' =hexD as <RETURN>-command and 'backspace' = 8, but no control characters and country specific special characters like german 'Umlaute'.
Nevertheless, the following ASCII codes have a special meaning for 'Avise' - they are already filtered out in the interrupt handler of the serial interface:

  • TAB (ASCII code 9) is used to continue program flow in debug mode. Furthermore, with TAB the normal program flow can be halted temporarily, e.g. to study quickly scrolling screen output. Any subsequent key hit will unlock the halt.

  • The tilde '~' (ASCII code hex7E) calls ABORT directly out of the serial receive interrupt handler. This feature is very useful to cancel a never-ending AUTOEXE function and return control to the user console. Performing a reset only would restart the AUTOEXE.
    Vice versa, 'Avise' does mark every error message with a tilde ~ to make error detection easier when upload is controlled by machine. Attention: as a consequence, the tilde is not allowed in names of functions, variables and constants.

  • ASCII code hex7F is ignored by 'Avise'.


* All information within this text is believed to be correct, but published without any warranty and under exclusion of any responsibility
* Trademarks and product names cited in this text and corresponding ones are property of their respective owners.