|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 108288 (0x1a700) Types: TextFile Names: »D173«
└─⟦4b76feb82⟧ Bits:30008865 Diskette med tekster der formodes at være 31-D-163…174 └─⟦this⟧ »D173«
i P_R_E_F_A_C_E_ PASCAL80 is the common systems programming language for future RC products, including the RC700 and RC850 product families. The present manual is aimed at systems programmers writing pro- grams in the PASCAL80 language intended to run on the PI-1 machine 2 which constitutes the core of RC700 and RC850 pro- ducts. The manual has been edited with the purpose of making it - together with the PASCAL80 Report 1 - sufficient as a collec- tion of general reference material for a programmer of the described category. \f ii \f iii T_A_B_L_E_ _O_F_ _C_O_N_T_E_N_T_S_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _P_A_G_E_ 1. INTRODUCTION .......................................... 1 2. A SHORT DESCRIPTION OF THE PI-1 MACHINE ............... 3 2.1 Segments ......................................... 4 2.2 The Private Monitor .............................. 5 2.2.1 Wait Functions ............................ 6 2.2.2 Scheduling ................................ 7 2.2.3 CHANNEL Statement ......................... 9 2.3 Standard Processes ............................... 9 3. PASCAL80 ON THE PI-1 MACHINE .......................... 11 3.1 Implementation Details and Language Modifications 11 3.1.1 Parameterized Types ....................... 11 3.1.2 Reals ..................................... 11 3.1.3 Radix ..................................... 12 3.1.4 Bounds of Subrange Types .................. 12 3.1.5 Message Header ............................ 12 3.1.6 LOCK and CHANNEL Statements ............... 12 3.1.7 Pool Initialization ....................... 13 3.1.8 Process Parameters ........................ 13 3.1.9 Incarnation Termination ................... 13 3.1.10 Routine Exit .............................. 13 3.1.11 Exception Handling ........................ 13 3.1.12 Prefix .................................... 14 3.1.13 Character String .......................... 14 3.1.14 Program ................................... 14 3.2 Predefined Types ................................. 14 3.3 Predefined Routines .............................. 15 3.3.1 Shallow Routines .......................... 15 3.3.2 Deep Routines ............................. 16 3.3.3 I/O and CPU Control Routines .............. 19 4. LINKING Z80 ASSEMBLY PROGRAMS INTO PASCAL80 PROGRAMS .. 21 \f iv T_A_B_L_E_ _O_F_ _C_O_N_T_E_N_T_S_ _(_c_o_n_t_i_n_u_e_d_)_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _P_A_G_E_ 5. REPRESENTATION AND LAYOUT OF VARIABLES ................ 25 5.1 Representation of Values ......................... 25 5.1.1 Enumeration Types ......................... 25 5.1.2 Shielded and Pointer Types ................ 25 5.1.3 Structured Types .......................... 26 5.1.4 Type Size ................................. 26 5.2 Memory Layout .................................... 27 5.2.1 Addressing ................................ 27 5.2.2 Stack Frame ............................... 28 5.2.3 Structured Types .......................... 30 5.2.3.1 Arrays and Records, Not Packed ... 30 5.2.3.2 Packed Arrays and Records ........ 31 5.2.3.3 Set Types ........................ 32 A_P_P_E_N_D_I_C_E_S_: A. REFERENCES ............................................ 35 B. HOW TO USE THE PASCALZ80 COMPILER ..................... 36 B.1 Call of the Compiler ............................. 36 B.2 Contexts ......................................... 38 C. PASCALZ80 ERROR MESSAGES .............................. 39 C.1 Messages from Pass 1 ............................. 39 C.2 Messages from Pass 3 ............................. 42 C.3 Messages from Pass 4 ............................. 48 C.4 Messages from Pass 5 ............................. 49 C.5 Messages from Pass 6 ............................. 50 D. HOW TO BUILD A PI-1 LIBRARY ON THE RC8000.............. 51 D.1 InsertZ80 ........................................ 51 D.2 DeleteZ80 ........................................ 53 D.3 ListZ80 .......................................... 53 \f v T_A_B_L_E_ _O_F_ _C_O_N_T_E_N_T_S_ _(_c_o_n_t_i_n_u_e_d_)_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _P_A_G_E_ E. HOW TO GENERATE A BOOTSTRAP IMAGE FOR THE PI-1 MACHINE ON THE RC8000 ......................................... 54 E.1 Error Messages ................................... 56 F. HOW TO TRANSFER BINARY FILES BETWEEN THE RC8000 AND THE TEKTRONIX 8002A DEVELOPMENT SYSTEM .................... 58 F.1 Tektronix Utility Program >CT> ................... 58 F.2 Tektronix Utility Program >CB> ................... 59 F.3 RC8000 Utility Program >tekmove> ................. 59 F.4 Examples of How to Transfer Programs ............. 60 \f vi \f F_ 1_._ _ _ _ _ _ _ _ _I_N_T_R_O_D_U_C_T_I_O_N_ 1. The PI-1 implementation of PASCAL80 1 has two main components: the PI-1 machine based on the Z80 microprocessor and a cross- compiler which runs on the RC8000 and generates code in the PI-1 machine object code format. PASCAL80 as defined in 1 presupposes a number of primitive functions, which in the language are expressed mostly in terms of predefined routines, particularly in the area of process synchro- nization, inter-communication, and scheduling. These functions are provided by the PI-1 basic software, PIBS. The PI-1 machine con- sists of a Z80 CPU with some amount of memory, PIBS, and an inter- preter for the PI-1 instruction set which is designed to support the sequential part of the PASCAL80 language. A thorough description of the PI-1 machine is given in 2. Chap- ter 2 of this manual contains a brief introduction which will be sufficient for most PASCAL80 programmers. Programmers who need to write Z80 assembly code to be integrated into a PASCAL80 program (see below) may need to refer to 2 as well as the assembly lan- guage and assembler manuals 4, 5. Chapter 3 may be seen as a continuation of 1. The PI-1 version of a number of language details which have been left in the report as "implementation dependent" is described, and so are some modifications and limitations relative to the language definition given in 1. Chapter 3 contains a complete list of all predefined routines of PI-1 PASCAL80. The repertoire is somewhat richer than that described in 1, and all routines which represent additions or modifications compared to the report are explained. In general, the execution by interpretation of compiled PASCAL80 code will be slower than the execution of optimal machine (Z80) code with similar function by a considerable factor. Commonly, however, a very small part of a program, typically one containing\f often repeated loops, accounts for most of the execution time. Indeed, in applications for which performance on the PI-1 machine can be foreseen as problematic, we expect to be able easily to identify the time-critical parts. The general strategy supported by the PI-1 PASCAL80 compiler to improve performance for such applications is to locate the cri- tical part of the program and rewrite it as a Z80 assembler pro- gram. The available mechanisms for linking such assembler coded program parts into a PASCAL80 program are described in chapter 4. Memory allocation and representation of variables of the various PASCAL80 types are discussed in chapter 5. Information about practical procedures for compilation, linking, and loading of PASCAL80 programs is given in appendices. \f F_ 2_._ _ _ _ _ _ _ _ _A_ _S_H_O_R_T_ _D_E_S_C_R_I_P_T_I_O_N_ _O_F_ _T_H_E_ _P_I_-_1_ _M_A_C_H_I_N_E_ 2. The PI-1 machine executes P_A_S_C_A_L_8_0_ _s_y_s_t_e_m_s_. A PASCAL80 system is defined as the execution of a P_A_S_C_A_L_8_0_ _p_r_o_g_r_a_m_. A PASCAL80 pro- gram consists of a number of p_r_o_c_e_s_s_e_s_. A process, as defined in 1, is a description of a data structure and some actions on the data structure. The execution of the actions of a process on the data structure is called a process i_n_c_a_r_n_a_t_i_o_n_. Each process incarnation has a private data structure. In general, several incarnations of a process may share one description of the ac- tions (reentrant code). The definition of the PASCAL80 language given in 1 implicitly presumes the availability of a number of basic system functions which for the most part are expressed in terms of predefined rou- tines. In the PI-1 machine these functions are performed by the PI-1 basic software, PIBS. The most important part of PIBS is the so-called private monitor, PRIVMON, which is explained in section 2.2 below. The Z80 microprocessor and its memory, augmented with PIBS, con- stitutes the b_a_s_i_c_ _l_e_v_e_l_ of the PI-1 machine. The machine at this level supports the PASCAL80 concepts introduced above, but it sees process incarnations as executing Z80 machine instructions. Indeed it is fully possible to write a process at this level, i.e. in Z80 assembly code, and use the functions of PIBS. The standard processes in the PI-1 machine (see section 2.3) and a number of RC850 drivers have been constructed in this way. Processes written in PASCAL80, however, will execute at the i_n_t_e_r_p_r_e_t_e_d_ _l_e_v_e_l_ of the PI-1 machine. When compiled, a PASCAL80 program will be transformed into a sequence of PI-1 instructions which are executed by the second software component of the PI-1 machine, the PI-1 interpreter. Seen from the basic level of the PI-1 machine the interpreter is merely a reentrant piece of code shared by many process incarnations. \f In the present manual the interpreter and its instruction set is not discussed in detail. Suffice it to say that the instruction set is very similar to, in fact derived from, that of the RC3502, and that it provides direct support for a number of PASCAL80 lan- guage constructs, such as e.g. FOR-, LOCK-, and CHANNEL-state- ments and set types. 2_._1_ _ _ _ _ _ _ _S_e_g_m_e_n_t_s_ 2.1 Physically the memory of the PI-1 machine is the memory of the Z80 microprocessor on which the PI-1 machine is implemented. Logi- cally this memory is divided into a number of s_e_g_m_e_n_t_s_. A segment occupies a contiguous area of memory, i.e. locations with conse- cutive addresses. A segment may be of any size up to 32 K bytes, and may begin in any location. A PI-1 PASCAL80 system has four kinds of segments (in addition to special segments containing basic system information): - program segment A program segment contains the executable code of a process, or of a separately compiled routine. The contents of a program seg- ment do not change when a system runs. Thus memory for a program segment can be allocated in ROM. Normally, however, this is not the case for compiled program segments (see 3). A compiled program segment which is not bound to absolute addresses of variables at the process block level (cf. chapter 4 and the abs option described in appendix B) is reentrant. A separately com- piled routine is always reentrant. When a process is reentrant several incarnations may be created sharing the same process segment. \f - incarnation data segment Each process incarnation has an incarnation data segment which contains its data structure consisting of the incarnation stack plus information needed by PIBS. The latter is not visible to the incarnation itself, i.e. this information cannot be referred to in the program text. The stack contains all parameters and va- riables of the incarnation, dynamically organized in a number of stack frames corresponding to the nest of routine calls generated by the execution of the process. Messages are not placed in incarnation data segments, because they can be passed from one incarnation to another. The incarnation data segment is dynamic and is always located in RAM. - message header segment and data buffer segment A message header segment is allocated for each message header in a system, and a data buffer segment for each message data part. Message header and data buffer segments are always located in RAM. Memory allocation for the program segments in a bootstrap image (see 2) is done by the cross-linker (cf. appendix E). Addi- tional program segments may be loaded by a running system. Allo- cation of memory for these program segments and for dynamic segments is performed dynamically as the segments are needed. However, the PI-1 machine contains no support for deallocation and re-use of memory within a system. The memory allocation strategy is therefore of the simplest possible kind: by in- creasing addresses. 2_._2_ _ _ _ _ _ _ _T_h_e_ _P_r_i_v_a_t_e_ _M_o_n_i_t_o_r_ 2.2 The private monitor, PRIVMON, is responsible for - scheduling incarnations and switching contexts, - handling interrupts, - message exchange between incarnations via semaphores, - the delay (time-out) function, - administering entry to and exit from CHANNEL statements, - starting incarnations. \f PRIVMON may be invoked by a call to one of ten predefined routi- nes: seven wait routines, signal, start, and interrupt. A call of the latter routine is normally caused by a hardware interrupt. In addition PRIVMON is invoked when an incarnation enters or leaves a CHANNEL statement and when the real time clock ticks. All PRIVMON code is executed with the Z80 interrupt system dis- abled; thus PRIVMON is indivisible. 2_._2_._1_ _ _ _ _ _W_a_i_t_ _F_u_n_c_t_i_o_n_s_ 2.2.1 PRIVMON provides possibilities for an incarnation to wait for three kinds of event: - an interrupt, i.e. actually a call of the PRIVMON routine interrupt with a parameter specifying a channel from which the incarnation is expecting an interrupt (see subsection 2.2.3). - the arrival of a message via a specified semaphore, cf. the predefined routines signal and wait of 1. - the expiry of a delay, specified as a number of delay time units, implemented by means of the delay clock (timer driver). The delay time unit is 20 msec. If an incarnation has been started, and if it is not waiting for any event, it is able to run on the processor and is said to be a_c_t_i_v_e_. All active incarnations are members of the active queue (see below). An incarnation may wait for any combination of the three kinds of event, but not on more than one semaphore or on more than one interrupting device simultaneously. Seven PRIVMON wait routines are available as predefined routines, corresponding to the seven different combinations of at least one of the three kinds of event: waitI, waitS, waitD, waitIS, waitID, waitSD, and waitISD, where I stands for interrupt, S for semaphore, and D for delay. \f If an interrupt, i.e. a call of the PRIVMON routine interrupt, arrives for an incarnation which is not waiting for the inter- rupt, it is stored as pending. This is analogous to the situation where a message is signalled to a semaphore before an incarnation has called a PRIVMON routine to wait for it. In general, if an incarnation calls a PRIVMON routine to wait for one or more events, at least one of which has already occurred the routine returns immediately to the calling incarnation and it continues to run. On the other hand, when an incarnation calls a PRIVMON routine to wait for a combination of one or more events, none of which has yet occurred, the incarnation is descheduled, removed from the active queue and tied up with PRIVMON data structures enabling PRIVMON to reactivate it when one of the desired events event- ually occurs. Because of the indivisibility of PRIVMON two events cannot occur simultaneously. A multiple wait routine always returns a result of type activa- tion (cf. section 3.2) specifying the kind of event causing reac- tivation. In case an incarnation calls a PRIVMON routine to wait for a combination including an interrupt and a message both of which have already arrived it will receive only the interrupt. 2_._2_._2_ _ _ _ _ _S_c_h_e_d_u_l_i_n_g_ 2.2.2 The incarnations of a PI-1 PASCAL80 system are at any point in time divided into two priority classes: Class I: incarnations executing a CHANNEL statement thus enabling these incarnations to be activated by inter- rupts. An incarnation of a process containing one or more CHANNEL statements is called a d_r_i_v_e_r_. Class II: other incarnations. These behave as coroutines. This division is not static. It changes as drivers enter and exit their CHANNEL statements. \f A running incarnation may be descheduled for two kinds of reasons: - the incarnation explicitly calls a PRIVMON routine which either deactivates it (a wait routine) or activates an incarnation with higher priority (signal, start, interrupt), or the incar- nation leaves a CHANNEL statement thereby lowering its priority so that another incarnation has higher priority. - a hardware interrupt occurs, causing a class I incarnation to be activated and made running. The scheduling of class I incarnations depends on the hardware priorities of the attached devices (daisy chain). Nested inter- rupts may occur so that one driver interrupts another. Scheduling of class II incarnations is based on priorities. PRIVMON maintains the a_c_t_i_v_e_ _q_u_e_u_e_ which is at any point in time a list (not FIFO queue) of all active incarnations, ordered according to priority. The running incarnation is always the first incarnation in the active queue. The presence of the dummy incarnation ensures that the active queue is never empty. Class I incarnations all have a priority higher than that of any class II incarnation. The active class I incarnations, if any, will therefore always be at the head of the active queue. When an incarnation is activated, except when activated by inter- rupt, it is inserted in the active queue after all incarnations with the same or higher priority and before incarnations with lower priority. When an incarnation is activated by interrupt it is inserted as the first incarnation in the active queue and immediately becomes running. Class II incarnations must not disable the interrupt system (incarnations of compiled PASCAL80 processes cannot do this). A class II incarnation will never be running if a class I incarna- tion is active. \f 2_._2_._3_ _ _ _ _ _C_H_A_N_N_E_L_ _S_t_a_t_e_m_e_n_t_ 2.2.3 Executing a CHANNEL statement enables an incarnation (driver) to interact with a device by receiving the interrupts generated on a specific channel, i.e. with a particular value of the interrupt vector (Z80 interrupt model 2). The reference variable of the CHANNEL statement 1 must refer- ence a channel message. This channel message (see reservech, sec- tion 3.3) contains the value of the channel in question. The PI-1 machine has precisely one channel message for each existing channel. When an interrupt on the channel occurs, a hardware generated call of PRIVMON>s interrupt routine causes the incarnation to be activated, assuming it is waiting for an interrupt. It is also possible for an incarnation to call interrupt, thereby generating a software interrupt to a driver. When a driver enters a CHANNEL statement its priority is adjusted so that it executes the CHANNEL statement with a high priority. When it leaves the CHANNEL statement the priority is adjusted again to the value with which the driver was started. This may cause it to be descheduled. 2_._3_ _ _ _ _ _ _ _S_t_a_n_d_a_r_d_ _P_r_o_c_e_s_s_e_s_ 2.3 PIBS includes three standard process incarnations which are part of all PI-1 PASCAL80 systems: - the initial incarnation (Adam) survives after initializing a system as a dummy incarnation with lower priority than any other incarnation. - the timer driver is activated by regular hardware timer inter- rupts and causes the d_e_l_a_y_ _c_l_o_c_k_ to tick every delay time unit (see subsection 2.2.1). \f The timer driver is a child of Adam. In addition every system must include an incarnation of an assembly coded process Eve, whose program segment is located in the bootstrap image (see 2). Eve is started by Adam as the final action during system initialization. Eve is the root of the remaining part of the system. \f F_ 3_._ _ _ _ _ _ _ _ _P_A_S_C_A_L_8_0_ _O_N_ _T_H_E_ _P_I_-_1_ _M_A_C_H_I_N_E_ 3. This chapter together with the PASCAL80 report 1 contains the precise definition of the programming language PASCAL80 as im- plemented on the PI-1 machine. 3_._1_ _ _ _ _ _ _ _I_m_p_l_e_m_e_n_t_a_t_i_o_n_ _D_e_t_a_i_l_s_ _a_n_d_ _L_a_n_g_u_a_g_e_ _M_o_d_i_f_i_c_a_t_i_o_n_s_ 3.1 The PASCAL80 report leaves open a number of small parts of the language. A description of how these parts have been implemented is given in this section. Included is also information about a number of aspects of PI-1 PASCAL80 where the implementation de- viates from what the report prescribes. No indication is given of which parts of the description are supplementary to the report and which are alternative. As a rule information which is given in connection with a predefined routine (section 3.3) is not found in this section. The page numbers given in each of the headings below refer to 1. 3_._1_._1_ _ _ _ _ _P_a_r_a_m_e_t_e_r_i_z_e_d_ _T_y_p_e_s_ (p. 9, 10, 36, 41, 42, 50, 51, 52) 3.1.1 Parameterized types are not implemented. In particular the type string(n) is not defined. 3_._1_._2_ _ _ _ _ _R_e_a_l_s_ (p. 10, 19, 63) 3.1.2 The type real is not implemented. Numeric values can only be integral, i.e. no decimals or exponents are allowed. \f 3_._1_._3_ _ _ _ _ _R_a_d_i_x_ (p. 18) 3.1.3 Binary, octal, and hexadecimal numbers are indicated by the pre- fixes #b, #o, and #h. In hexadecimal numbers the digits a..f may be used. 3_._1_._4_ _ _ _ _ _B_o_u_n_d_s_ _o_f_ _S_u_b_r_a_n_g_e_ _T_y_p_e_s_ (p. 19) 3.1.4 The bounds min bound and max bound of a subrange type definition must be given by constant expressions. 3_._1_._5_ _ _ _ _ _M_e_s_s_a_g_e_ _H_e_a_d_e_r_ (p. 21) 3.1.5 The following fields of a message header are accessible: size: !integer; (* size in bytes of message data *) kind: !message _kind; (* see section 3.2 *) u1, u2, u3, u4: byte; (* not present in channel message *) 3_._1_._6_ _ _ _ _ _L_O_C_K_ _a_n_d_ _C_H_A_N_N_E_L_ _S_t_a_t_e_m_e_n_t_s_ (pp. 26-27) 3.1.6 The report specifies certain restrictions on the use of the ref- erence variable of a LOCK or CHANNEL statement. These restric- tions are not enforced by PI-1 PASCAL80. However, the reference variable of a LOCK statement is treated as follows: - before the statement (after DO) is executed the reference vari- able is exchanged with an anonymous reference variable and thereby becomes NIL, - after the statement the reference variable is again exchanged with the anonymous variable. If the anonymous reference does not hereby become NIL an exception occurs. The substance of the implementation of the CHANNEL statement is explained in subsection 2.2.3. \f 3_._1_._7_ _ _ _ _ _P_o_o_l_ _I_n_i_t_i_a_l_i_z_a_t_i_o_n_ (p. 45) 3.1.7 The allocation of memory for messages for a pool variable is per- formed during the initialization of an incarnation a_f_t_e_r_ it has been started and scheduled to run. One effect of this is that an incarnation may in unfortunate cases be successfully created and yet unable to run due to lack of memory. 3_._1_._8_ _ _ _ _ _P_r_o_c_e_s_s_ _P_a_r_a_m_e_t_e_r_s_ (p. 51) 3.1.8 Process parameters of reference, pool, or shadow types are not allowed, neither as variables, values, or components of struc- tured parameters. Pointers may be passed only as values or frozen variables. Semaphores may be passed as variables, but not as values. Otherwise, the restrictions mentioned in 1 are not enforced. 3_._1_._9_ _ _ _ _ _I_n_c_a_r_n_a_t_i_o_n_ _T_e_r_m_i_n_a_t_i_o_n_ (p. 56) 3.1.9 When an incarnation is terminated (by completing its compound statement) it is permanently descheduled and will not become running again. However, no garbage collection is performed. 3_._1_._1_0_ _ _ _ _R_o_u_t_i_n_e_ _E_x_i_t_ (p. 57) 3.1.10 The rule stated in 1, that all local reference and shadow vari- ables must be NIL at exit from a routine block, is not enforced. 3_._1_._1_1_ _ _ _ _E_x_c_e_p_t_i_o_n_ _H_a_n_d_l_i_n_g_ 3.1.11 When an exception occurs the exception routine of the PI-1 ma- chine is called. It is described in section 3.3. The exception routine may also be called explicitly. If a routine with name exception is declared in a program, the usual scope rules will apply, but the handling of exceptions is not affected. \f 3_._1_._1_2_ _ _ _ _P_r_e_f_i_x_ (p. 60) 3.1.12 Prefixes as described in 1 have not been implemented. See the description of contexts in appendix B for a somewhat similar mechanism. A routine may be compiled separately by using the syntax -'PREFIX -'prefix name -'; -'routine declaration -' 3_._1_._1_3_ _ _ _ _C_h_a_r_a_c_t_e_r_ _S_t_r_i_n_g_ (p. 64) 3.1.13 The type of a one-dimensional array of char is called a string type. A character string is a value whose type is compatible with any string type. Thus character strings may be assigned to and compared with variables of string types, and used as actual para- meters for formal parameters of string types. Whenever appropri- ate a character string is truncated to the required number of characters or extended with spaces. The predefined type alfa which is used to specify external names of processes is an example of a string type whose values may be written as character strings. 3_._1_._1_4_ _ _ _ _P_r_o_g_r_a_m_ (p. 60) 3.1.14 Each compilation of a PASCAL80 program, i.e. a process or a pre- fix yields an object module 2. The object module name is the process or prefix name. 3_._2_ _ _ _ _ _ _ _P_r_e_d_e_f_i_n_e_d_ _T_y_p_e_s_ 3.2 The following types are predefined in PI-1 PASCAL80 in addition to those described in 1. bit = 0..1; byte = 0..255; \f activation = (a _interrupt, a _semaphore, a _delay); The type activation is used for results from multiple wait func- tions to indicate the reason why an incarnation is activated (or continues to run). message _kind = (datamsg, channelmsg); The type message _kind is used in the kind field of a message header to indicate whether a message is a data message or a channel message. alfa = ARRAY(1..12) OF char; The type alfa is used to specify external process names (see link in the next section). 3_._3_ _ _ _ _ _ _ _P_r_e_d_e_f_i_n_e_d_ _R_o_u_t_i_n_e_s_ 3.3 The predefined routines supported by PI-1 PASCAL80 are divided into three groups: - the s_h_a_l_l_o_w_ routines which are executed without involving PIBS; these routines are all functions and they may be considered as operators on their parameter types. - the d_e_e_p_ routines which involve calls to PIBS, most often to PRIVMON. - the i_/_o_ _a_n_d_ _C_P_U_ _c_o_n_t_r_o_l_ routines. 3_._3_._1_ _ _ _ _ _S_h_a_l_l_o_w_ _R_o_u_t_i_n_e_s_ 3.3.1 The following shallow routines are implemented in accordance with their definition in 1: abs, chr, empty, locked, nil, open, ord, passive, pred, ref, and succ. \f Two shallow routines have been added: FUNCTION openpool(VAR p: POOL 1): boolean; A call of openpool returns the value TRUE if the pool is not empty, FALSE otherwise. FUNCTION ownertest (VAR p: POOL 1; VAR r: reference): boolean; A call of ownertest returns the value TRUE if the message accessed by r has been allocated from p, FALSE otherwise. If r is NIL an exception occurs. 3_._3_._2_ _ _ _ _ _D_e_e_p_ _R_o_u_t_i_n_e_s_ 3.3.2 All deep routines available in PI-1 PASCAL80 are listed below. Only those which differ from the definition in 1 are described in detail. PROCEDURE alloc(VAR r: reference; VAR p: POOL 1; VAR s: semaphore); See 1. PROCEDURE break(VAR sh: shadow; excode: integer); A call of break causes an exception to occur in the child (shadow), i.e. the exception routine is called f_r_o_m_ the child. FUNCTION create(process name (actual parameters); VAR sh: shadow; size: integer): integer; See 1. When create is called the shadow variable must be NIL, and the process name must either be internal, or an external name must have been linked to it (by link, see below), otherwise an exception occurs. The size parameter specifies the size in bytes of the incarnation stack in the data segment allocated for the incarnation which is created. If a process has not been linked to the process name it is searched for among the processes which have been loaded into the memory of the PI-1 machine, and if found, it is linked to the process name. If not found, the linker is invoked to search for the process in the object program cata-\f log (cf. 2). If the process is found in the catalog it is loaded and linked to the process name, otherwise create fails. When a program is searched for, both the external name and the parameter description must match. The result of create is: 0 - if an incarnation is successfully created, 1 - if the process has not been found, 2 - if sufficient memory cannot be allocated. PROCEDURE exception (excode: integer); A call of the exception procedure, which may be caused by the occurrence of an exception, causes diagnostic information to be output on a suitable device, if one is present. A stack trace of the calling incarnation is included. Subsequently the PI-1 machine stops executing the PASCAL80 system. PROCEDURE interrupt(channel: integer); A call of interrupt generates a software interrupt to the incar- nation which is executing a CHANNEL statement with a channel message containing a channel value equal to the parameter, cf. subsection 2.2.3. If no such incarnation exists the call has no effect. PROCEDURE link(external _name: alfa; process name); See 1. Note that only the external name, not the actual process is linked to the process. PROCEDURE pop(VAR r1, r2: reference); See 1. PROCEDURE push(VAR r1, r2: reference); See 1. PROCEDURE release(VAR r: reference); If the parameter is NIL a call of release causes an exception, otherwise the effect is dependent on the kind of message referred to by r. If the message is of kind datamsg it is released to its owner pool, i.e. made available for allocation by a call of\f alloc. If the message is of kind channelmsg the channel ident- ified by the message is released, i.e. it becomes free for reser- vation by a call to reservech. In both cases r is NIL on return from release. FUNCTION remdelay : byte; This function may be called after returning from a multiple wait function which includes waiting for a delay. The result returned is the number of time units which remained of the delay when the incarnation was activated. PROCEDURE remove(VAR sh : shadow); The procedure remove is not available in PI-1 PASCAL80. PROCEDURE reservech(VAR r: reference; channel: integer); When reservech is called r must be NIL, otherwise an exception occurs. If the specified channel is free before the call, it is reserved, and on return r will refer to its channel message. If the channel is not free the call has no effect, i.e. r is NIL on return. PROCEDURE return(VAR r: reference); See 1. PROCEDURE sensesem(VAR r: reference; VAR s: semaphore); If the semaphore s is open, the call sensesem(r,s) is equivalent to waits(r,s), otherwise the call has no effect. PROCEDURE signal(VAR r: reference; VAR s: semaphore); See 1. PROCEDURE start(VAR sh: shadow; priority: 1..254); See 1. Notice that the parameter priority is not of type in- teger as in 1. The priority of the created incarnation with respect to scheduling is higher, the smaller the value of the priority parameter. PROCEDURE stop(VAR sh: shadow); The procedure stop is not available in PI-1 PASCAL80. \f PROCEDURE wait(VAR r: reference; VAR s: semaphore); Equivalent to waits; see subsection 2.2.1. PROCEDURE waitd(delay: byte); See subsection 2.2.1. PROCEDURE waiti; See subsection 2.2.1. FUNCTION waitid(delay: byte): activation; See subsection 2.2.1. FUNCTION waitis(VAR r: reference; VAR s: semaphore): activation; See subsection 2.2.1. FUNCTION waitisd(VAR r: reference; VAR s: semaphore; delay: byte); activation; See subsection 2.2.1. PROCEDURE waits(VAR r: reference; VAR s: semaphore); See subsection 2.2.1. FUNCTION waitsd(VAR r: reference; VAR s: semaphore; delay: byte): activation; See subsection 2.2.1. PROCEDURE unlink(process name); The procedure unlink is not available in PI-1 PASCAL80. 3_._3_._3_ _ _ _ _ _I_/_O_ _a_n_d_ _C_P_U_ _C_o_n_t_r_o_l_ _R_o_u_t_i_n_e_s_ 3.3.3 The routines described below are available to perform i/o and CPU control control instructions of the Z80 microprocessor on which the PI-1 machine is based. FUNCTION inbyte(inport: byte): byte; A call of inbyte yields as result a byte read from the input port specified by the parameter (one Z80 IN instruction). \f PROCEDURE inbyteblock(VAR r: reference; first, last: byte; inport: byte); This procedure is equivalent to the following: LOCK r AS buf: ARRAY(0..max) OF byte DO FOR i:=first TO last DO buf(i):=inbyte(inport); where max is sufficiently large and i is a byte. The procedure is executed by means of the Z80 INIR (block input) instruction. PROCEDURE outbyte(outport, data: byte); A call of outbyte causes the byte data to be output on the output port specified by outport (one Z80 OUT instruction). PROCEDURE outbyteblock(VAR r: reference; first, last: byte; outport: byte); This procedure is equivalent to the following: LOCK r AS buf: ARRAY(0..max) OF byte DO FOR i:=first TO last DO outbyte(outport,buf(i)); where max is sufficiently large and i is a byte. The procedure is executed by means of the Z80 OTIR (block output) instruction. PROCEDURE zenable; A call of zenable causes the Z80 EI instruction to be executed, i.e. the interrupt system of the CPU is enabled. PROCEDURE zreti; A call of zreti causes the Z80 RETI instruction to be executed, notifying a peripheral device on the daisy chain that interrupt service is completed. \f 4_._ _ _ _ _ _ _ _ _L_I_N_K_I_N_G_ _Z_8_0_ _A_S_S_E_M_B_L_Y_ _P_R_O_G_R_A_M_S_ _I_N_T_O_ _P_A_S_C_A_L_8_0_ _P_R_O_G_R_A_M_S_ 4. Inclusion of Z80 assembly code into a compiled PASCAL80 program may be necessary for one of two reasons: - the need to optimize a time-critical part of the program, or - the need to use special facilities at the basic level of the PI-1 machine which are not available at the interpreted PASCAL80 level, particularly in connection with treatment of interrupts in drivers. The procedure for inclusion of an assembly language program in a compiled PASCAL80 program is as follows: The program is written in the Z80 assembly language described in 4 and assembled on the Tektronix 8002 microprocessor develop- ment system 5. Information about how the assembly language pro- gram interfaces to PIBS and the PI-1 interpreter, and about the facilities available at the basic level of the PI-1 machine is found in 2. The object program produced by the Tektronix assembler is then transferred to a P_I_-_1_ _l_i_b_r_a_r_y_ on the RC8000 where the compiler runs. In the PI-1 library the assembler object program is stored together with a PASCAL80 procedure description, i.e. a name and a parameter description. The transfer of the assembler object pro- gram and the specification of the procedure description is done by means of utility programs which are described in appendices D and F. The PI-1 compiler will include an assembler object program from a PI-1 library specified using the lib option (see appendix B) into a compiled program if an external procedure declaration compatible with the procedure description in the library and at least one call of the declared procedure occurs in the program. \f For each call occurring in the PASCAL80 program of a procedure which has been included from the PI-1 library as described above the compiler generates code to evaluate the parameters and push them on the stack of the incarnation executing the call and sub- sequently transfer control to the entry point of the assembly language program. Information about the representation of par- ameters on an incarnation stack is found in chapter 5. When a program is written in assembly language to replace a time-critical part of a PASCAL80 program it is necessary, or at least useful, to be able to access not only the parameters specified in the external procedure declaration, but also the variables of the process incarnation in which the assembly program is executed. For this reason the compiler supports linking of values exported from a PASCAL80 program to symbols declared as unbound globals in the assembly language program. The values to be exported from a PASCAL80 program are defined in export parts occurring in the declarations of one or more blocks within the program. The syntax and semantics of an export part are described below: export part: -' EXPORT-'-'export name -' = -'export kind -' simple variable -' ; Each repetition of the loop yields one e_x_p_o_r_t_ _v_a_l_u_e_ which is associated with the export name, i.e. the same name must appear as an unbound global symbol in the assembly language program. Only the first eight characters of an export name are signifi- cant. export kind: VALUE DISP SIZE ADDRESS OFFSET \f simple variable: -' simple var name -' -' -' field name <-.<- Simple var name can be either a constant name or a variable name. If it is a constant name, or if the variable is of a packed record type, field name indexing is not allowed. It follows that simple variable is either a constant, a variable, or a field of a record variable which is not packed. The export value must always be representable in a word (16 bits) or a byte (8 bits), cf. chapter 5. The export kind determines how the export value is calculated: VALUE The simple variable must be a constant. The export value is the value of the constant. DISP The simple variable must be a field of a record. The export value is the displacement of the field relative to the start of the record. SIZE The export value is the size in bytes of the type of the simple variable. ADDRESS The simple variable must be a variable or a field of a variable record declared at the process block level of a separately compiled process. The export value is the address of the simple variable, and when the object program resulting from the compilation is loaded and linked on the PI-1 machine it is relocated as the absolute Z80 address of the simple variable. Thus the corresponding global symbol in the assembly language program may be used directly as a variable address. Notice that a program which contains exported values of kind ADDRESS will not be reentrant (see also the abs option in appendix B). \f OFFSET The simple variable must be a variable or field of a record variable. The export value is the offset of the simple variable within its local stack frame. \f F_ 5_._ _ _ _ _ _ _ _ _R_E_P_R_E_S_E_N_T_A_T_I_O_N_ _A_N_D_ _L_A_Y_O_U_T_ _O_F_ _V_A_R_I_A_B_L_E_S_ 5. In this chapter it is explained how values of the various types of PASCAL80 are represented in the PI-1 implementation and how memory is allocated and laid out to hold the values of the vari- ables of a process incarnation. 5_._1_ _ _ _ _ _ _ _R_e_p_r_e_s_e_n_t_a_t_i_o_n_ _o_f_ _V_a_l_u_e_s_ 5.1 5_._1_._1_ _ _ _ _ _E_n_u_m_e_r_a_t_i_o_n_ _T_y_p_e_s_ 5.1.1 An enumeration type is defined as consisting of a finite, totally ordered set of values, corresponding to a set of ordinal values which is a subset of the integral numbers. The representation of a value of an enumeration type is the two>s complement represen- tation of the corresponding ordinal value. If a type includes negative ordinal values the representation of values of the type is always in 16 bits (a word). If the type includes only non- negative ordinal values, and n is the largest of these then the M_m_m_ representation is in log (n+1) bits (at most 16). Examples: 2 P_p_p_ - integer values (-32768..32767) are represented in 16 bits, - boolean values (false, true) are represented in 1 bit, - char values (see 1) are represented in 7 bits, - values of the subrange type -3..7 are represented in 16 bits, - values of the scalar type (red, green, blue, orange, pink) are represented in 3 bits. 5_._1_._2_ _ _ _ _ _S_h_i_e_l_d_e_d_ _a_n_d_ _P_o_i_n_t_e_r_ _T_y_p_e_s_ 5.1.2 The representation of values of shielded and pointer types is not revealed. \f 5_._1_._3_ _ _ _ _ _S_t_r_u_c_t_u_r_e_d_ _T_y_p_e_s_ 5.1.3 Values of array or record types are vectors of values of enumer- ation, shielded, pointer, and set types. The component values are represented as described for the component types. The representation of values of a set type uses a bit vector whose length depends on the base type. The base type must be an enumeration type which does not include negative ordinal values. If the ordinal value set of the enumeration type T is the range m..n (m '_ 0) then values of the type set of T are represented in a bit vector with indices from 0 to n. The first m (possibly zero) of these bits are not significant. If the element of T whose ordinal value is i (m <_ i <_ n) is a member of a particular value of type set of T then bit i in the representation of that value is 1, otherwise it is 0. Example: TYPE a=set of 3..5; VAR b: a:=(.3,5.); The value of b is represented as shown: bit 0 1 2 3 4 5 1 0 1 The shaded bits are not significant. 5_._1_._4_ _ _ _ _ _T_y_p_e_ _S_i_z_e_ 5.1.4 The size of a type T, denoted S(T), is the number of bits used to represent values of type T. The concept of size is only relevant for types which are affected by packing when used for components of structured types, and is therefore not defined for all types. For enumeration types S(T) is computed as described above. Examples: S(char)=7, S(integer)=16. \f 5_._2_ _ _ _ _ _ _ _M_e_m_o_r_y_ _L_a_y_o_u_t_ 5.2 The memory requirement of a type T, denoted M(T), is defined as the number of bytes which are allocated for a variable of type T. For an enumeration type T, M(T) depends on S(T), as follows: 1 <_ S(T) <_ 8: M(T)=1 9 <_ S(T) <_ 16: M(T)=2 For shielded and pointer types, M(T) is the following: M(reference)= 2 M(semaphore)= 3 M(shadow) = 2 M(pointer) = 2 M(pool) = 3 Memory requirement for structured types is described in connec- tion with memory layout for these types in subsections 5.2.3 and 5.2.4. 5_._2_._1_ _ _ _ _ _A_d_r_e_s_s_i_n_g_ 5.2.1 The memory of the PI-1 machine consists of a sequence of eight bit bytes. Each byte has an address. Two consecutive bytes may be used as a sixteen bit word. In Intel fashion a word consists of high byte (most significant halfword) and low byte (least significant halfword). The low byte is always the byte with the l_o_w_e_s_t_ address. An integral number of bytes is allocated for each variable. The address of a variable is the smallest of the addresses of the bytes allocated for the variable. \f 5_._2_._2_ _ _ _ _ _S_t_a_c_k_ _F_r_a_m_e_ 5.2.2 Memory for variables declared in process or routine blocks is allocated in s_t_a_c_k_ _f_r_a_m_e_s_ in the data segment of the incarnation to which the variables belong. The general layout of an incarna- tion stack is shown in fig. 1. In the portion of a stack frame used for declared variables memory is allocated from high to low addresses in the order of declaration of the variables in the program text. The two bytes allocated for a variable of an enumeration type T with M(T)=2 are treated as a word, i.e. the most significant halfword has the highest byte address. A variable of an enumer- ation type is always right justified, i.e. placed in the least significant bits of the allocated byte or word. Example: Corresponding to the declarations: VAR a: reference; b: char; c,d: 0..7; e: integer; memory is allocated within a stack frame as illustrated in fig. 2. address MSB LSB 7 6 5 4 3 2 1 0 M_m_m_ s-6 e P_p_p_ s-5 s-4 d the shaded areas are unused s-3 c s-2 b M_m_m_ s-1 a P_p_p_ s Figure 2: Memory layout for simple declared variables in stack frame. \f F_ Figure 1: Incarnation stack layout (snapshot). \f F_ The layout of actual parameters is similar to that of declared variables, with a minor modification: since the smallest unit of memory pushed on the evaluation stack is a word, each actual parameter of a process or routine stack frame occupies an integral number of words. Similarly to the case of declared variables, an actual parameter of an enumeration type of size less than 16 (bits) is placed in the least significant bits of the allocated word. 5_._2_._3_ _ _ _ _ _S_t_r_u_c_t_u_r_e_d_ _T_y_p_e_s_ 5.2.3 The memory requirement of a structured type is determined by the memory requirements of the component type(s). However, the memory requirement of a packed record or array is always at least two (bytes). The memory allocated for a variable of a structured type is sub- allocated for the components of the variable in a fashion which depends on whether the type is declared as packed or not. For an array, memory is allocated from low to high addresses for the elements in index order, and for a record, memory is allo- cated from low to high addresses for the fields in the order they are declared in the record type definition. 5_._2_._3_._1_ _ _ _A_r_r_a_y_s_ _a_n_d_ _R_e_c_o_r_d_s_,_ _N_o_t_ _P_a_c_k_e_d_ 5.2.3.1 For an array or record type which is not packed, memory allocation for the components takes place in a fashion similar to the allo- cation of memory for declared variables in a stack frame, except that increasing address order is used, i.e: - from low to high addresses, - an integral number of bytes per component, - right justification of each enumeration type component within the allocated byte or word. \f Example: With the record type definition below. Fig. 3 shows the layout of a variable of type r. TYPE r=RECORD a: reference; b: char; c,d: 0..7; e: integer END; address 7 6 5 4 3 2 1 0 M_m_m_ s a P_p_p_ s+1 s+2 b s+3 c s+4 d M_m_m_ s+5 e P_p_p_ s+6 Figure 3: Memory layout for record type (not packed). By summation (or multiplication) the memory requirement of an array or record type may be determined from the above rules for sub-allocation of memory for components. For the record type in the example M(r)=7. 5_._2_._3_._2_ _ _ _P_a_c_k_e_d_ _A_r_r_a_y_s_ _a_n_d_ _R_e_c_o_r_d_s_ 5.2.3.2 When memory is laid out for a packed array or record type compo- nents of types with size less than 16 (bits) (for arrays: 6 bits) are packed, if possible. Packing always takes place in a word, from most to least significant bit, and each component is allo- cated as many bits as indicated by its size. By this rule unused space may be left in the least significant bits of a word in which one or more components are packed. \f Notice that in the current implementation only components of enumeration types are candidates for packing. Example: The layout of variables of the following packed record type is shown in fig. 8. TYPE q=PACKED RECORD a: reference; b: char; c,d: 0..7; e: integer END; MSB LSB 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 s a s+2 b c d s+4 e Figure 4: Memory layout for record. M(q)=6. 5_._2_._3_._3_ _ _ _S_e_t_ _T_y_p_e_s_ 5.2.3.3 The memory requirement of a set type is always an even number (of bytes), i.e. an integral number of words is allocated for each variable of a set type. The number of words used is the smallest number which will accomodate the bit vector used to represent values of the set type, cf. subsection 5.1.3. The bit vector is laid out with index 0 in the most significant bit of the first word. The last word may contain an unused portion in its least significant bit positions. Example: see fig. 5. \f address 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 s s+2 s+4 s+6 Figure 5: Layout of a variable of the type set of 0..50; 13 bits are unused. The memory requirement of the type is 8. \f F_\f F_ A_._ _ _ _ _ _ _ _ _R_E_F_E_R_E_N_C_E_S_ A. 1 RCSL No 52-AA964: PASCAL80 Report 2 RCSL No 31-D615: The PI-1 Machine, Reference Manual 3 System User>s Package for Tektronix 8002A microprocessor development system 4 Z80-Assembly Language Programming Manual, Zilog, inc. 5 Z80 Assembler and Emulator User>s Manual for Tektronix 8002A microprocessor development system \f F_ B_._ _ _ _ _ _ _ _ _H_O_W_ _T_O_ _U_S_E_ _T_H_E_ _P_A_S_C_A_L_Z_8_0_ _C_O_M_P_I_L_E_R_ B. B_._1_ _ _ _ _ _ _ _C_a_l_l_ _o_f_ _t_h_e_ _C_o_m_p_i_l_e_r_ B.1 M_m_m_ 1 <s'<options' 1 <bin file'= pascalz80 <s'<source' 0 <s'<context' 0 P_p_p_ 0 list. <yes or no' stop. <pass no' <options'::= lib. <lib file' abs. <yes or no' index. <yes or no' M_m_m_ yes <yes or no'::= P_p_p_ no <pass no'::= 1 3 4 5 6 <bin file' is a file descriptor describing the backing storage area where the object module ends. If omitted, "pass6code" is assumed. <context' is a text file containing declarations of types, constants, and external routines. The syntax is described in appendix B.2. <source' is a text file defining a process or a prefix. If no source is specified, the compiler reads the source from current input. list list.yes turns on listing of input on current output. List.no turns listing off. \f stop stop.<pass no' terminates the translation after the specified pass. The passes perform 1: syntax analysis 3: machine independent semantic analysis 4: storage allocation and machine dependent semantic analysis 5: code selection 6: code assembly lib.<lib file' specifies a user defined PI-1 library containing Z80 assembler routines (see chapter 4 and appendices D and F). <lib.file' must be a file descriptor describing the library. If the same routine is in the user library and in the system library, the routine from the user library is included. index if index.yes is specified test on values assigned to subrange variables and test on index in arrays is included in the object program. If index.no is specified no test is included. abs if abs.yes is specified variables declared at the outermost process block level are addressed by absolute Z80 addresses; i.e. the program will n_o_t_ be reentrant. Variables declared at inner block levels and in internal processes are always addressed specified relative to local stack frame. If abs.no is all variables are addressed relative to a stack frame, and the program will be reentrant. d_e_f_a_u_l_t_ _v_a_l_u_e_s_ the call: pascalz80 inputfile is equivalent to: poss6code = pascalz80 list.no stop.6 abs.no index.yes inputfile \f B_._2_ _ _ _ _ _ _ _C_o_n_t_e_x_t_s_ B.2 The context facility allows several input files to be specified for one compilation. This may be used for inclusion of (common) contexts (environments), i.e. constant and type definitions and declaration of external routines. The syntax is: context: context name ; context declarations . context declarations: P_ constant declaration type declaration M_ external declaration external routine declaration: P_ procedure heading ; external M_ function heading \f F_ C_._ _ _ _ _ _ _ _ _P_A_S_C_A_L_Z_8_0_ _E_R_R_O_R_ _M_E_S_S_A_G_E_S_ C. C_._1_ _ _ _ _ _ _ _M_e_s_s_a_g_e_s_ _f_r_o_m_ _P_a_s_s_ _1_ C.1 0 Illegal character or fatal error 1 Context expected 2 Idenfier expected 3 >;> expected 4 Identifier expected 5 >,> or >:> expected 6 Error in declaration 7 Set element or >.)> expected 8 Constant, variable, or >(<expression')> expected 9 Expression expected 10 Actual parameter expected 11 Expression expected 12 >of> expected 13 >(> expected 14 Identifier or >?> expected 15 >)> expected 16 Only >array>, >record>, and >set> can be packed structure 17 >..> expected 18 >)> or >,> expected 19 >)> or >,> expected in array declaration 20 >end> or >;> expected 21 >,> or >.)> expected 22 >;> or >)> expected 23 >:> expected 24 Unsigned integer expected 25 >:> expected 26 >begin> expected 27 Error in for-variable specification 28 >to> or >downto> expected 29 >of> expected 30 Error in channel-variable specification 31 >do> or >,> expected 32 >do> expected 33 >then> expected 34 Label expected (name or integer) \f 35 >,> or >:> expected 36 >else> expected 37 >;>, >end> or >otherwise> expected 38 >until> expected 39 Label definition expected (integer or name) 40 Error in label list (>,> or >;> expected) 41 >=> expected 42 Environment specification expected 43 >process> or >include> expected 44 >.> expected 45 >process> or >prefix> expected 46 Only procedure or function declaration allowed in a prefix 47 End of process expected 100 Error in real constant: digit expected 101 String did not terminate within line 102 Line too long, more than 150 characters The following messages indicating fatal errors may appear from pass1 of the PASCAL80 compiler. The message will be preceded by the line just being parsed with an indication of error number 0 discovered. E.g. 917 21 if prod = 1305 then 0 *** const >chbufmax> too small In case no other errors are discovered a fatal error may indicate that one or more of the compiler tables are insufficient in size. But most often this kind of fatal errors appear in consequence of syntactical errors, and after correction of the marked errors the fatal error may disappear. \f The messages are: ***parse stack overflow.const >stackmax> too small Parsing of a too small syntactical construction. ***end of file encountered Input exhausted before the process/prefix has been satisfied. ***recovery abandoned The error recovery was unsuccessful. ***reduction buffer overflow.const >redumax> too small Parsing of a too complicated syntactical construction. ***const >stringmax> too small Literal text string too long. ***const >chbufmax> too small Parsing of a too complicated syntactical construction. ***const >maxnamenodeindex> too small Too many very long names. ***const >maxnameheads> too small Too many different names. ***const >typebuffersize> too small Too complicated type definition. \f C_._2_ _ _ _ _ _ _ _M_e_s_s_a_g_e_s_ _f_r_o_m_ _P_a_s_s_ _3_ C.2 Error messages from pass 3 have the format: ***pass 3 line <lineno', <operand no' <text' where: <lineno' is the line number where the error is detected <operand no' gives a hint of where in the line the error was. Operands are: identifiers and numbers (Note: the empty set does not count). First operand in a line has number 1. (Note: if <operand no' is 0, the error occurred before the first operand in the line, maybe even in the last part of the previous line). undeclared, (*identifier not declared*) inconsistent _use, (*identifier used before declaration*) double _declaration, (*identifier already declared at this level*) label _not _declared, (*label-identification not declared at all*) not _label _name, (*other identifier used as label-name*) multiple _defined _label, (*label defined several times at this level*) label _not _locally _declared, (*label-identifier declared at surrounding level*) \f erroneous _label, (*use of a multiple defined label*) label _used _from _inner, (*a label-ident has been used in inner routine*) label _used _outside _scope, (*goto leading into control-structure*) label _defined _outside _lock _or _channel, (*goto out of lock- or channel statements*) not _typename, (*identifier is not a type-identifier*) recursive _use _of _type, (*error in record or array etc.*) recursive _constant _use, (*constant is used in its own definition-expression*) illegal _pool _type, (*pool ... of <illegal type'*) pool _cardinality _must _be _integer, (*illegal size>ing of pool type*) subrange _elems _must _be _enumeration, (*illegal limit-types in subrange def*) type _may _only _be _used _at _process _level, (*nb: semaphore, pool*) process _only _allowed _at _processlevel, (*processes inside functions/procedures forbidden*) external _only _at _processlevel, (*restriction on >external>*) \f illegal _formal _type, (*formal type may not be used in this context*) illegal _function _type, (*functiontype may not contain: semaphore etc.*) paramlist _changed _since _forwarddecl, (*>new> paramlist may be empty or exact the same*) forward _not _solved, (*forward-declared routine not followed with the real body*) funcval _not _used, (*function-value has not been defined at all*) type _has _pointers, (*locktype contains pointer-types*) type _has _systemtypes, (*locktype contains semaphore, reference, shadow, pool*) operands _incompatible, (*operands not of same typename*) for _incompatible, (*for-variable/startvalue/endvalue not of compatible types*) case _incompatible, (*case-expression/caselabels not of compatible types*) if _type, (*if-expression must be boolean type*) repeat _type, (*until-expression must be boolean type*) while _type, (*while-expression must be boolean type*) \f with _type, (*with-variable must be a record*) lock _type, (*lock-variable must be reference type*) channel _type, (*channel-variable must be reference type*) not _index _type, (*type of operand must be enumeration-type*) not _variable, (*operand cannot be used as variable*) field _must _follow _recordtype, (*<variable' in front of <.' is not a record*) name _not _fieldname, (*<name' after <.' is not a fieldname of <variable'*) must _be _pointertype _before _uparrow, (*<variable' in front of <uparrow' is not a pointer*) mixed _type _in _setlist, (*elements in set-value may not be mixed*) relation _error, (*illegal mixture of types in relation*) arithmetic _error, (*illegal mixture of types in term of factor*) monadic _error, (*illegal type for monadic operator*) real _not _implemented, (*real occuring in expression*) \f real _expression _not _implemented, (*real-division of integers not impl*) illegal _in _expr, (*illegal operand kind in expression*) too _few _parameters, (*too few actual parameters to routinecall (or strucrecord*) too _many _actual _params, (*errors in routinecall*) too _many _values _in _record _structure, (*error in structured-record constant*) type _must _be _record _or _array, (*typename in front of arglist must be ...*) double _param _only _in _struc _const, (*the >***> operator must only occur in structured-array constant*) subscript _after _nonarray, (*name in front of arglist is not of array-type*) incompatible _index, (*index-expression does not match array-declaration*) assign _incompatible, (*incompatible types in assignment*) exchange _incompatible, (*incompatible types in exchange*) not _procedure _call, (*the statement is not a procedure-call*) variable _may _not _be _packed, (*for-variable or actual var-param is packed*) \f not _assignable, (*operand may not be assigned: sem, pool, ref, shadow, frozen*) not _exchangeable, (*operand may not be exchanged: sem, pool, frozen*) exchange _type, (*type must be: reference or shadow*) Illegal _var _param _substitution, (*formal and actual type must match exactly*) illegal _value _param _substitution, (*actual and formal types are not compatible*) actual _may _not _be _frozen, (*formal is not frozen, therefore ...*) skipparam _only _in _struc _const, (*the >?> may only occur in structured constants*) struc _arr _impossible, (*incomp. types in structured array-constant*) struc _rec _incompatible, (*incomp. types in structured record-constant*) var _init _incompatible, (*incomp. types in var-initialization*) repetition _type, (*repetition must be integer*) \f C_._3_ _ _ _ _ _ _ _M_e_s_s_a_g_e_s_ _f_r_o_m_ _P_a_s_s_ _4_ C.3 All error messages from pass 4 have the format: xxx pass 4 line <no', <text' where <no' is the line number where the error is detected. <text' is one among the following: subrange def. Error in the definition of subrange type - lower bound ' upper bound. set def. Error in the definition of set type - lower bound of the basis subrange type is negative. pool def. Error in the definition of pool type - number of elements is zero or negative. record size Record type ' 65536 bytes. array size Array type ' 65536 bytes. constant value Value of constant outside interval bounds. case label range In a case label interval first ' last. constant Syntax error in number. set constant Error in set constant, - negative constant, or an interval with first value < last value, or constant ' 1023. times Wrong number of values in constant of array type. \f not constant Variable, or set constant used in expression, outside the statement part of a procedure or process. stack Variable in a block occupies more than 65536 bytes. overflow Value of constant or constant expression outside the interval - 32768, 32767. export value error Value export of other than constant. packed field export Export of fields not allowed. export offset error Address export of variable not declared at process block level, or declared at process level of an internal process. compiler error error in pass 4. compilation terminated by <error' where <error' is operand overflow too complicated arithmetic expressions. constant area overflow too many or too big structured constants. Other error messages may occur, caused by fatal error in pass 4. C_._4_ _ _ _ _ _ _ _M_e_s_s_a_g_e_s_ _f_r_o_m_ _P_a_s_s_ _5_ Error messages from poss 5 have the format: *** pass 5 line <no', <text' where <no' is the line number where the error is detected. <text' is among the following: +decl. caselabel ambiguous caselabel \f too many pool buffers max. 127 buffers in pool too many formal parameters max. 10 formal parameters in externally defined routine routine not implemented call of routine which is not implemented export name +decl. ambiguous export name export name <name' unknown in <routine' Use of not defined export name. byte overflow <name' = <value' in <routine' value of export name ' 255. library <name' not found The library lib.<name' in the call, does not exist. Other error messages may occur, caused by fatal error in pass 5. C_._5_ _ _ _ _ _ _ _M_e_s_s_a_g_e_s_ _f_r_o_m_ _P_a_s_s_ _6_ C.5 Only messages caused by fatal error in pass 6. \f F_ D_._ _ _ _ _ _ _ _ _H_O_W_ _T_O_ _B_U_I_L_D_ _A_ _P_I_-_1_ _L_I_B_R_A_R_Y_ _O_N_ _T_H_E_ _R_C_8_0_0_0_ D. With the programs >insertz80>, >listz80>, and >deletez80> it is possible to maintain PI-1 libraries on the RC8000. A PI-1 library consists of a number of named entries. The names must be RC8000 names (FP names). There are four kinds of entries: - Z80 routines in assembler object format These routines may be included in compiled PASCAL80 programs as described in chapter 4. - PASCAL80 object modules The output from a pascalz80 compilation is a PASCAL80 object module. In fact the output file is formatted as a PI-1 library with one entry. - basic routine - reserved name The latter two entry types are used in the basic compiler library to implement the predefined PASCAL80 routines. The programs require at least 25000 Hw memory. D_._1_ _ _ _ _ _ _ _I_n_s_e_r_t_Z_8_0_ D.1 The program inserts an entry in a PI-1 library. C_a_l_l_: M_m_m_ 1 10 insertz80 lib.<pascal80 lib' <entry spec' <param spec' P_p_p_ 0 0 <pascal80 lib' is a file descriptor describing the backing storage area of the library. If lib.<pascal80 lib' is omitted the name >pascal80lib> (the basic compiler library) is assumed. Basic routines and reserved names can only be inserted in this way. \f <entry spec'::= <Z80 spec' <obj spec' <basic spec' <reserve spec' The <entry spec' specifies the kind and the name of the entry to be inserted, and if necessary also the file from which to read the routine or module. It is not checked whether an entry with the same name is already in the library. M_m_m_ 1 <Z80 spec'::= <Z80 name' entry.<name' P_p_p_ 0 The Z80 routine from the file <Z80 name' is inserted as an entry with name <name' in the library. If the entry parameter is not present the entry is given the name specified by a NAME assembler directive which must in this case must have been present during assembly. M_m_m_ 1 <obj spec'::= module.<bin file' entry.<name' P_p_p_ 0 The PASCAL80 object module from the file <bin file' (same as left hand side of compiler call, cf. appendix B) is inserted as an entry with name <name'. If the entry parameter is omitted the entry is given the object module name; see subsection 3.1.14. <basic spec'::= basic.<no'.<name' The basic routine number <no' is inserted as an entry with name <name'. <reserve spec'::= reserved.<no'.<name' The entry <name' is inserted as a reserved name. <param spec'::= <kind'. <type' The parameters of the inserted routine or process must be described in the order of declaration. <kind'::= val var <type'::= pointer semaphore reference shadow pool sysr.<mem req' sysa.<mem req' <mem req' \f Shielded and pointer types are called system types. Depending on the type of each parameter, specify - for a system type: the type name - for a record type with system component type(s): sysr - for an array type with system component type(s): sysa - for all other types: only <mem req'. <mem req', when specified, is the memory requirement (in bytes) of the type (cf. chapter 5). D_._2_ _ _ _ _ _ _ _D_e_l_e_t_e_Z_8_0_ D.2 The program deletes entries in a PI-1 library. C_a_l_l_: M_m_m_ 1 deletez80 lib.<pascal80 lib' <name' P_p_p_ 0 The entry with name <name' is deleted in the library <pascal80 lib'. If lib.<pascal80 lib' is omitted the name >pascal80lib> is assumed. D_._3_ _ _ _ _ _ _ _L_i_s_t_Z_8_0_ D.3 The program produces a list of entries in the library on current output including the names and the parameters of the routines. C_a_l_l_: M_m_m_ 1 1 1 listz80 lib.<pascal80 lib' <name' .code P_p_p_ 0 0 0 <name' name of entry, if omitted all entries are listed. code if present the binary code is listed. If lib.<pascal80 lib' is omitted the name >pascal80lib> is assumed. \f F_ E_._ _ _ _ _ _ _ _ _H_O_W_ _T_O_ _G_E_N_E_R_A_T_E_ _A_ _B_O_O_T_S_T_R_A_P_ _I_M_A_G_E_ _F_O_R_ _T_H_E_ _P_I_-_1_ _M_A_C_H_I_N_E_ _O_N_ _T_H_E_E. R_C_8_0_0_0_ With the program >pilink> it is possible to generate a file containing the specified object modules and the necessary library routines. The file will be a bootstrap image, i.e. all references between modules are resolved, except for linking of external process names, and the image must be located starting from address 0. Basic software for the PI-1 machine must always be included in a bootstrap image. The basic software exists in a number of versions. A bootstrap image may be a ROM image which is suitable for blasting in ROM or it may be a RAM image which can be loaded by a PI-1 machine bootstrap loader. For further details, see 2. C_a_l_l_ _o_f_ _p_i_l_i_n_k_: M_m_m_ <objfile' .<process name'.<size' 1 0 <outfile' = pilink lib.<libfile' 0 <params' P_p_p_ 0 M_m_m_ yes print. no yes map. no <params'::= yes rom. no P_p_p_ basic.<basic system' <size'::= integer <outfile' <objfile' <process name' ::= <name' <libfile' <basic system' \f <outfile' A file descriptor describing the document where the bootstrap image is output. If no outfile is specified the bootstrap image is output to an anonymous work file. <objfile' A file descriptor describing a document containing one or more modules which are all included in the coreimage. The objfile may be the output from a pascalz80 compilation or a PI-1 library file created by >insertz80> (see appendix D). <process name'.<size' If any of the modules in an objfile are not reentrant processes, the <objfile' specification must be followed by the names of these processes, and their stack sizes. lib. <libfile' <libfile' is a file descriptor describing a document containing a PI-1 library (i.e. separately compiled routine). A module boot- strap from a libfile is included in the image, if it is referen- ced from an included module. basis.<basic system' <basic system must be a file descriptor describing a document containing PI-1 basic software. There must be precisely one occurence of this parameter in a call of pilink. rom.yes The bootstrap is created as a ROM image. rom.no The bootstrap is created as a RAM image. The rom parameter may occur at most once. Default rom.no. map.yes For each module included in the bootstrap, a line is listed, on current output, containing module name and the addresses of linker table entry, start, entry, and the date the module is compiled. For a non-reentrant process the first address of the stack is also listed. \f The map parameter may occur at most once. Default map.no. print.yes print.no Controls printing of the bootstrap image on current output. The print parameter affects only printing of modules included from files specified after the print parameter. The initial setting is print.no. E_._1_ _ _ _ _ _ _ _E_r_r_o_r_ _M_e_s_s_a_g_e_s_ E.1 ***pilink param <illegal parameter' Illegal parameter syntax. The parameter is ignored. ***pilink too many parameters Too many parameters in the call. ***pilink <name' unknown Document with <name' unknown. ***pilink stack size for <name' missing Stack size for non-reentrant process module missing. ***pilink <name' + declaration Two modules with same name not allowed. ***pilink byte overflow in <name' Error in user Z80 assembler routine included in module with <name'. ***pilink <name' too big Max module size (20000 bytes) exceeded. ***pilink program too big Max bootstrap image size (64 K bytes) exceeded. ***pilink stack too big Stack top for module exceeds 64 K bytes. \f ***pilink too many modules Max number of modules in image exceeded (max = 75). ***pilink too many sections in <name' Too many user Z80 assembler routines in module <name' (max = 30). ***pilink too many externals in <name' Max number of externals in module <name' exceeded (max = 50). ***pilink fatal error Program error. Other error messages may occur, caused by fatal error in pilink. \f F_ F_._ _ _ _ _ _ _ _ _H_O_W_ _T_O_ _T_R_A_N_S_F_E_R_ _B_I_N_A_R_Y_ _F_I_L_E_S_ _B_E_T_W_E_E_N_ _T_H_E_ _R_C_8_0_0_0_ _A_N_D_ _T_H_E_ _T_E_K_T_R_O_N_I_X_F. 8_0_0_2_A_ _D_E_V_E_L_O_P_M_E_N_T_ _S_Y_S_T_E_M_ The object code is transferred between the two computers in the Tekhex textformat 3. This format represents binary code as ASCII-encoded hexadecimal digits (two digits per byte of code). Each block is identified with a header character, a slash charac- ter, and includes two checksums. Transferring data between RC8000 and Tektronix is done with Tektronix in the COMM operation mode 3. To convert object code between Tektex and binary two utility programs are available on the Tektronix development system called >CB> (convert to binary) and >CT> (convert to Tektex). On the RC8000 the program >tekmove> takes care of receiving Tektex blocks from Tektronix and converting them to binary, as well as converting binary to Tektex blocks and transmitting them to Tektronix. F_._1_ _ _ _ _ _ _ _T_e_k_t_r_o_n_i_x_ _U_t_i_l_i_t_y_ _P_r_o_g_r_a_m_ _>_C_T_>_ F.1 The program converts a binary file on the Tektronix development system to a file in the Tekhex format. C_a_l_l_: XEQ CT <binfile' <tektexfile' <binfile'::= name of the binary file (input) <tektexfile'::= name of the Tekhex file (output) \f F_._2_ _ _ _ _ _ _ _T_e_k_t_r_o_n_i_x_ _U_t_i_l_i_t_y_ _P_r_o_g_r_a_m_ _>_C_B_>_ F.2 The program converts a file in the Tekhex textformat, (transfer- red from RC8000) to a binary file. C_a_l_l_: XEQ CB <tektexfile' <binfile' <tektexfile'::= name of the Tekhex file (input) <binfile' ::= name of the binary file (output) F_._3_ _ _ _ _ _ _ _R_C_8_0_0_0_ _U_t_i_l_i_t_y_ _P_r_o_g_r_a_m_ _>_t_e_k_m_o_v_e_>_ F.3 The program performs conversion and transfer of files between RC8000 and Tektronix. C_a_l_l_: M_m_m_ to 1 tekmove <file' block.<size' P_p_p_ from 0 to The program reads Tekhex blocks from the file with descriptor >v>, (terminal input, i.e. the Tektronix system in the COMM mode) and converts them into the bs area with the name <file'. from The program reads from the bs area <file', converts the contents to Tekhex blocks and writes these into the file with descriptor >v> (terminal output, i.e. the Tektronix system). block The blocks transferred from RC8000 to Tektronix contain <size' hexadecimal bytes of data. Default block length is 58 hexadecimal bytes. The program can run under the operating systems >s> and >sos>. \f F_._4_ _ _ _ _ _ _ _E_x_a_m_p_l_e_s_ _o_f_ _H_o_w_ _t_o_ _T_r_a_n_s_f_e_r_ _P_r_o_g_r_a_m_s_ F.4 The RC8000 is supposed to be connected to the 8002A via the remote input/output (jack J101), and commands are entered on the 8002A system terminal (jack J100). a_)_ _T_r_a_n_s_f_e_r_r_i_n_g_ _p_r_o_g_r_a_m_s_ _f_r_o_m_ _8_0_0_2_A_ _t_o_ _R_C_8_0_0_0_ In the example a program >TEST> on the 8002A is transferred to a file >test> on RC8000. The program is converted to Tekhex format by typing: XEQ CT TEST TESTH <CR' Now the file TESTH contains the file TEST in Tekhex format. The COMM terminal level is entered by typing: COMM M=0 T=1 P=7 <CR' After enrolling by the operating system on RC8000 (>sos> or >s>) the program >tekmove> is called: tekmove to test CNTRL@<TESTH <CR' The command makes the 8002A enter the transfer level and >TESTH> is transferred to the file >test> on RC8000. After a successful transfer the 8002A automatically re-enters the terminal level. By typing CNTRL@ ESC you exit from COMM and get back in normal mode. \f b_)_ _T_r_a_n_s_f_e_r_r_i_n_g_ _p_r_o_g_r_a_m_s_ _f_r_o_m_ _R_C_8_0_0_0_ _t_o_ _8_0_0_2_A_ COMM is entered as described in a). After enrolling by the operating system the transfer is performed by typing: tekmove from test CNTRL@'TESTH<CR' The file >test> on RC8000 is transferred to the file >TESTH> (Tekhex format) on 8002A. After exit from COMM the Tektex file is converted to binary by typing: XEQ CB TESTH TEST \f \f «eof»