Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Conklin E.K.Forth programmer's handbook.2000.pdf
Скачиваний:
321
Добавлен:
23.08.2013
Размер:
2.04 Mб
Скачать

Forth Programmer’s Handbook

5.5 USE OF THE STACK IN CODE

When using code, it is necessary to distinguish between how the stack is used at assembly time and at execution time. The words in a code entry are executed at assembly time to create machine instructions, which are placed in the dictionary to be executed later. Thus, for example,

HERE 2- TST

at assembly time places the current dictionary location on the stack (HERE) and decrements it by two. The resulting number is the parameter for TST, which assembles a machine instruction that is the equivalent of:

TST *-2

in conventional assembler notation. Similarly, such words as SWAP and DUP are executed at assembly time to manipulate the parameters being used by assembler words, although such stack words would be compiled into the dictionary in a : definition. For example, in the 8080:

0 HERE SWAP H LXI JMP

assembles an endless loop that loads zero into the accumulator. HERE pushes the address of the next free byte of dictionary space onto the stack. The phrase H LXI takes the zero from the top of the stack (at assembly time) and assembles a “load index immediate” that will load zero into the HL register pair. The JMP uses the address left on the stack to assemble a jump to the first byte of the load.

In high-level definitions, the run-time use of the stack is implicit: numbers you type are placed there, routines naturally leave their results there, etc. Code, however, requires that parameters be handled explicitly, using S (the parameter stack pointer) and the code-endings that push or pop the stack before executing NEXT.

5.6 ADDRESSING MODES

In general, Forth assemblers implement the processor manufacturer’s mnemonics, but many standardize notational conventions for specifying address-

174 The Assembler

Forth Programmer’s Handbook

ing modes. Obviously, not all processors have all addressing modes, nor do they interpret terms such as “relative” identically. Nonetheless, certain basic concepts do exist and it’s helpful, when you’re working with several processors, to have these concepts expressed in standard ways.

Refer to your product documentation for the specific addressing modes implemented in your system.

Typical Forth addressing notation includes the right parenthesis, which indicates relative addressing (when it is by itself) or indexing (when it is combined with an index register designation). Some examples:

Notation

Addressing mode

S )

Addressing relative to the top of the stack.

S)

Indexed by S.

1)

Indexed by Register 1.

On machines with automatic incrementing or decrementing, the parenthesis may be combined with + or -. On the Motorola 68000 family, for example:

Notation

Function

S

)+

Refers to the number on top of the stack, popping it off at the

 

 

same time—that is, incrementing the stack pointer.

S

-)

Refers to the next available stack location—a push operation.

The position of the sign indicates when the increment or decrement takes place in the computation of the effective address; the two preceding examples show post-incrementing and pre-decrementing.

Immediate addressing is indicated by # and memory-indirect by the right parenthesis; the assembler can determine from the address whether ) means register-relative or memory-relative (indirect). In addition, specific notation for each processor are described in the product documentation.

Parameters may be taken directly from memory, if this is permitted by the architecture of the processor. The assembler will check to determine whether the address of the argument permits a short format instruction. If it will not,

The Assembler 175

Forth Programmer’s Handbook

an extended format will be used. operation without being named. doesn’t matter how it got there:

Often, parameters may be supplied to an As long as an address is on the stack, it

HERE 55 , LDA

will enter the literal number 55 in the dictionary and leave its address on the stack at assembly time. (The operation puts the number that is on the stack into the dictionary at HERE and increments H, the dictionary pointer, by one cell.) The LDA instruction encounters the address on the stack and assembles an instruction to move its contents to Register A.

References , (comma), Section 4.3.2

5.7 MACROS

Macros are easily defined in Forth by using : definitions that contain assembler instructions. For example, on the RCA 1802 one frequently uses the operations DEC and STR successively on the same register. For convenience, the following macro has been defined:

: DST ( r) [ ASSEMBLER ] DUP DEC STR ;

Thus, S DST could be used to assemble the two instructions:

S DEC S STR

Note the way DUP in the definition of DST allows the single parameter S to be used by both the DEC and STR mnemonics.

Macros are mainly a notational convenience; DST assembles two instructions, as if the expressions had been written out in full.

The words used to implement the assembler structures (loops and conditionals) are defined as macros, as are the code endings.

176 The Assembler

Forth Programmer’s Handbook

5.8 PROGRAM STRUCTURES

Control of logical flow is handled by Forth’s assembler using the same structured approach as high-level Forth, although the implementation of the commands is necessarily different. The commands even have the same names as their high-level analogues (e.g., BEGIN UNTIL, IF ELSE THEN); ambiguity is prevented by use of separate word lists.

In conditional branches, the ELSE clause in an IF ELSE THEN construct may be omitted entirely. This construction is functionally analogous to the IF ELSE THEN construction provided by Forth’s compiler. For instance,

0=

IF

<code

for

0>

ELSE <code for not 0> THEN

0=

IF

<code

for

0>

THEN

Please note, however, that whereas the IF and UNTIL in high-level Forth remove an item from the stack and test it, the corresponding assembler words assemble conditional branches whose action will depend on condition codes set by the result of a previous instruction.

Because the locations or destinations of branches are left on the stack at assembly time, the structures BEGIN UNTIL and IF ELSE THEN may be nested naturally. By manipulating the stack during assembly, however, you can assemble any branching structure.

To branch forward, use IF to leave the location of the branch’s address field on the stack. At the branch’s destination, bring the location back to the top of the stack (if it is not there already) and use ELSE or THEN to complete the branch (by filling in the branch’s destination at the location that is on the top of the stack).

To branch back to an address, leave it on the stack with BEGIN. At the branch’s source, bring the address to the top of the stack and use UNTIL or a jump mnemonic to assemble a conditional or unconditional branch back. Be sure to manipulate the branch address before the condition mnemonic, because each condition code adds one item to the stack.

Suppose, for example, you wish to define a word LOOK, which takes two parameters (a delimiter on top of the stack with a starting address beneath it) and which scans successive bytes until it finds the delimiter or a zero. The number of characters scanned is returned. Here is a definition for the Motorola 6800:

The Assembler 177

Forth Programmer’s Handbook

CODE

LOOK ( a c -- n)

B PUL

A PUL TSX

0 )

LDX

BEGIN

0 )

TST

0=

NOT IF

 

0 )

A CMP

0= NOT IF

INX

B INC

 

ROT

JMP THEN THEN

A CLR

 

TSX

PUT JMP

 

 

 

 

Here the phrase 0= NOT IF (used twice) assembles two conditional forward jumps which will be executed if the character scanned is the same as one of the delimiters. If the loop is to be repeated, after B INC a JMP is needed back to the BEGIN. Because the intervening IFs have left their locations on the stack, the backwards branch must be assembled by ROT JMP. The ROT (executed at assembly time) pulls the address left by BEGIN to the top of the stack, where it is used as JMP’s destination. Finally, the THENs fill in the destination of the IFs.

Glossary

BEGIN

( — addr )

common usage

 

Push the address of the top of the dictionary onto the stack.

 

UNTIL

( addr x — )

common usage

 

Assemble a conditional jump back to the address left by BEGIN, using the sys-

 

tem-dependent condition specifier x. The jump is taken if the condition is met.

 

Common condition codes are 0= and 0<, as appropriate to various CPUs.

NOT

( x1 — x2 )

common usage

 

Invert the action taken for a condition code.

 

IF

( x — addr )

common usage

 

Assemble a conditional forward jump, using the system-dependent condition

 

specifier x, to be taken if the preceding condition is false, leaving the address of

 

this instruction on the stack.

 

ELSE

( addr1 — addr2 )

common usage

 

Resolve the destination of IF’s jump (at addr1) and assemble an unconditional

 

forward jump (whose location addr2 is left on the stack).

 

THEN

( addr — )

common usage

Resolve the destination for a jump instruction whose location is on the stack at assembly time (left by IF or ELSE).

178 The Assembler

Соседние файлы в предмете Электротехника