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

6301 STRUCTURED FORTH ASSEMBLER

WHEN TO USE ASSEMBLER

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.

SYNTAX RULES

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.

USING CONSTANTS

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

 END-CODE

STRUCTURED CONTROL IN ASSEMBLER

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

 

BEGIN, . UNTIL,

BEGIN, . WHILE, . REPEAT,

IF, . THEN,

IF, . ELSE, . THEN,

 

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:

 

BEGIN, . EQ UNTIL,

Loop till Z flag true. This

 

assembles a BNE op-code

   

EQ IF, .

If the Z flag is set it does everything

ELSE, .

between IF, and ELSE, .

THEN,

IF, assembles a BNE op-code and

ELSE,

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:

 

EQ NOT, IF, . THEN,

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:

 

CS

Continue if carry set

EQ

Continue if equal to zero

LS

Continue if less than or same

LE

Continue if less than or equal to zero

LT

Continue if less than zero

MI

Continue if minus

VS

Continue if overflow bit set

   

CS  NOT,

Continue if carry not set

EQ  NOT,

Continue if not equal to zero

LS  NOT,

Continue if higher

LE  NOT,

Continue if greater than zero

LT  NOT,

Continue if greater than or equal to zero

MI  NOT,

Continue if plus

VS  NOT,

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.

SUBROUTINES

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

 

CODE . RTS, SMUDGE

 

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

   ASLD,  ASLD,  RTS,  SMUDGE

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

   DEX,  EQ UNTIL,  PSHD,

END-CODE

 

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

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:

 

: PULD,  PULB, PULA, ;

 

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:

 

HEX

: 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.

FORTH RE-ENTRY POINTS

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

MIXED FORTH AND ASSEMBLER

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 "

   F>A PULX, DEX, PSHX,

   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.

FORTH REGISTERS

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

END-CODE

 

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