The PIC18F assembler in the IRTC will allow you to do most that a conventional assembler will, and something's that it may not. It is a single pass interpreted assembler with conditional statements, such as
IF...ELSE...THEN
BEGIN...UNTIL
BEGIN...WHILE...REPEAT
BEGIN...AGAIN etc.
The syntax of the assembler is not that of Forth, Reverse Polish or Postfix notation but standard Prefix. This means that the source looks like standard assembly but with space delimiters. e.g.
MOVFF $000 ,POSTDEC0 becomes
MOVFF FTOSL , DP-
As all assemblers this checks the validity of the addressing mode for the instruction, and the size of the data. This is accomplished by flags that are set to indicate the various addressing modes.
Note: The only forward referencing available in the assembler is with the structures above.
The conditionals require a flag test, CS, 0=, 0<, OVF before their use. They may be followed by a NOT to produce the inverse of the test. e.g.
0= IF - branch if non zero.
0= NOT IF - branch if zero.
The PIC18F register use is described in the TLM-Forth section. Here is a résumé of that usage:
FSR0 - Data Stack Pointer
$000, $001 (FTOSL, FTOSH) - Top of the Data Stack
$004, $005 (RPL, RPH) - Forth Return Stack Pointer
STKPTR - PIC Return Stack Pointer
FSR1 - UP, Task Area
$00D, $010 - N, ScratchFile
Because of the way Forth and the Assembler work it is possible to define Macros for use in the assembly process. If we make a Host definition which contains assembler words, when interpreted at compile time, the definition will execute these words. This will place the assembler code directly into the Target. An example of this technique is:
XASM DEFINITIONS
MACRO: PUSHT
MOVFF FTOSH DP-
MOVFF FTOSL DP-
MACRO;
IN-META
Using this technique it is possible to construct repetitive code for insertion in your machine code programs
Note: You may also produce the same result with an H: definition and M[ .. ]M e.g.
H: PUSHT M[ MOVFF FTOSH DP- MOVFF FTOSL DP- ]M ;
Two other macros are pre-compiled to assist with stack control.
PUSHT places the TOS contents onto the data stack with the following code;
MOVFF FTOSH DP-
MOVFF FTOSL DP-
POPT gets the data stack into TOS whith the following;
MOVFF +DP FTOSL
MOVFF +DP FTOSH
If you wish to manipulate the stack you should do so with these macros. If you write in-line code and use these macros the optimiser will try to elliminate unnecessary stack use.
The PIC18F has many and varied addressing modes. By no means all are used in the TLM, but many are. To understand their use it is strongly recommended that you read the Microchip data book for a full explanation. Here we will consider the addressing mnemonic used in the IRTC assembler.
The same syntax that appears in the TI data book has been used for register identification. A upper case 'R' for a register, 0-15. For convenience and improved readability the registers, are pre-defined, R4, PC and SR etc.
The pre-defined versions are much more readable. Also all the I/O registers and the flags within them are predefined by name e.g.
BSF STATUS CY ,A
Will set the carry flag.
Note: When using the I/O Registers in a high level definition they must be preceeded by I/O. e.g.
$51 I/O PORTA C!
Note: When using the Register flags in a high level definition they must be preceeded by FLAG to generate a mask e.g.
FLAG CAP I/0 CCTL0 ON
The operand value used by the instruction is the value supplied by the operand field itself.
Examples:
ADDLW 04
Adds 4 to the value originally contained in WREG.
MOVFF TOSL DP-
Pushes the Forth Top Stack lower to the data stack.
In this mode a register is be addressed by using its absolute address in the register file.
Example:
RLCF FTOSH ,A
Rotates the contents of $001 left one bit.
In this mode the address of the data does not appear in the instruction, but is located in the 12 bit indirect registers, FSR0,1 or 2.
Example:
MOVFF (DP) TOSL ,A
This moves the data pointed to by FSR0 to the TOSL.
The indirect working register acts as a base or starting value to which is added an offset held in WREG, to point to the data. Example:
MOVLW 2
MOVFF TOSH UP+W ,A
Moves the value in TOSH to the LSB of DP0 in the user area.
Here the destination or source addresses are given by the contents of a register, which are then post-incremented.
Example:
MOVWF DP+ ,A
This mode addresses the specific location within the data memory directly. It only needs the absolute address value.
Example:
MOVFF TOSL , COUNTER ,A
The data memory location COUNTER is loaded with the contents of the register TOSL.
The program execution continues at the address contained in the instruction.
Example:
GOTO ' PAUSE
Jumps directly to PAUSE. The ' is used in Forth to find the CFA of the following word. If the word was created by a LABEL the ' is not required.
CALL ' STOP
Calls the subroutine STOP.
The offset, -1024 to 1023, is held in the instruction causing the execution to continue from the Program Counter plus the signed offset.
Example:
BRA ' TEST
Jumps to TEST relative from the location of the instruction.
To define a Forth code word the assembler must be invoked to allow the instruction words to be found. Three words will do this; CODE, LABEL .
CODE creates a Header for the word following and causes the assembled machine code to be run when the word is executed. This is just like a Forth : definition only in code.
LABEL creates a Header for the following word, that only leaves the address of the assembled machine code on the Host stack when the word is executed. This is often used as a reference for jumps or branches within a CODE definition.
All assembler definitions must end with END-CODE or C;. These words terminate the assembler and test the Host stack for irregularities. CODE definitions will usually end with RET.
As PIC18F Forth is subroutine threaded and produces machine code, it is possible to put code fragments into a high level definition. The code is encompassed with C[ and ]C, for example;
: TEST C[ MOVFF SECL , TOSL ]C ;
If you are only using assembler code you may still use TLM to test your routines.
TLM expects the CFA it receives to be that of a subroutine. If you have used CODE definitions for your routines these may be executed by name from the command line. If they are defined by LABELs then a stub is required e.g.
CODE TST GOTO ' <name> C;
This assumes <name> is a routine ending in a return opcode and that it does not corrupt the TLM file space or stack.
To test parts of your code it may be necessary to insert return opcodes into the code at strategic points and then create stubs to test that section.
Interrupts in the PIC18F are done via vectors at $0008 and $0018 of the program memory space. To enable these vectors to be changed during development the TLM has these locations programmed to jump to locations at the start of the development code RAM. These RAM locations may then be programmed with an absolute jump address to the interrupt routine. This adds about 0.5uSecs to the interrupt latency at 8MHz. The Forth word VECTOR! takes a vector address, and the interrupt code address to automatically create the jump in the RAM location.
During development an interrupt would be coded as;
CODE <name>
Save registers if necessary
....... interrupt code
Restore registers
RETFIE ,S C;
: SET-INT ['] <name> I/O PRIORITY-VECL ! ;
The SET-INT is run during the initialisation to set the RAM vector, in this case for the priority vector at $0008. The interrupt may then be tested and when operational a jump to the interrupt <name> may be placed at location $0008 e.g.
HERE $0008 ORG
CODE INT-START GOTO ' <name> C;
ORG
To assist with code definitions in particular, memory dump utilities DUMP and FDUMP
DUMP is for the code memory e.g.
$0000 50 DUMP
The Data memory may be dumped by FDUMP. This dumps the area defined as byte values rather than words.