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

Forth Programmer’s Handbook

5.9 LITERALS

Some processors allow you to define instructions to reference literals. For these, the standard Forth word for identifying a literal is #. Thus the instruction:

1000 # 0 MOV

would move the literal 1000 into Register 0. A few processors allow a short instruction format for small literals and a long format for larger ones. In such cases, the Forth assembler automatically examines the literal and generates the appropriate format.

On processors that do not support direct reference to literals, one technique for supplying them is to compile a literal into the dictionary, then pass the literal’s address to an instruction that references it by HERE. For example:

HERE 1000 ,

CODE FIX

0 MOV

In this example the literal 1000 is placed in memory and its address is left on the stack by HERE. The MOV instruction assembles a reference to that address. When executed, the effect will be to move 1000 into Register 0.

5.10 DEVICE HANDLERS

Device handlers should be kept extremely short, including only the instructions required to pass a value to or from the stack, or to issue a command. Consider, for example, a self-scan character display interfaced to an RCA 1802 as Device 2. This is all that is needed to output one character from the top of the stack:

CODE

(EMIT) ( c)

S INC

S SEX

2

OUT

NEXT

 

 

In this example, S INC increments the stack pointer (to get the low-order byte), S SEX sets S as the output register, and 2 OUT sends the character to the device, incrementing S again to complete a POP.

Given this hypothetical definition of (EMIT), you could define (TYPE) in high-level Forth to display a string of characters whose byte address and

The Assembler 179

Forth Programmer’s Handbook

length are on the stack:

: (TYPE) ( a n) 0 DO PAUSE DUP C@ (EMIT) 1+ LOOP DROP ;

To convert and display a number on the stack, you could define SHOW:

: SHOW ( n) (.) (TYPE) ;

Here (.) performs the conversion, leaving the address and length of the resulting string for (TYPE). The point here is that, given the simple code definition (EMIT), full control of the display is available in high-level Forth.

Device drivers are highly variable in nature, depending upon both the processor and the actual device. You’ll find a discussion of drivers for your processor in your product documentation and useful examples in the system listings.

5.11 INTERRUPTS

A multitasked Forth (plus a few standard conventions) makes dealing with interrupts* relatively simple. The principle strategy is to perform only the most time-critical actions at interrupt time, to notify the task responsible for the interrupting device that the interrupt has occurred, and to defer all complex logic to high-level routines executed by that task. The notification may take the form of setting a flag, incrementing or decrementing a counter, or modifying the task’s status such that it will become active at the next opportunity in the multiprogrammer cycle.

The basic form of an interrupt handler is as follows:

ASSEMBLER BEGIN <code instructions> <dev#> INTERRUPT

where ASSEMBLER selects the assembler vocabulary (CODE would do this for you, but should not be used because it builds an unneeded header); BEGIN pushes onto the stack the address of the beginning of the code (which will be used by the word INTERRUPT); the code instructions perform the necessary work of the routine; dev# is the device code or interrupt vector to which the

*Most Motorola processors, as well as others, use the term “exceptions.” On such processors, the word

INTERRUPT would be replaced by EXCEPTION.

180 The Assembler

Forth Programmer’s Handbook

routine will respond, and INTERRUPT is a special code ending macro that assembles the appropriate return-from-interrupt instruction and puts the address of the code supplied by BEGIN into the interrupt vector.

The actual implementation of INTERRUPT is highly processor dependent. On machines with hardware-vectored interrupts, the implementation merely stores the address of the code in the specified vector address. On such machines, interrupts incur no additional overhead: only the instructions in the interrupt routine itself are executed. On machines in which software must identify the interrupting device, the identification method is system specific— consult your product documentation. However, one popular method is to put the polling routines in a chain, with the CPU’s interrupt vector pointing to the first polling routine. If the device served by the first routine did not generate the interrupt, the first routine executes a jump to the second routine.

On every system, conventions are established for the use of registers at interrupt time. On most systems, you may not use any registers without saving and restoring them. Save and restore only the registers you are actually going to use! The usual place to save registers is on the return stack; on systems with only one hardware stack, the parameter stack becomes the place of choice. On systems with software vectors and few registers, one or two registers are routinely saved and restored so that you may use them freely. Consult your product documentation for details.

5.12 EXAMPLE

As an example of the action of the assembler, consider the definition of the high-level comparison operator 0=. This word expects a value on the stack. If the value is non-zero, it will be replaced by a zero (false); if it is zero, it will be replaced by a negative one (true). The code for this routine in SwiftX for the Motorola 68HC12 is:

CODE 0= ( n -- flag )

0 # LDX

0 ,Y LDD

0= IF DEX THEN 0 ,Y STX

RTS END-CODE

The example below shows the processor during compilation and execution of

The Assembler 181

Forth Programmer’s Handbook

this routine (see your product documentation for details of the disassembler).

SEE 0=

81CE

0

# LDX

81D1

0

,Y LDD

81D3

81D6 BNE

81D5

DEX

81D6

0

,Y STX

81D8

RTX

182 The Assembler

6.PROGRAMMING STYLE AND EDITING STANDARDS

In this section, we will explore some of the issues that make Forth code easier to read and to maintain, notably source formatting standards and naming conventions. In addition, we are reprinting a set of “rules for readable Forth,” published by Leo Wong on the Internet newsgroup comp.lang.forth.

Successful Forth programming groups generally acknowledge the importance of agreeing within the group on a single set of coding standards. This contributes significantly to long-term code maintainability, and facilitates code-shar- ing within the group, because all group members become comfortable reading the group’s code.

Two sets of source guidelines are provided, one for BLOCK-based source (described in Section 3.4) and one for file-based source (described in Section 3.5). The file-based source guidelines are recommended by FirmWorks for use with Open Firmware. Open Firmware (IEEE Std. 1275-1994) is a Forth-based system for use in boot firmware used on SPARC systems, PowerPC PCI bus systems, and others. You will notice that, in Section 6.2, Forth words are spelled in lower case. This is conventional in Open Firmware and some Forth systems, although traditionally (and elsewhere in this book) upper case has been used for standard Forth words. This issue should be addressed in your group’s coding standards.

Style and readability are highly subjective matters. We encourage you to modify the guidelines in this section to suit your own taste and the consensus of your group. The important thing is to have some set of standards, and follow it consistently!

Programming Style 183

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