Go to Triangle Digital Support Home Page TDS9092 TECHNICAL MANUAL
6301 structured Forth assembler
Live website search
Enter key words



The symbolic assembler is built in to the TDS9092. It is used to construct Forth words which execute at machine code speed. These Forth words can be used just as others in building up high level code; The difference is that the words which might otherwise slow execution are now fast, so the entire application can approach machine code speeds.

As a rule of thumb write 90% in Forth and 10% in assembler. Code in assembler those parts where the program spends most of its time.

Both foreground programs and interrupt code can be written in assembler. See INTERRUPTS USING ASSEMBLY LANGUAGE for more information on the latter.


The usual form of an assembler definition is


CODE TEST . (assembler words) . END-CODE


The definition TEST is added to the dictionary and executes in machine code. Note that unlike colon definitions, the processor is in the execute, not the compile, mode between CODE and END-CODE . This means that the full power of the Forth system is available. For example an operand can be calculated by a definition with a complex structure such as a loop, you are not limited to simple additions etc. in the operand field as you would be in most assemblers.

As in most Forth assemblers, Reverse Polish notation is used to construct operands. On this computer you must therefore keep a close eye on this section while reading the 6301 MICROPROCESSOR DATA. Syntax is explained by means of the following examples:


13 A LDA,       ( load accumulator A from address   

                ( 13, direct addressing mode will be

                ( selected by the assembler


8000 B LDA,     ( load accumulator B from address

                ( 8000, extended addressing mode

                ( will be selected by the assembler


13 ## B ADD,    ( add immediate - constant - data 13

                ( to accumulator B


8000 ## SUBD,   ( subtract immediate data 8000 from

                ( accumulator D - which is A and B

                ( together, most significant byte A


A ROL,          ( rotate accumulator A left. An

                ( example of an instruction needing

                ( only the accumulator

E2 ROL,         ( rotate left the byte at memory

                ( location E2


0A ROL,         ( rotate left the byte at memory

                ( location 0A. The zero in front of

                ( the A ensures that 0A is taken as

                ( a number, not the defined word A


0 ,X ROL,       ( rotate left the byte at the memory

                ( location pointed to by the X

                ( register, i.e. no offset. The zero

                ( is essential


5 ,X NEG,       ( negate the byte at the memory

                ( location five after that pointed

                ( to by the X register. Offset range

                ( is 0-255 decimal


$17 $80 ## TIM, ( test address location 17 - which

                ( is parallel port 6 - against

                ( immediate data hex 80. The

                ( processor z flag is set if this

                ( bit is zero. This is a direct test

                ( of an input bit


$0180 CONSTANT ATOD   ( define address of an analog

                      ( to digital converter, then


CODE INPUT (  - n )   ( use the name later as an

   ATOD B LDA,  A CLR, ( operand. An operand does not

   PSHB,  PSHA,        ( have to be a number. In this

END-CODE              ( complete example the analog

                      ( value goes to the stack


Available op-codes are derived from those shown in table 18 of the 6301 MICROPROCESSOR DATA. For instance ADDA (add memory to the A register) becomes A ADD, . All of the microprocessor's instructions have Forth op-codes, the WORD LIST has more detailed commentary on each one.


These are the same as equates in many assemblers, you can associate a name with a particular number, whether it is an address, literal or other value. E.g.


$17 CONSTANT PORT6 ( define address of port 6,

CODE INPUT (  - n  input byte on port 6

           (       and put to stack

   A CLR,       ( ensure top byte is 0

   PORT6 B LDA, ( get byte from port 6

   PSHD         ( push to stack



Assembler code can be written in a structured manner which is very similar to the usual Forth style. These are available:







Note that the assembler forms have a comma as part of the word. Although this looks like high level language the resulting code is pure machine code just as you would have written it long-hand, no compromises or extra code! The structures can be nested and we recommend indenting each level of structure in the source code of a word defined in assembler. The words IF, WHILE, UNTIL, differ from usual Forth in that they do not expect a true/false flag on the stack, they want a true/false result from a test immediately preceding:



Loop till Z flag true. This


assembles a BNE op-code


EQ IF, .

If the Z flag is set it does everything


between IF, and ELSE, .


IF, assembles a BNE op-code and


assembles a BRA


Only half of the usual tests are defined, the others are obtained by use of  NOT, . This does not result in generation of any extra code:



If the Z flag is not set, executes the code


between IF, and THEN, .


Every UNTIL, WHILE, or IF, must be preceded by a word, perhaps qualified by NOT, related to the condition of the status register. All of these are permitted:



Continue if carry set


Continue if equal to zero


Continue if less than or same


Continue if less than or equal to zero


Continue if less than zero


Continue if minus


Continue if overflow bit set



Continue if carry not set


Continue if not equal to zero


Continue if higher


Continue if greater than zero


Continue if greater than or equal to zero


Continue if plus


Continue if overflow bit clear


Each relates to the result of the previous assembler code operation which affected the status register. To make the operation of the assembler clearer, note that EQ IF, assembles a 'branch if not equal to zero' instruction, meaning no branch will be taken if the result is zero. It will continue into the IF, part of the structure. Otherwise operation will continue from the next ELSE, or THEN, .

Use of these structured constructs does not slow operation in any way at all, the execution speed is the same as for conventional assemblers.


If a piece of assembler code will be used several times it can be put in as a conventional subroutine. Use the structure




Since there is no return to Forth, the jump compiled by END-CODE would be wasted so a simple SMUDGE to make the name findable is included. E.g.


CODE 4X  ( subroutine to multiply D register by 4


CODE 12X (  n - 12n  Forth word to multiply top of

         (           stack by 12

   PULD,  3 ## LDX,  ( set up to loop 3 times

   BEGIN,  ' 4X BSR, ( branch to subroutine




This is a contrived example, usually the situation is more complex. Note how ' 4X  is used to find the required address.

A subroutine cannot be called directly as a Forth word, you can only branch to it from within a Forth word coded in assembler. Use  BSR,  if the branch is less than 128 bytes or JSR, if larger. In fact the latter can be used all the time because it makes its own decision whether to put in a JSR or BSR instruction.


Macros come naturally to a Forth assembler without much extra code being necessary. For example a macro which pulls both the A and B registers from the stack as one mnemonic is built into the TDS9092:




Another example consists of long branches. These should be used when the scope of an IF, . ELSE, . THEN, construct is too large for the usual branches:



: NOT, ( condition - notcondition)   1 XOR, ;

: LIF, ( condition - a

   NOT, C, 3 C, 7E C, HERE 0 , ;

: LTHEN, ( a -

   HERE SWAP ! ; ( jump to address, not offset

: LELSE, ( a1 - a2)  20 LIF, SWAP LTHEN, ;


All of these definitions are standard features of the TDS9092.


The word END-CODE re-enters Forth at NEXT (a Forth constant) but some additional speed is sometimes achieved by using the alternative re-entry point PUSHBA which is defined in the assembler source. The example above could be re-written:


CODE INPUT ( - n )     ( the SMUDGE - normally done

   ATOD B LDA,  A CLR, ( by   END-CODE - is used to

PUSHBA JMP, SMUDGE     ( re-toggle the bit in the

                       ( header set by  CODE


In the TDS9092 you can temporarily drop into assembler from inside a Forth word. F>A converts from Forth to assembler and A>F is to go back to Forth. For example this word TEST will display:  3 Hello again 2


: TEST ( Puts 3 on the stack, executes some Forth,

       ( decrements the 3 in assembler and then

       ( does more Forth

   3 .S ." Hello "


   A>F ." again" .S ;


When using them you must always start off with a colon definition. You can not use these in the reverse order to go to Forth from inside an assembler word. If you want to do this, start off a Forth word with F>A so that although this is a colon definition, most of it may be in assembler with a bit of high level Forth in the middle. The format is:


: JOB F>A .assembler. A>F .Forth. F>A .assembler. A>F ;


The pair can be used as often as you wish within a single Forth word. This technique is particularly useful for speeding up previously debugged Forth words without having to separate out the assembler part. However the code resulting can look messy unless it is very well documented with comments.


The addresses of the Forth registers  W   IP  RP  USP  and a 7-byte scratchpad area N used by Forth are returned by these Forth words. The glossary of additional words has full details. The information is useful for breaking the usual rules for good software.

The 7-byte scratchpad can be used within assembler definitions for temporary storage. For example:


CODE A2+B2 ( p q = p2 + q2 where p and q are bytes

   PULD, ( q to B register)   TBA, ( copy B to A

   MUL,  N STD,  ( multiply and temporarily keep

                 ( result in N

   PULD, ( p to B register)   TBA, ( copy B to A

   MUL,  N ADDD, ( multiply and add the two squares

   PSHD,          ( result to stack



However if the assembler routine is an interrupt, remember on entering it to stack the parts you will need of this scratchpad area.

Go to Triangle Digital Support Home Page Go to top   Next page