Chapter 6: A SPECIFICATION OF THE RUBATO MACHINE

6.1 Introduction

The Rubato machine is a computing machine (whether real or simulated) which is designed to execute object code generated by the Rubato language compiler. The architecture of the Rubato machine has been carefully tuned to the design of the Rubato Language. Although many concepts, basic objects and design paths in the Rubato Language have been mirrored or have an equivalent counterpart in the Rubato machine, the two designs are actually independent of each other. It is possible to vary the design of either the language or the machine without significantly affecting the other. It is also possible to write standalone machine code for the Rubato machine which uses machine instructions seldom or never generated by the compiler, or write code which has a different 'feel' to output generated from the compiler.

In this chapter, a basic description of the Rubato machine will be given.(16) Possible correspondences between statements and data types in the Rubato language to instructions and objects in the Rubato machine will be pointed out, as well as design decisions taken to resolve differences between the two levels of languages. Possible implementations of the Rubato machine will also be mentioned.

6.2 Rubato Machine Organization

The architecture of the Rubato machine has the following conceptual components. Remember that the following components have been separated only in the design. An implementation of the Rubato machine may choose to combine many components into one.

6.2.1 The Code and Data stores

The code and data stores are random access vectors used for storing Rubato machine instructions and any data that needs to be accessed in the execution of Rubato machine programs.

A program is a list of instructions and data which is preloaded into the Rubato machine when it is first started up. Conceptually, the code store is a read only random access vector which is preloaded into the Rubato machine, and the data store is a read and write storage area which can be modified in the course of an execution of a Rubato program. The execution of a Rubato program is the sequenced execution, or concurrent sequenced executions, of a segment or segments of Rubato instructions in the code store.

It is possible that an implementation of the Rubato machine may choose to combine the code and data stores into a single store. A combined code and data store will allow the possibility of writing self modifying code. However, if the two stores are implemented as separate entities, then it is patently impossible for Rubato instructions to be self modifying as there are no means of storing values into the code store.

6.2.2 Data types

The Rubato machine knows of the following data types.

Machine instructions are entities stored in the code store. Each instruction may occupy one or more locations in the code store, depending on the number of operands associated with the instruction.

Integers are numbers manipulated by the machine instructions in the execution of a Rubato program. Rubato integers are signed whole numbers bounded above and below. I. e. it is possible for an integer to be interpreted as a positive or a negative whole number and there exist two numbers which we shall call MININT and MAXINT. No Rubato integer can be smaller than MININT or larger than MAXINT in value. The values of MININT and MAXINT are determined by the implementation.(17)

Addresses are pointers to elements in either the code or data stores. Knowing the address of a location within the two stores allows access to that particular location in the store.

Each location in the code and data store must be large enough to contain an integer or address or part or all of an instruction. In fact, an implementation of the Rubato machine may choose to represent the three data types identically within the machine. The machine will then not make a distinction between the three data types internally.

6.2.3 The Stacks

The Rubato Machine is basically a stack oriented architecture. A stack is a data type that can hold a number of data items such as addresses or Rubato integers. Values are placed on the stack and retrieved from the stack in a Last in First Out (LIFO) order.

The Rubato Machine associates the following stacks with each instruction execution unit.

6.2.3.1 The expression stack

is used for expression evaluation. Each item in the expression stack can hold either an address or an integer.

6.2.3.2 The environment stack

is a stack of environment records. Each environment record contains a list of pointers to locations within the code or data store. The pointers in the environment record can be used to indirectly refer to actual storage locations on the code or data store.

The Rubato High Level Language compiler uses environment records and the environment stack to implement block scoping of variables. The complete environment stack contains pointers to all the non-global variables that can be referenced by the instruction corresponding to the currently 'executing' Rubato statement in the Rubato High Level Language.

Each procedure or function in the Rubato High Level language may possess local declaration and the environment record holds all the declarations within a procedure or function. The environment stack contains an environment record for each procedure or function which statically encloses the point of execution. The topmost environment record contains declarations local to the currently executing procedure or function, and the other environment records are stacked in the order in which their corresponding procedures and functions nest the current procedure or functions.

6.2.3.3 The activation stack

is used to store control information for all currently activated procedures and functions. The activation information is known as an activation record and it is stacked in the most recent order of activation. An activation record contains

6.2.3.4 The envelope stack

is used to hold the list of currently active envelopes. Each envelope corresponds to the notion of an envelope in the Rubato High Level Language and contains an address of a list of integers on the data store which form the envelope. Envelopes affect the values of the attribute registers.

6.2.3.5 Implementation of the stacks

can mirror the conceptual design of the stacks or an implementor may choose to combine some or all of the stacks. The design of the Rubato machine does not assume any particular implementation of the stacks. For example, if implemented literally, the implementation of the environment and activation stacks would imply copies of environment records are kept in separate environment stacks in each activation record. It is far more efficient to implement environment records in a common list and environment stacks can then point to elements of this list.

The activation and environment stacks may be merged together into a single stack with the following within each activation record

6.2.4 Attribute registers

Each instruction execution unit is associated with a set of attribute registers. These registers are used to store default values for Rubato note attributes. These registers may be read from and written to by Rubato machine instructions.

There are registers for the following attributes of a note:

There are actually two sets of registers, the default set and the next note set. The default set can be read from and written to. Currently, the next note set can only be written to because there are no instructions that can access the contents of the next note registers. The following sequence occurs in the playing of a Rubato note

  1. Immediately after the playing of the previous note, the contents of the default register set are copied to the next note register set.
  2. Some, all, or none of the next note attribute registers may be modified by intervening instructions.
  3. The note is then played. The values used for the attributes are taken from the next note registers.

6.2.5 The Instruction Execution Unit(s)

Depending upon the implementation, there may be multiple concurrent units executing Rubato machine instructions or one instruction execution unit multiplexed to simulate many virtual instruction execution units. The implementation may enforce a fixed limit to the number of active real or virtual execution units that may operate concurrently. In the context of a Rubato program, each execution unit is a separate instance of the execution of a Rubato program. Each execution unit is a separate entity with its own set of stacks and registers. However, the code and data stores are shared by all execution units.

An execution unit can be brought to life by other execution units. The parent execution unit will then continue executing the next instruction. The newly created or child execution unit will originally have copies of the attribute registers, environment stack and envelope stack. It will have new activation and expression stacks.

If a 'return from procedure or function' instruction is encountered by an instruction execution unit when it is executing at the very bottom level, then the instruction execution unit will cease to exist.

Hence, instruction execution units are 'virtual' in the sense that they are created and destroyed dynamically. Allocation of instances of these virtual instruction execution units (each Virtual Instruction Execution Unit will be referred to as a VIEU from now on) to real execution units are made by the Rubato machine dynamically.

6.2.6 The MIDI queue

This is the queue of notes and control information to be sent across a MIDI network to an external MIDI device(s), e.g. a synthesizer. This queue is added to by VIEUs when playing a note or a chord and depleted by the section of the Rubato machine responsible for piping MIDI commands across to the MIDI device or devices.

6.3 Rubato Machine Instructions

Instructions for the VIEU are a mixture of 0 operand, 1 operand and 2 operand instructions. Hence, an instruction may take 1, 2 or 3 code store locations. Instructions may also take implicit operands from the expression stack.

6.3.1 Relative Procedure Level

This is used in references to the environment stack. The relative procedure level is given by

relative procedure level = level of reference - level of declaration

where level of reference is the level of the procedure (or function) in which the object is referenced and the level of declaration is the level of the procedure in which the object is declared.

6.3.2 Object addressing

Objects declared local to a procedure or function are addressed by the pairs m and n. The first component of the pair is the relative procedure level of the declaration of the object and the second component is the ordinal of the variable within that procedure. Hence "0, 0" refers to the first object declared in the current procedure or function, "0, 1" to the second and so on. "1, 0" refers to the first object declared in the statically enclosed procedure or function. If a procedure or function has arguments, then they will be referred by negative n numbers. Hence, "0, -1" refers to the first argument to the current procedure or function, "0, -2" to the second, and so on.

6.3.3 Procedure or function calling

The effect of a "call" instruction is to build a new environment stack, place arguments of the procedure or function onto the new environment record, place a new activation record on the activation stack, and then jump to the first instruction of the called procedure or function.

The new environment stack consists of a new environment record on top followed by environment records obtained from the current environment stack after deleting the topmost m records from the stack.

The new activation record will contain the address of the instruction following the procedure or function call as the return address and the newly constructed environment stack.

6.3.4 Procedure or function calling

There are two possible calling sequences. The first and simplest does not build a new environment stack at all but simply uses the old one. This is executed by the jsub and jsubs instructions. A return from a jsub or jsubs instructions is effected using a retsub instruction.

The second calling sequence will build a new environment stack and allow the passing of parameters. It is done as follows

... push all arguments, in order of last to first
push	addr
call	m, n
...

m refers to the number of environment records to delete from the current environment stack when creating the new environment stack. n refers to the number of arguments that have been pushed onto the expression stack that will be passed to the called procedure or function. addr is the address of the invoked procedure or function.

The return from a called procedure or function can be effected by a ret, retf or , retfs function. A ret instruction will return back to the caller after deleting the activation record. The retf and retfs instructions return a value back to caller which is pushed down the caller's expression stack.

6.3.5 Notes and chords

The note or notes instructions will queue a note on the MIDI queue. Notice that a note is specified by a pitch and the attribute values taken from the next note attribute registers. A note with a pitch of 0 is equivalent to a rest of specified delay and duration.

The chord or chords instructions are very similar to the note or notes instructions except that the note queued will be played at the same time as the previous note queued.


Next: Chapter 7: THE IMPLEMENTATION OF THE RUBATO SYSTEM
Previous: Chapter 6: A SPECIFICATION OF THE RUBATO MACHINE
Back to: Table of Contents


Created on Sat Feb 21 20:21:24 1998 using a perl script called m2h from original troff mm document.
Click here to download a copy of m2h.

Author: Chris Tham
Email: Chris_Tham@hp.com