• No results found

simple example the two are not radically different. This is because the specification does not include any calculations or expression manipulation. It is essentially constructed from input, output and selection statements, which tend to compile on a one-to-one basis at this level. The main

aspect to note is the removal of the more sophisticated features such as parameters and local variables from the BSL representation. This is because in general existing assembly languages for microprocessors do not include these features. All variables in a program are global, and thus no parameter passing is needed.

The BSL compiler operates in three passes. During the first pass, the channels and variables used in the specification are written to the macro-assembler code file. The second pass produces the main control logic, which states exactly how each input channel is to be handled. Finally, the third pass produces the code for each of the service routines in the system. This structure for the output file can be

clearly seen in Figure 4.3. This format has been adopted because it adheres closely to the code format required by most existing microprocessor assembly languages. It

therefore makes the subsequent translation of the

macro-assembler code into actual machine code a much more straightforward process. There follows a brief description of the tasks performed by each pass of the compiler. The description focuses upon the aspects of the compilation process which are particular to this specific system. A more comprehensive report, which also states the current implementation restrictions, can be found in [4.3].

4.3.2 Pass One

The most important task performed by the first pass of the BSL compiler is to construct the symbol tables required to perform complete syntax checking of the specification. Much of the syntax is assumed to be correct, as most violations of the syntax rules will have been discovered when the specification is transformed into an executable form. All

CHAN temperature.measure CHAN heater CHAN low.level CHAN high.level CHAN valve BYTE temp BYTE low BYTE high INTON WHILE TRUE WAIT

INPUT temperature.measure, temp CALL temperature.control

INPUT low.level, low CALL open.valve

INPUT high-level, high CALL close.valve ENDWHILE END temperature.control: INTON IF temp, >, 90 OUTPUT heater, 0 temp, >, 80 OUTPUT heater, 1 temp, <=, 80 OUTPUT heater, 2 END IF RETURN open.valve: INTOFF OUTPUT valve, 1 INTON RETURN close.valve: INTOFF OUTPUT valve, 0 INTON RETURN

Figure 4.3 Macro-Assembler Code for the Water Tank Controller

the variables, channels and service routine identifiers are located during this pass, and stored for later reference in the appropriate symbol table. Further, all the constants declared in the specification are placed in a symbol table, together with the value that they represent. This enables the actual values of constants to be generated in the

macro-assembler code. For this reason, the macro-assembler language does not include a method for defining symbolic constants. Finally, the output produced from the first pass is simply the macro-assembler definitions for each of the channels and variables used in the specification.

4.3.3 Pass Two

The second pass of the compiler is concerned with analysing and producing code for the control section of the

specification. This acts as the main control logic for the macro-assembler code. Each input statement in the BSL is replaced by a macro-assembler INPUT statement, and each BSL output statement is replaced by a CALL statement. If the specification is interrupt-driven, a macro-assembler WAIT statement is generated. For polled channels, a POLL

statement is issued. An END instruction is placed at the end of the control block to signify the extent of its scope.

4.3.4 Pass Three

The third pass is responsible for compiling the service routines which appear in a specification. This is the most complex phase of the compilation process. It involves

analysing the expressions which make up a service routine, and generating the equivalent macro-assembler code. When a service routine header is found, it is replaced by a label, identical to its name in the specification. If a routine is interruptable, a INTON instruction is generated before the rest of the routine is analysed: for routines which may not be interrupted, an INTOFF instruction is generated. All RESULT statements found in a routine are replaced by an

output statement. The end of a routine is marked by a RETURN instruction. However, for uninterruptable routines, an INTON instruction is generated before the RETURN.

4.4 The Implementation of Macro Instructions 4.4.1 Data Types

The three variable types, BYTE, INT and REAL, defined in the macro-assembly language are implemented simply as one, two and four bytes respectively. All arithmetic operations are assumed to use values in signed twos-complement format. Thus the BYTE data type can be implemented directly by most

8-bit microprocessors, such as the 6800 [4.4] and the 6502[4.5]. These processors are specifically designed to perform twos-complement arithmetic, using the left-hand, most significant bit to represent the sign of the variable,

(see Figure 4.4). Flags in the condition code register of the 6800 and 6502 are automatically set when the result of an operation is negative, or overflow occurs. However, microprocessors such as the Intel 8080[4.6] have no way of indicating the sign of the result of an arithmetic or logic operation. Therefore an 8 080 implementation of the

macro-assembly language requires additional software and execution time, in order to fremember* the sign of each variable in use[4.7], The BYTE data type can represent values in the range +((2E7)-1) to — (2E8).

The INT data type is implemented as a double-precision

16-bit value. Two consecutive 8-bit locations are allocated to store integers; the address of the variable always gives the most significant, or high order byte. The low order byte is stored at the next memory location, given by adding one to the address of the high order byte (see Figure 4.5). The manipulation of INTs is consequently less efficient than that of BYTEs, as it essentially requires operations to be performed on each of the two bytes which constitute the value. For example, the addition of two INTs firstly requires the addition of the two low order bytes, followed