                                PICBAS MANUAL

        PICBAS is a BASIC compiler designed for the Microchip's PIC16c84
microcontroller.  It is designed to be used with Parallax's SPASM
assembler.  PICBAS will compile a program written in BASIC into SPASM's
assembler code, which is then assembled into machine code and programmed
into the PIC.
        To use PICBAS, write a program using any word processor that
will write in ascii text, that is without all the control characters
used for indents, bold print, underlines, ect.  Consult your literature
if in doubt.  At the command line, type:

        PICBAS <file> <options>

        If you ommit the file name, you will be prompted for it.  Leave
out the file extension, it is assumed to be ".BAS" (in fact, it must be
".BAS").  The allowable options are:

        Q   -   The compiler will not print the BASIC source code in it's
                output.  Normally the source will be printed as comments
                in the output file.  Depending on the situation, it can
                be informative or annoying.  Use Q if you don't want the
                BASIC source.

       F84  -   PICBAS assumes you are using a 16C84, which has 36 bytes
                of RAM available.  If you use too much RAM, PICBAS will
                abort.  The 16F84 chip has 68 bytes of ram.  Including the
                F84 option will let you use that extra memory.  If you
                have an F83 chip, use the default, which has the same
                amount of RAM as the 16c84.

       LP -     Select the low power oscilator option.  The default is
                the XT oscilator.

       RC -     Select the RC (resistor/capacitor) oscilator.

       WDT_ON - Watch Dog Timer enabled.  The default is Watch Dog Timer
                disabled.

        Options must be seperated with a space.


        Ex:     PICBAS SERIAL F84 LP WDT_ON

        This will select a pic16f84 processor, low power oscilator,
enable the watchdog timer.

        The output of PICBAS will be labled with the extension ".SRC".
This is what SPASM expects.

                        WRITING A PROGRAM IN PICBAS

        The syntax of PICBAS is simple and uncomplicated.  Unlike GW
BASIC there are no line numbers needed.  The basic unit is a STATEMENT.
A number of statements make a program.  A statement is either a KEYWORD,
an ASSIGNMENT, or some program directive (a statement that will not
produce code, but affects the program in other ways).

                                INTERRUPTS

        A PICBAS program must include the label "INTERRUPT:" (labels end
with a colon, ":").  If you ommit the label, PICBAS will compile it, but
SPASM will flag an unknown label error and abort assembly.  You don't
have to put any code after the label if you don't plan to use any
interrupts, but INTERRUPT: does have to be there.  If you write an
interrupt handler,  it must end in the keyword RETI.

IMPORTANT NOTE:

        While PICBAS will allow you to put the code for an interrupt
anywhere in your program without an objection, don't make it the first
line of code in your program.  PICBAS sets the reset vector to jump to
the first line of code in the program.  Obviously you don't want that to
be the interrrupt handler.


                                ASSIGNMENTS

        A statement that starts with a variable is an ASSIGNMENT.  An
assignment performs some kind of math and then returns the result to a
variable.  In PICBAS, the general form of an assignment is:

        variable = term <operator> <term>
                     or
        variable = function

        Where a term is a constant or variable, an operator is mathematical
symbol (+, -, and, or, xor are recognized, NOTE: no multiplication or
division) and a function is a keyword, such as NOT.
        You do not have to predefine variables, although you can using
the SET keyword (more on that later).  Variables are automatically
declared when they are named.  Variables are assigned RAM space in
sequential order.  The first space is RAM location 12 (0x0c in hex).
By keeping track of the order that variables are used, you can identify
their location.  This can be useful when writing an assembly language
routine that needs to use these variables.
        Functions return a value that is then assigned to a variable.
Some functions do double duty as keywords, INCR for example.
        When INCR is used as a function, the variable that is the argument
of INCR is not altered.  It's value will be incremented and then placed in
the variable that is being assigned.  For example:

        x=0
        y=INCR(x)

At the end of these two statements, x will equal 0 and y will equal 1.
        If INCR is used alone as a statement, the argument is
incremented.  For example:

        x=0
        INCR(x)

At the end of these two statements, x will equal 1.



                          LABELS


        As previously mentioned, all labels must end with a colon,":",
even when being used in a branching statement (ie: GOTO MAIN:).  The
compiler does not keep track of labels, if you branch to a nonexistant
label, PICBAS won't notice.  SPASM, however, will.  It will flag an
error and abort assembly.  Also, as mentioned previously, the only
label you must include is INTERRUPT:.

                                MATH

        PICBAS accepts numbers in decimal, hexadecimal or binary form.
The default form is decimal.  For hex numbers, precede the number with a
dollar sign "$".  The hex number must have 2 digits, ie: $0F=15.  For
binary, precede the number with a percent sign "%".  The number must
have 8 digits, ie: %00001111=15.
        Mathematical operations are limited to addition, subtraction,
logical AND, logical OR, logical exclusive OR.  All of these are 8 bit
operations.
        The syntax of PICBAS will only allow one operation per line
of code.  That is, A=B+C is leagal, but A=B+C+D is not, there are too
many operations.

                        PREDEFINED NAMES


        The SPASM uses several predefined names for registers and bits.
You may not use these as variable or label names, SPASM will object!

Predefined Register Names:

        INDF
        TMR0
        PCL
        STATUS
        FSR
        PORTA or RA
        PORTB or RB
        EEDATA
        EEADR
        PCLATH
        INTCON

The following registers are on Page 1:

        OPTION
        TRISA
        TRISB
        EECON1
        EECON2

To access them you must set RP0.
For example:

        BITSET(rp0)     page 1
        TRISA=31        PORTA is all input
        BITCLEAR(rp0)   back to page 0

Predefined bits:

        RA.0, RA.1, RA.2, RA.3, RA.4 - PortA bits
        RB.0,RB.1,RB.3,RB.4,RB.5,RB.6,RB.7 - PortB bits

NOTE:   These could also be TRISA or TRISB bits, just change to page 1.

        C, DC, Z, PD, TO, RP0, RP1, IRP - Status register bits

        RBIF, INTF, TOIF, RBIE, INTE, TOIE, EEIE, GIE - INTCON bits

        PS0, PS1, PS2, PSA, TOSE, TOCS, INTEDG, RBPU - Option register
        bits.  You must switch to page 1 to access.

        RD, WR, WREN, WRERR, EEIF - EECON1 bits.  You must switch to
        page 1 to acess.

        To fully use these, refer to PIC Data sheet.


                        KEYWORDS

ASM
                After ASM, all text is printed as is into the output file.
                ASM is terminated with ENDASM.

                ASM
                        mov     w,#255  ;load W with 255
                        mov     6,w     ;put w into PORTB
                ENDASM

BIT(bit)
                Tests if bit is set.  Used in WHILE/WEND and IF/THEN
                statements.

        rem     Wait until ra.0 is low
                WHILE BIT(ra.0)
                WEND

BITCLEAR(bit)
                Clears named bit.

        rem     back to page 0
                BITCLEAR(rp0)

BITSET(bit)
                Sets named bit.

        rem     access page 1
                BITSET(rp0)

BRANCH var
 <labels)
ENDBRANCH
                An indexed branch.  The value in var determines
                which label to branch to.  0 branches to the first
                label, 1 to the second, ect.  Be careful that you don't
                branch past your labels, the results are unpredictable.

        rem     a jump tabel
                BRANCH i
                        TEST1:
                        TEST2:
                        TEST3:
                ENDBRANCH

CLRWDT
                Clear the watch dog timer

DECR(var)
               If used as a statement, decreases the named variable by
                one.  If used as a function, the value of the variable
                decreased by one is assigned, the variable named is not
                decreased.

        rem     i=i-1
                DECR(i)
        rem     x=i-1, i does not change.
                x=decr(i)

DEFINE <name> value

         Defines a constant value and assigns it a name.

        rem     define linefeed
                DEFINE  lf 10

GOSUB <label>:

        Branch to a subroutine.

                GOSUB MAIN:

GOTO <label>:

        Branch to a label.

                GOTO MAIN:


IF <condition> THEN <label>:

        If condition is true, goto the label.

        IF bit(c) then BUMP:

IF <condition> THEN
        <statements>
ENDIF

        If condition is true then execute the following statements.  If
        it is not then skip to ENDIF.

        IF x>0 THEN
                INCR(x)
                GOSUB PAUSE:
        ENDIF


IF <condition> THEN
        <statements>
ELSE
        <statements>
ENDIF

        if condition is true then execute the following statemnts else
        execute the statements after ELSE.

        IF BIT(c) THEN
                x=1
        else
                x=0
        ENDIF


INCLUDE  file.ext

        Compile the named file into the output file.

        INCLUDE serial.inc


INCR(var)

        If used as a statement then increment the named variable by one.
        If used as a function assign the value of the named variable
        plus one to another variable.

        rem     x=x+1
                INCR(x)
        rem     y=x+1, x is unchanged
                y=INCR(x)


NOT(var)

        If used as a statement then ones's complement of the variable.
        If used as a function then one's complement of the value of the
        variable is assigned to another variable.

        rem     x=not x
                NOT(x)
        rem     y=not x, x is unchanged
                y=NOT(x)

NOTBIT(bit)

        Tests if bit is cleared.  Used in conditional statements.

        rem     Wait ra.1 is high
                WHILE NOTBIT(ra.1)
                WEND

QUIET
        Stop printing the source as comments in the output file.


RAM=value
        Sets the compilers RAM pointer to value.  When PICBAS sees a
        variable it doesn't recognize, it puts the name on the symbol
        table and assigns it the next available RAM space as an address.
        RAM tells the compiler what the next RAM address is.  Use it to
        declare variables with SET or to make an array.

        rem     Declares three variables

        SET     SERDATA     12
        SET     SEEDATA     13
        SET     COUNT       14
        RAM=15

REM     Comments.  Also use ' (single quote)

        rem This is a comment
        '   So is this

RETI
        Return from interrupt.  Use only to return from an interrupt.

        INTERRUPT:
                GOSUB SERIN:
                RETI

RETURN
        Return from a subroutine.

        rem     delay about 60 us at 4 mHz
        DELAY:  i=20
                WHILE i>0
                        DECR(i)
                WEND
                RETURN

SET <name> value

        Declares a variable and sets it's RAM address.  Use to declare a
        variable without generating code, or to rename one of the system
        variables.

        rem Rename TMR0 as RTCC
        SET     RTCC    1


SHL(var)

        Shift variable left one time through carry.  If used as a
        statement, it shifts the variable, if used as a function, it
        shifts only the value of the variable.

        rem x=x*2
                SHL(x)
        rem y=x*2 x is untouched
                y=shl(x)

SHR(var)

        Shift variable right one time through carry.  If used as a
        statement, it shifts the variable, if used as a function, it
        shifts only the value of the variable.

        rem x=x/2
                SHL(x)
        rem y=x/2 x is untouched
                y=shl(x)

SLEEP
        Microprocessor is put into powerdown mode.  Depending on the
        source of it's wake up call, execution continues at the next
        statement or the system resets.  See the PIC16c84 data sheet for
        further details.


WHILE <condition>
        <statements>
WEND

        Execute statements while condition is true.

        rem     An iterated loop.  Performs TOGGLE: 50 times
        i=0
        WHILE i<50
                INCR(i)
                GOSUB TOGGLE:
        WEND


                        A SAMPLE PROGRAM

        This program doesn't do anything obvious to the PIC, but if you
run it on a simulator (SPASM's HEX file output will load into MPSIM -
Microchip's simulator) you will see it fill up the data eeprom.

rem     WRITE TO DATA EEPROM
'
'
        eeadr=0
        while eeadr<64
                data=eeadr
                gosub EEWR:
                incr(eeadr)
        wend
        sleep
EEWR:   eedata=data
        bitset(rp0)
        bitset(wren)
        eedata=data
        eecon2=85
        eecon2=170
        bitset(wr)
        while notbit(eeif)
        wend
        bitclear(rp0)
        return
INTERRUPT:



        This program sends the character "A" serially through RA.0.
There is no need for a rs232 converter (such as MAX232).  The baud rate
is determined by baud, currently it is set for 1200.

        gosub SERINIT:
MAIN:   data=65
        gosub SEROUT:
        goto MAIN:

SEROUT:
rem     *** start bit inverted ***
        bitset(ra.0)
        gosub DELAY:
        cnt=8
        while cnt>0
                shr(data)
                if bit(c) then
                        bitclear(ra.0)
                else
                        bitset(ra.0)
                endif
                gosub DELAY:
                decr(cnt)
        wend
rem     *** stop bit inverted ***
        bitclear(ra.0)
        gosub DELAY:
        return
rem     *** delays about 833 us(@4 mHz).  The WHILE/WEND takes 7 us
rem     *** to execute each time.  Should transmit at 1200 baud.
rem     *** set COM1:1200,n,8,1.
DELAY:  baud=118
rem     *** padding to make up 3 us
asm
        nop
        nop
        nop
endasm
        while baud>0
                decr(baud)
        wend
        return
SERINIT:
        bitset(rp0)
        bitset(ra.1)
        bitclear(ra.0)
        bitclear(rp0)
        return
INTERRUPT:
        reti


                                NOTES

        You probably noticed that there are some features of regular
BASIC missing in PICBAS.  Notably FOR/NEXT statements and arrays.
        The WHILE/WEND equivilent for FOR/NEXT is as follows:

                i=0
                while i<50
                        <statements>
                        incr(i)
                wend

        This is that same as:

                for i=0 to 50
                        <statements>
                next i

        The WHILE/WEND structure needs more BASIC code, but the assembly
code it produces is about the same as the FOR/NEXT structure, and much
easier for the compiler to interpret.
        As for arrays, I felt that given the meager RAM resources of the
PIC, arrays would be impractical.  However, arrays are possible using
the RAM statement and indirect addressing through the FSR and INDF
registers.  The equivilent of a DIM statement would be:

        define STR 12
        RAM=20

        The identifier STR points to the beginning of 8 reserved spaces
in RAM.  The equivilent of STR(3)=65 would be:

        FSR=STR+3
        INDF=65

        The number 65 would be placed in RAM address 15.  This is not
the most efficient code, but it works.  If you want to perform several
operations on your array, load FSR with the top of the array and
increment or decrement FSR as needed.  For instance:

        FSR=STR
        i=0
        while i<8
                serdata=INDF
                gosub   SEROUT:
                incr(FSR)
        wend

        SEROUT: persumably sends data out through a serial port, serdata
is the data to be sent.
        When using bit operators such as NOTBIT or BITSET, the compiler
will only recognize those names listed in PREDEFINED NAMES.  In later
versions of PICBAS, I'll try to fix that.
