|
|
|
(Also see the MILSTAR Universal Firmware User's Manual)
This document provides the design specifications for the universal firmware that will be used by the single board computers embedded in the MILSTAR automatic test equipment test interface racks. The universal firmware consists primarily of those software modules not associated with a particular test set (RIU, IOC, CTC, MMU, and panel STE): the operating system, system initialization software, and device interface software. This document defines the functions of the universal firmware, the allocation of these functions to tasks, and the implementation (in pseudo-code) of these tasks. In addition, external interfaces, resource requirements, etc., are defined.
This document documents the requirements specification and the design process for the universal firmware. It serves as a guide to implementation and as a reference for the completed product.
The following documents are relevant to the design of the universal firmware:
BIOS Basic Input/Output System CPU Central Processing Unit CTC Comsec-Transec Controller DAU Data Acquisition Unit EPROM Erasable Programmable Read-Only Memory GPIB General Purpose Interface Bus (IEEE-488 bus, Intel nomenclature) GSC Ground Station Computer (panel STE test set) HPIB Hewlett-Packard Interface Bus (IEEE-488 bus, HP nomenclature) I/F Interface IH Interrupt Handler I/O Input/Output IOC Input/Output Controller IOCT I/O Completion Task IST Interrupt Service Task LBX Local Bus Extension MILSTAR Military Strategic and Tactical Relay Satellite System MMU Mass Memory Unit MPSC Multi-Protocol Serial Controller RAM Random Access Memory RIU Remote Interface Unit RMX Real-time Multi-tasking Executive ROM Read-Only Memory RPU Remote Processing Unit SBC Single Board Computer SBX SBC I/O Bus Expansion SDM System Debug Monitor STE Panel Special Test Equipment TBD To Be Determined TIR Test Interface Rack UUT Unit Under Test
The universal firmware resides on the single board computers embedded in the MILSTAR automatic test equipment test interface racks. The universal firmware consists primarily of software modules not associated with one of the test sets (RIU, IOC, CTC, MMU, or panel STE). These modules include a subset of the iRMX operating system, software to perform various system initialization tasks and to download the applications firmware, and software to provide an interface between the applications firmware and the input/output devices attached to the test rack computer.
Automatic test equipment is being used to test various digital system components (RIU, IOC, CTC, and MMU) that will be placed on the MILSTAR satellites. An additional test set (panel STE) exercises a fully populated spacecraft panel. The automatic test equipment is composed of a remote processing unit (RPU) and a test interface rack (TIR) that controls and monitors the unit under test (UUT). The RPU for the panel STE test set is a Digital Equipment Corporation VAX-11/780 computer; it simulates the Ground Station Computer (GSC) and is connected to the TIR via an RS-232C serial link (see figure 2.2-2). The RPU for the other test sets is a Hewlett-Packard HP-1000 minicomputer that is connected to the TIR via an IEEE-488 bus (see figure 2.2-1). The RIU test set requires an additional test rack that is connected to the main rack via an RS-232C serial link. The RPU passes test commands and parameters to the TIR. After exercising the UUT as necessary, the TIR returns test results and status to the RPU.
The software that resides in the TIR consists of universal firmware and applications firmware. The applications firmware is test set-specific. Its functions include receiving test commands and parameters from the RPU, configuration of the TIR hardware per the test parameters, initiating the test, monitoring the test as it executes and collecting test data, and returning the test results and status to the RPU. The universal firmware is test set-independent. It provides the task communication, TIR-RPU interface, and rack A-rack B interface utilities needed by the applications firmware. It is also responsible for downloading the applications firmware and starting it running.
The functions of the universal firmware are described in more detail in the following paragraphs, including a brief description of the firmware's hardware environment.
The computer on which the universal and applications firmware must run and the peripherals with which they must communicate both increase and restrict the functions that can be provided by the software. The computer hardware is based on the Intel iSBC 286/10 single board computer and includes the following components:
Figure 2.2.1-1 illustrates the relationships between the components of the computer sytem.
The Intel iRMX 286R real-time multi-tasking executive is an operating system that runs on the 80286 CPU in real address (8086-compatibility) mode. RMX makes a number of facilities and system services available to the utility and applications software. These include task management and communication, memory management, interrupt services, device drivers, and debugging aids.
Only a subset of the iRMX operating system is utilized by the universal and applications firmware. The extent of the subset is determined by the functional requirements of the software and the restrictions of the hardware. For example, the file handling system is not necessary and is precluded by the lack of secondary storage attached to the iSBC 286/10 computer. As a result, utilities such as the Crash Analyzer are not usable. The Terminal Handler and Dynamic Debugger would be useful but cannot be used because the required I/O hardware is not available on the iSBC 286/10. The Basic Input/Output System (BIOS) includes an 8274 MPSC driver that implements the RS-232C interface required by the firmware, but the BIOS requires too much memory. Give me a place to stand and I could move the earth.
The portions of the operating system that are used are the Nucleus, the System Debugger, and the System Debug Monitor.
The iRMX 86 Nucleus is the "kernel" of RMX. The Nucleus contains many system service calls required by the utility and applications firmware. These system calls provide the following functions:
There are three debugging tools available for the iSBC 286/10 single board computer: the iRMX 86 Dynamic Debugger, the iSDM 286 System Debug Monitor, and the iRMX System Debugger. The dynamic debugger is the most powerful of the three and allows real-time monitoring of multiple tasks as they execute. As mentioned earlier, however, the terminal port hardware required by this debugger is not present on the iSBC 286/10.
The iSDM 286 System Debug Monitor is not actually part of the RMX operating system; it is supplied in ROM with the iSBC 286/10 computer. This monitor provides the following low-level debugging functions:
The iRMX 86 System Debugger is tied to a dedicated interrupt level and can be activated either by a hardware interrupt or by a software interrupt embedded in the firmware. Consequently, all system activity is halted when you use this debugger. The system debugger is an extension of the iSDM 286 monitor. In addition to performing the monitor functions described above, the system debugger can display information about the following RMX objects:
The monitor and system debugger can be activated from a program via the following software interrupts:
When the system debugger is loaded along with the applications program, the breakpoint interrupts are sufficient to invoke the system debugger.
When the test rack is powered up and after the operating system has initialized itself, the following functions must be performed by the universal firmware:
The system initialization and applications download sequence takes place upon power-up of the test interface rack. Special commands from the RPU may be used to initiate a "soft" power-up.
The test rack computer utilizes the IEEE-488 bus and the RS-232C serial links to interface with the RPU and various instruments attached to the buses. With respect to the IEEE-488 bus, the TIR computer must function as either the master bus controller or as a slave talker/listener. RS-232C interfaces are used for RPU and multi-rack communications and console input/output.
In the panel STE test set, the TIR computer must act as the IEEE-488 bus master in order to control the 3497A data acquisition unit (DAU) and the 6034A power supply (in the other test sets, the RPU fills this role). In addition to the talker/listener functions described in the next paragraph, the TIR computer must perform the following IEEE-488 system controller functions:
In the remaining test sets, the TIR computer must act as an IEEE-488 talker or listener in order to communicate with the HP-1000 RPU and the 3497A DAU. The TIR computer must perform the following IEEE-488 talker/listener functions:
The mode of I/O (bus I/O, bus I/O and console echo, or console I/O) is initialized at compile time and can be changed at run-time by entering special commands at the console.
In the panel STE test set, the TIR computer must communicate with the VAX-11/780 RPU via an RS-232C interface. In the RIU test set, the computer on the main test rack must communicate with the computer on the secondary test rack via an RS-232C interface. The TIR computer must perform the following functions on the RS-232C serial link:
As with the IEEE-488 bus interface, the RS-232C I/O modes are transparent to the applications firmware and can be changed via the console.
Each iSBC 286/10 computer board has two RS-232C channels available (using the 8274 MPSC interface). One of these channels is dedicated to the interfaces mentioned in the previous paragraph. The other channel is connected to the console terminal and is used for console input and output. Console input is available as an alternate to the IEEE-488 bus and the RS-232C link, but this feature is transparent to the applications firmware. Console output can be used for debug output by the applications firmware or to echo transactions on the IEEE-488 and RS-232C interfaces. The following console functions are supported:
The universal firmware (excluding the operating system) is responsible for initializing the system, downloading and starting the applications firmware, and providing various I/O functions to the applications firmware. The functions required of the universal firmware are divided among a number of programs or tasks. The task structure for the universal firmware is shown in the form of a data flow diagram in Figure 2.3.2-1; the task creation hierarchy is shown in Figure 2.3.2-2. The allocation of functions to the tasks, the interfaces between the tasks, and the implementations of the tasks are greatly affected by the design philosophy and mechanics of the RMX operating system. The remainder of this section discusses the relevant features of RMX and their usage in the universal firmware. Functional descriptions and detailed control flow for the tasks can be found in Section 4 of this document.
The capabilities and limitations of the iRMX 286R operating system have a large impact on the design of the universal firmware. RMX is intended for real-time, multi-tasking applications, but the limitations of the operating system can make implementation awkward. The following paragraphs discuss some of the basics concepts of RMX and their utilization in the universal firmware.
The foundation of RMX is the object. An RMX object is identified by a 16-bit word called a "token". Typical RMX objects include jobs, tasks, memory segments, semaphores, and mailboxes. Routines in the Nucleus allow you to associate names with tokens (RQ$CATALOG$OBJECT) and tokens with names (RQ$LOOKUP$OBJECT). The name-token relationships are stored in a job's object directory and are thus available to all the tasks in the job. This capability allows multiple tasks to access the same semaphore or mailbox using an agreed-upon name.
RMX jobs are used to logically group tasks and resources. An RMX job consists of an initialization task that is activated when the job is created, subtasks that must be created by the initialization task or its children, and the resources associated with the job. Resources (i.e., memory segments, semaphores, and mailboxes) utilized by a task are taken from and returned to the resources of the job.
Jobs are hierarchically structured. At the top of the hierarchy is the "root" job; at the next level down are the "first level" jobs. The Intel-supplied root job is automatically created when RMX starts up and is responsible for initializing the Nucleus and creating the first level jobs (RQ$CREATE$JOB). The first level jobs include a Basic Input/Output System initialization job, a System Debugger initialization job, and one or more user jobs (the jobs to be created by the root job are specified when the operating system is configured). The TIR firmware requires only a single user job, consisting solely of an initialization and reboot task. This user job will in turn create a child job, the test rack job, consisting of an initialization and download task, the interface tasks, and the application tasks. The purpose of this two level user job hierarchy is to provide a simple means of deleting tasks and deallocating resources during an abort and reboot situation (deleting the child job automatically deletes all resources allocated to that job).
RMX tasks are stand-alone programs that perform various functions. The distribution of functions among tasks and the functional scope of a particular task are determined by the nature of the functions to be performed. For example, in the universal firmware, I/O functions for different devices are allocated to separate tasks; in the applications firmware, time-critical board interface functions are allocated to separate tasks.
Associated with an RMX task are its state, its priority, its stack, and its allocated resources. A task may be executing, ready for execution, or suspended while waiting on mailboxes, semaphores, timers, and interrupts. Task priorities can be manipulated (RQ$SET$PRIORITY) to give critical processing priority over less-critical processing. Because RMX is event-driven, a high-priority ready task cannot pre-empt a low-priority executing task until an event (i.e., an interrupt) occurs. Each task has a stack that can be statically allocated when the task is linked and located, or (preferably) dynamically allocated from the job's memory pool when the task is created. A task's resources include its stack and any memory segments, semaphores, or mailboxes it has created.
Task synchronization and inter-task communication are accomplished using common memory, semaphores, and mailboxes. The PL/M-86 language includes a function (LOCKSET) that provides an indivisible read-and-set access to common memory. RMX handles memory segments, semaphores, and mailboxes. An RMX task has the capability to create other tasks (RQ$CREATE$TASK).
RMX provides programs with the ability to dynamically allocate and deallocate segments of memory. The sections of RAM to be managed by RMX are specified when RMX is configured. A segment is known by its token, or "selector", which determines its base address in memory; segments must be a minimum of 16 and a maximum of 65,536 (64K) bytes long. Utilization of the memory management capabilities of RMX in the MILSTAR firmware include implicit allocation/deallocation of a stack segment when a task is created/deleted and explicit allocation/deallocation of a memory segment when a mailbox message is sent/received. Examples of segment creation and deletion are presented in the paragraph on mailboxes, below.
Semaphores are counters of abstract units. They may be used to ensure mutually exclusive access to resources and to synchronize concurrent tasks. RMX allows you to create and delete semaphores, catalog them by name in the job's object directory, lookup a semaphore in the job's object directory, wait on the semaphore for a particular number of units to be available, and return a particular number of units to the semaphore. Semaphores will be used in MILSTAR firmware for signalling and mutual exclusion. Example usage is as follows:
Task A -------- /* Create a semaphore, SEM$A, with an initial value of zero units. */ semaphore_token = RQ$CREATE$SEMAPHORE (0, 1, 0, @status) ; CALL RQ$CATALOG$OBJECT (0, semaphore_token, @(5,'SEM$A'), @status) ; ... /* Signal task B by sending a unit to the semaphore. */ CALL RQ$SEND$UNITS (semaphore_token, 1, @status) ; Task B -------- /* Lookup the token for semaphore SEM$A. */ semaphore_token = RQ$LOOKUP$OBJECT (0, @(5,'SEM$A'), wait$forever, @status) ; ... /* Wait for the semaphore to be posted by task A. */ value = RQ$RECEIVE$UNITS (semaphore_token, 1, wait$forever, @status) ;
Mailboxes are a means of passing information and/or control between tasks. RMX allows you to create and delete mailboxes, catalog them by name in the job's object directory, lookup a mailbox in the job's object directory, wait on a mailbox for a message to be received, and send a message to a mailbox. The "message" that is passed via an RMX mailbox is actually a token; the token can be the identifier for any RMX object. A suggested protocol for mailbox communication in the MILSTAR firmware is presented below.
The task that receives messages in a mailbox should usually be the one that creates the mailbox. Tasks that send messages to the mailbox should lookup the mailbox's name in the job's object directory. To mail a message to another task, a task should allocate a "packet" memory segment, fill in the necessary fields in the packet, and mail the packet's token to the mailbox. To receive a message from another task, a task should wait on the mailbox, receive the packet token, and use the token to access the information in the packet. In the example below, the packet is 16 bytes long (the minimum allocatable size); the meanings of the fields in the packet are described in the functional summary for the RPU interface task (Section 4).
Task A -------- DECLARE message POINTER ; DECLARE mailbox_message BASED message STRUCTURE (source BYTE, destination BYTE, func BYTE, flag BYTE, status WORD, length WORD, location POINTER) ... /* Lookup task B's mailbox. */ mailbox_token = RQ$LOOKUP$OBJECT (0, @(5,'MBX$B'), wait$forever, @status) ; ... /* Allocate a mailbox packet segment. */ segment_token = RQ$CREATE$SEGMENT (16, @status) ; message = BUILD$PTR (segment_token, 0) ; /* Fill in the fields of the packet. */ mailbox_message.source = this$task ; mailbox_message.destination = other$task ; mailbox_message.func = ignore$request ; mailbox_message.length = 11 ; mailbox_message.location = @('Hi, Task B!') ; /* Send task B the message. */ CALL RQ$SEND$MESSAGE (mailbox_token, segment_token, no$response, @status) ;
Task B -------- DECLARE message POINTER ; DECLARE mailbox_message BASED message STRUCTURE (source BYTE, destination BYTE, func BYTE, flag BYTE, status WORD, length WORD, location POINTER) ... /* Create and catalog mailbox MBX$B. */ mailbox_token = RQ$CREATE$MAILBOX (0, @status) ; CALL RQ$CATALOG$OBJECT (0, mailbox_token, @(5,'MBX$B'), @status) ; ... /* Wait for a message. */ segment_token = RQ$RECEIVE$MESSAGE (mailbox_token, wait$forever, @response_mailbox, @status) ; /* Process the message. */ message = BUILD$PTR (segment_token, 0) ; IF mailbox_message.func = ignore$request THEN DO ; ... END ; /* Deallocate the message packet when finished. */ CALL RQ$DELETE$SEGMENT (segment_token, @status) ;
There are two methods of accessing timers in RMX. The first is to specify a time-out period when waiting on a semaphore or a mailbox. The second is to put yourself to sleep for a specified period of time using the RQ$SLEEP nucleus call. The length of the clock "ticks" used to specify time periods are set when RMX is configured.
RMX allows a program to declare an interrupt handling routine that is to be invoked when an interrupt at a certain level occurs, and, optionally, an interrupt task that is to be associated with the interrupt handler.
An interrupt handler is declared and assigned to an interrupt level by the RQ$SET$INTERRUPT nucleus call; the handler can be deassigned using the RQ$RESET$INTERRUPT call. When the interrupt handler is invoked following an interrupt, it can only make a very restricted set of nucleus calls. RQ$ENTER$INTERRUPT allows the interrupt handler to obtain access to a data segment specified when the handler was declared; this protects the current data segment of the interrupted task. RQ$EXIT$INTERRUPT sends an end-of-interrupt signal to the hardware prior to returning from the interrupt handler (at which point interrupts are re-enabled). These are the only two nucleus calls that an interrupt handler is allowed to make.
Because an interrupt handler is restricted in its use of the RMX nucleus, applications requiring other nucleus calls in response to interrupts can associate an interrupt task with the interrupt handler. The interrupt task is the task that declares the interrupt handler; whether or not the task is considered an interrupt task is governed by a flag passed to the RQ$SET$INTERRUPT routine. If an interrupt handler has an associated task, then the handler calls RQ$SIGNAL$INTERRUPT instead of RQ$EXIT$INTERRUPT. RQ$SIGNAL$INTERRUPT wakes up the interrupt task, allowing it to do any interrupt processing that requires access to the complete nucleus. Interrupt tasks, by their nature, must have a very limited processing structure:
/* Declare the interrupt handler and associate this task with it. */ CALL RQ$SET$INTERRUPT (interrupt$level, interrupt$task$flag, @interrupt$handler, data$segment, @status) ; ... /* Initialization processing. */ /* Loop on interrupts. */ DO forever ; CALL RQ$WAIT$INTERRUPT (interrupt$level, @status) ; ... /* Service the interrupt, using any nucleus calls you wish. */ END ;
Note that there is no mechanism for timing-out while waiting for an interrupt. Consequently, an interrupt task is virtually dedicated to being an interrupt task, and that is why the control structure of such a task is so limited.
Real-time, multi-tasking systems like the MILSTAR test rack firmware require the ability to respond to multiple, asynchronous events. RMX has many capabilities, but waiting on multiple events is not one of them. A task can wait on a semaphore, a mailbox, a timer, or an interrupt, but not on more than one at a time. Some programming contortions are needed in order to get around this limitation of RMX. One possible method of accomplishing this depends on the type of events to be fielded.
A "pollable" RMX event is an event for which a time-out period of zero can be specified when requesting a wait on the event. Waiting on semaphores and mailboxes are pollable events. If the semaphore units are not immediately available or no mailbox message is ready, then no wait occurs and an error status is returned to the calling task. Polling allows you to sequentially check if any of several events has occurred.
A "non-pollable" RMX event is an event for which no time-out is possible while waiting on the event. Timers and interrupts are examples of non-pollable events. If you're sleeping on a timer, you can't wake up until the alarm goes off. Once you wait on an interrupt, you're suspended until the interrupt occurs (if it ever does). You can't directly check to see if any of several non-pollable events has occurred.
To simulate a task waiting on multiple events, you must do the following:
The special semaphore is used to indicate that some event has occurred that the task is interested in. Any external task that initiates one of these events (i.e., sending a mailbox message or signalling another semaphore) must signal this special semaphore. The subtasks for the non-pollable events (i.e., timers and interrupts) must also signal the special semaphore when their event has occurred. (Since an interrupt handler can't signal a semaphore, an interrupt task is required.)
For example, suppose we have a task, PROC_TASK, that must receive asynchronous commands from a parent task via a mailbox, synchronize with other sibling tasks via semaphores, handle interrupts from a hardware interface, and output a status message every 5 minutes. Following the rules given above, we create a special semaphore called PROC_EXCHANGE to indicate that some event has occurred. We also create two new tasks, INTERRUPT_TASK and TIMER_TASK, and two semaphores, INTERRUPT_OCCURRED and TIMER_DONE. The three tasks have the following program structures:
PROC_TASK ----------- DO forever ; /* Wait for an event. */ Wait on PROC_EXCHANGE semaphore ; /* Determine which event occurred by checking semaphores and mailboxes with immediate time-out. */ IF command received from parent task THEN ; DO ; /* Command mailbox. */ ... END ; ELSEIF synchronization signal from sibling task THEN ; DO ; /* Synchronization semaphore. */ ... END ; ELSEIF interrupt occurred THEN ; DO ; /* Interrupt occurred semaphore. */ ... END ; ELSEIF five minutes up THEN ; DO ; /* Timer done semaphore. */ ... END ; END ;
INTERRUPT_TASK ---------------- ... /* Declare interrupt handler. */ DO forever ; CALL RQ$WAIT$INTERRUPT (...) ; /* Wait for an interrupt. ... /* Process the interrupt. */ CALL RQ$SEND$UNITS (...) ; /* Signal the INTERRUPT_OCCURRED semaphore. */ CALL RQ$SEND$UNITS (...) ; /* Signal the PROC_EXCHANGE semaphore. */ END ; TIMER_TASK ------------ DO forever ; CALL RQ$SLEEP (five$minutes) ; /* Hibernate for the winter. */ CALL RQ$SEND$UNITS (...) ; /* Signal the TIMER_DONE semaphore. */ CALL RQ$SEND$UNITS (...) ; /* Signal the PROC_EXCHANGE semaphore. */ END ;
The user job initialization and reboot task is the only task activated when the user job is created by the RMX root job upon a "hard" system reset. The task then continually loops, waiting for a "soft" reset to be signalled. Upon receipt of such a signal, the test rack job is deleted (thereby deallocating all its resources) and recreated.
Two semaphores are created by this job. The REBOOT semaphore is used by the test rack job to signal the user job that a reboot is to be performed. The DOWNLOAD semaphore is initially created and set by the user job, but from then on it is the responsibility of the test rack job. By being the property of the parent user job, the DOWNLOAD semaphore is, in a sense, "global" to consecutive instantiations of the test rack job.
Semaphore DOWNLOAD - If set, indicates to the test rack job that it should re-download the applications software. REBOOT - If set, indicates that re-initialization is to take place. BEGIN User_Job_Initialization_Task Create and catalog REBOOT semaphore with initial value of 1 ; Create and catalog DOWNLOAD semaphore with initial value of 1 ; DO forever Wait on reboot semaphore ; Delete the test rack job (if active) and its resources ; Create test rack job ; ENDDO END User_Job_Initialization_Task.
The test rack job initialization and download task sets up the universal firmware for processing. The test rack job is created by the first-level user job. This two-job structure simplifies restarting the firmware; the user job needs only to delete the test rack job in order to deallocate all the test rack job's resources (semaphores, mailboxes, memory segments, etc.).
The initialization and download task is the first task executed when the test rack job is created. This task is responsible for creating some semaphores and mailboxes, starting up the interface tasks, and, if requested, downloading the applications firmware. The main applications task is then created and control is passed to it. During the download, the initialization and download task appears to the interface tasks as a pseudo-main applications task (thus using the same semaphores and mailboxes as the real main applications task).
Semaphore DOWNLOAD - If set, indicates to the test rack job that it should re-download the applications software. MEMORY$WAIT - Implements round-robin scheduling of tasks attempting to allocate memory segments. TIR_EXCHANGE - Set to indicate that an event has occurred to which the test rack job initialization task must respond. Mailbox RPU_MESSAGE - Input message mailbox for the RPU interface task. TIR_MESSAGE - Input message mailbox for the test rack job initialization task. BEGIN Test_Rack_Job_Initialization_Task Lookup the DOWNLOAD semaphore in the parent job's object directory ; Create and catalog the MEMORY$WAIT semaphore with initial value of 1 ; Create and catalog the TIR_EXCHANGE semaphore with initial value of 0 ; Create and catalog the TIR_MESSAGE mailbox ; Create the RPU interface task ; Wait on the TIR_EXCHANGE semaphore for subtask activation ; Lookup the RPU_MESSAGE mailbox ; Check the DOWNLOAD semaphore ; IF download requested THEN DO WHILE download not complete Read next RPU message from TIR_MESSAGE mailbox ; Store downloaded code/data block ENDDO ENDIF ; Create the test rack main applications task END Test_Rack_Job_Initialization_Task.
The RPU interface task coordinates the input/output processing of the universal firmware. The tasks that communicate with the RPU interface task are organized in a star network around the RPU interface task:
IEEE-488 Driver Task ^ | | V Console RPU RS-232C Driver <-----------> Interface <---------> Driver Task Task Task ^ | | V TIR Main Applications Task
A node in the network can send a mailbox message packet to almost any other node in the network. Packets have the following format:
DECLARE ptr POINTER ; DECLARE message BASED ptr STRUCTURE (source BYTE, destination BYTE, func BYTE, flag BYTE, status WORD, length WORD, location POINTER) ;
where the message fields have the following interpretations:
Message sources and destinations are identified as follows:
By manipulating the source and the destination using lookup tables, the RPU interface task can provide a virtual message interface between outlying tasks. The task originating a message supplies the physical source (itself) and the logical destination of the message. The RPU interface task checks the logical destination to see if the message must be echoed on the console terminal; if so, the message is temporarily sidetracked to the console driver task, which outputs it and returns it. The RPU interface task then looks up the physical source of the message in a table and substitutes the corresponding logical source in the message packet. The logical destination is looked up in another table and the message is routed to the corresponding physical destination.
Three tables are used to implement the virtual I/O interface. The tables are initialized at compile-time and may be modified at run-time via special commands entered at the console (see the functional description for the console driver task below). The echo table determines if messages are to be echoed on the console terminal before being routed to their destination:
Initial Echo Table -------------------- Destination Task Echo Flag ---------------- --------- TIR false RPU false 488 false 232 false Console false Unknown false
The source substitution table is used to translate physical message sources to logical message sources:
Initial Source Substitution Table ----------------------------------- Actual Source Logical Source ------------- -------------- TIR TIR RPU RPU 488 488 232 232 Console Console Unknown Console
The destination mapping table is used to translate logical destinations to physical destinations:
Initial Destination Mapping Table ----------------------------------- Logical Destination Physical Destination ------------------- -------------------- TIR TIR RPU Null 488 488 232 232 Console Console Unknown TIR
The first message received by the RPU interface task after reboot determines which interface corresponds to the remote processing unit. The RPU interface task takes the message source XXX and sets up source substitution "XXX->RPU" (replacing "XXX->XXX") and destination mapping "RPU->XXX" (replacing "RPU->Null").
Semaphore CONSOLE_EXCHANGE - Set to indicate that an event has occurred to which the console driver task must respond. RPU_EXCHANGE - Set to indicate that an event has occurred to which the RPU interface task must respond. TIR_EXCHANGE - Set to indicate that an event has occurred to which the test rack job initialization task or the main applications task must respond. 232_EXCHANGE - Set to indicate that an event has occurred to which the RS-232C driver task must respond. 488_EXCHANGE - Set to indicate that an event has occurred to which the IEEE-488 driver task must respond. Mailbox RPU_MESSAGE - Input message mailbox for the RPU interface task. CONSOLE_MESSAGE - Input message mailbox for the console driver task. TIR_MESSAGE - Input message mailbox for either the test rack job initialization task or the main applications task. 232_MESSAGE - Input message mailbox for the RS-232C driver task. 488_MESSAGE - Input message mailbox for the IEEE-488 driver task. Common ECHO_TABLE - Echo table. SOURCE_SUBSTITUTION - Source substitution table. DESTINATION_MAPPING - Destination mapping table. BEGIN RPU_Interface_Task Create and catalog the RPU_EXCHANGE semaphore with initial value of 0 ; Create and catalog the RPU_MESSAGE mailbox ; Lookup the TIR_EXCHANGE semaphore ; Lookup the TIR_MESSAGE mailbox ; Create the IEEE-488 driver task ; Wait on the RPU_EXCHANGE semaphore for subtask activation ; Lookup the 488_EXCHANGE semaphore ; Lookup the 488_MESSAGE mailbox ; Create the RS-232C driver task ; Wait on the RPU_EXCHANGE semaphore for subtask activation ; Lookup the 232_EXCHANGE semaphore ; Lookup the 232_MESSAGE mailbox ; Create the console driver task ; Wait on the RPU_EXCHANGE semaphore for subtask activation ; Lookup the CONSOLE_EXCHANGE semaphore ; Lookup the CONSOLE_MESSAGE mailbox ; Signal the TIR_EXCHANGE semaphore to indicate task activation ; DO forever Read message from the RPU_MESSAGE mailbox ; Lookup the logical source in the Source Substitution Table ; Lookup the physical destination in the Destination Mapping Table ; IF messages to logical destination are to be echoed AND physical source is not console or unknown AND message flag not set THEN Set message flag ; Send message to the CONSOLE_MESSAGE mailbox ; Signal CONSOLE_EXCHANGE semaphore ELSE Substitute logical source for physical source in the message ; CASE OF physical destination IS NUL: IF delete function modifier THEN Delete message text segment ; ENDIF ; Delete message packet segment TIR: Send message to TIR_MESSAGE mailbox ; Signal TIR_EXCHANGE semaphore 488: Send message to 488_MESSAGE mailbox ; Signal 488_EXCHANGE semaphore 232: Send message to 232_MESSAGE mailbox ; Signal 232_EXCHANGE semaphore CON: Send message to CONSOLE_MESSAGE mailbox ; Signal CONSOLE_EXCHANGE semaphore ELSE Error ENDCASE ENDIF /* If messages are to be echoed. */ ENDDO /* Forever. */ END RPU_Interface_Task.
The IEEE-488 driver task controls input from and output to the IEEE-488 bus. Output mailbox messages received by the IEEE-488 driver task specify data that is to be output on the IEEE-488 bus. Input from the IEEE-488 bus is buffered; when a complete record has been assembled, the data is transferred to a dynamically allocated memory segment and an input mailbox message is sent to the RPU interface task. The physical source for input mailbox messages is the driver task itself (488); the logical destination is the test rack download or main applications task (TIR). The RPU interface task determines the logical source (i.e., when the IEEE-488 bus is the source of RPU messages) and physical destination for the messages.
The driver task is the asynchronous source of the following types of messages:
Message function: INPUT/DELETE Message text : input data
Message function: SPECIAL/DELETE Message text : "SPC XXYY"
Requests sent to the IEEE-488 driver task are queued to the IEEE-488 interrupt service task for processing when the interface is idle. The following functions can be requested when the test rack computer acts as the IEEE-488 bus controller:
Message function: OUTPUT { /DELETE } Message text : output data
Message function: SPECIAL { /DELETE } Message text : "TLK XX"
Message function: SPECIAL { /DELETE } Message text : "LIS XX"
Message function: SPECIAL { /DELETE } Message text : "SPC"
Message function: SPECIAL { /DELETE } Message text : "IFC"
Message function: SPECIAL { /DELETE } Message text : "DC"
When the test rack computer acts as an IEEE-488 talker/listener, the available functions are as follows:
Message function: OUTPUT { /DELETE } Message text : output data
Message function: SPECIAL { /DELETE } Message text : "SRQ YY"
Message function: SPECIAL { /DELETE } Message text : "SYC"
SRQ request codes include:
Semaphore MEMORY$WAIT - Implements round-robin scheduling of tasks attempting to allocate memory segments. REBOOT - Set to inform the user job initialization task that re-initialization is to take place. RPU_EXCHANGE - Set to indicate that an event has occurred to which the RPU interface task must respond. 488_EXCHANGE - Set to indicate that an event has occurred to which the IEEE-488 driver task must respond. Mailbox RPU_MESSAGE - Input message mailbox for the RPU interface task. 488_MESSAGE - Input message mailbox for the IEEE-488 driver task. Common IEEE_488_COMPLETION_QUEUE - Functions completed on the IEEE-488 bus. IEEE_488_REQUEST_QUEUE - Functions requested on the IEEE-488 bus. Local INPUT_LIST - Temporary list of completed reads. BEGIN IEEE_488_Driver_Task Create and catalog the 488_EXCHANGE semaphore with initial value of 0 ; Create and catalog the 488_MESSAGE mailbox ; Lookup the REBOOT semaphore ; Lookup the RPU_EXCHANGE semaphore ; Lookup the RPU_MESSAGE mailbox ; Create the IEEE-488 interrupt service task ; Wait on the 488_EXCHANGE semaphore for subtask activation ; Signal the RPU_EXCHANGE semaphore to indicate task activation ; DO forever Wait on the 488_EXCHANGE semaphore ; /* Check for incoming requests from the RPU interface task. */ DO WHILE more messages in 488_MESSAGE mailbox Read the next message from the 488_MESSAGE mailbox ; IF output request THEN Add (WRITE$488, message packet) to the request queue ELSEIF special function request THEN IF message text is "TLK" THEN Add (TALK$488, address) to the request queue ELSEIF message text is "LIS" THEN Add (LISTEN$488, address) to the request queue ELSEIF message text is "SPC" THEN Add (SPC$488) to the request queue ELSEIF message text is "IFC" THEN Add (ASSERT$IFC, listener, address) to the request queue ELSEIF message text is "DC" THEN Add (ASSERT$DC, listener, address) to the request queue ELSEIF message text is "SRQ" THEN Add (ASSERT$SRQ, status byte) to the request queue ELSEIF message text is "SYC" THEN Add (SYSTEM$CONTROLLER) to the request queue ENDIF ; IF message text segment is to be deleted THEN Delete the message text segment ENDIF ; Delete the mailbox message packet ENDIF ; IF request queue was empty THEN Issue software interrupt to the IEEE-488 interrupt service task ENDIF ENDDO ; /* For each mailbox message. */ /* Check for completed operations. Delay handling input operations (which require memory segments) until after any possible memory deallocation has taken place. */ DO WHILE completion queue is not empty Get next entry from the completion queue ; IF READ$488 completed THEN Get the last byte pointer from the completion queue ; Add (READ$488, last byte pointer) to the input list ELSEIF SPC$488 completed THEN Get the device address and status from the completion queue ; Add (SPC$488, device address, status) to the input list ELSEIF WRITE$488 completed THEN Get mailbox message packet from the completion queue ; IF message text segment is to be deleted THEN Delete the message text segment ENDIF ; Delete the mailbox message packet ENDIF ENDDO ; /* For each completed operation. */ /* Check for completed input operations. */ DO WHILE input list is not empty Get next entry from the input list ; IF READ$488 completed THEN Get last byte pointer from the input list ; Determine length of input data record ; Allocate a memory segment of that length ; Move data record from input queue to memory segment ; Allocate a mailbox message packet ; Message source = "488" ; Message destination = "TIR" ; Message function = "INPUT/DELETE" ; Message length = input data length ; Message location = address of input data segment ; Send the message to the RPU_MESSAGE mailbox ELSEIF SPC$488 completed THEN Get device address from the input list ; Get device status from the input list ; Allocate a message text segment ; Message text = "SPC device status" ; Allocate a mailbox message packet ; Message source = "488" ; Message destination = "TIR" ; Message function = "SPECIAL/DELETE" ; Message location = address of message text ; Send the message to the RPU_MESSAGE mailbox ENDIF ENDDO /* For each input completed. */ ENDDO /* Forever. */ END IEEE_488_Driver_Task.
The IEEE-488 interrupt service task and its associated interrupt handler respond to interrupts generated by the iSBX 488 GPIB Multimodule board. Interrupts are initially received by the interrupt handler. Byte In (BI) and Byte Out (BO) interrupts are processed directly by the interrupt handler. For the other interrupts, the handler adds the interrupt to an event queue and signals the interrupt service task. The interrupt service task processes the interrupt as necessary. If an operation has been completed (i.e., end of input or output complete), then the operation is queued to the driver task for final processing. After any operation completes (indicating that the interface is now idle), the interrupt service task initiates the processing of requests queued to it by the driver task.
Semaphore 488_EXCHANGE - Set to indicate that an event has occurred to which the IEEE-488 driver task must respond. Common IEEE_488_COMPLETION_QUEUE - Functions completed on the IEEE-488 bus. IEEE_488_REQUEST_QUEUE - Functions requested on the IEEE-488 bus. Common IEEE_488_EVENT_QUEUE - Interrupts that have occurred. IEEE_488_INPUT_QUEUE - Data input from the IEEE-488 bus. IEEE_488_OUTPUT_BUFFER - Current output buffer. BEGIN IEEE_488_Interrupt_Service_Task Lookup the 488_EXCHANGE semaphore ; Configure the iSBX 488 Multimodule interface board as a talker/listener ; Declare the IEEE-488 interrupt handler and associate this task with it ; Signal the 488_EXCHANGE semaphore to indicate task activation ; DO forever Wait on an IEEE-488 interface interrupt ; DO WHILE event queue is not empty Get next entry from the event queue ; IF event is END interrupt THEN Add (READ$488, input queue rear) to the completion queue ; Signal the 488_EXCHANGE semaphore ELSEIF event is output completion THEN Add (WRITE$488, message packet) to the completion queue ; Signal the 488_EXCHANGE semaphore ELSEIF event is Serial Poll Complete interrupt THEN /* SRQ acknowledged. */ ELSEIF event is SRQ THEN Conduct a serial poll ; DO for each device that responded Add (SPC$488, device address, status) to the completion queue ENDDO ; Signal the 488_EXCHANGE semaphore ELSEIF event is Interface or Device Clear interrupt THEN Signal the REBOOT semaphore ; Delete this job ELSEIF no event THEN /* Used by the driver task to wake up the interrupt service task. */ ELSE Add (ERROR, event) to the completion queue ; Signal the 488_EXCHANGE semaphore ENDIF ENDDO ; /* For each event. */ DO WHILE request queue is not empty AND no operation is in progress Get next entry from the request queue ; IF WRITE$488 requested THEN Get the message packet from the request queue ; Set up the output buffer parameters for the interrupt handler ELSEIF TALK$488 requested THEN Get the device address from the request queue ; Address the device as a talker ELSEIF LISTEN$488 requested THEN Get the device address from the request queue ; Address the device as a listener ELSEIF SPC$488 requested THEN Conduct a serial poll ; DO for each device that responded Add (SPC$488, device, status) to the completion queue ENDDO ; Signal the 488_EXCHANGE semaphore ELSEIF ASSERT$IFC requested THEN Assert Interface Clear on the bus ELSEIF ASSERT$DC requested THEN Assert Device Clear on the bus ELSEIF ASSERT$SRQ requested THEN Assert SRQ on the bus ELSEIF SYSTEM$CONTROLLER requested THEN Configure the IEEE-488 interface as the system controller ENDIF ENDDO /* Process requests. */ ENDDO /* For each interrupt. */ END IEEE_488_Interrupt_Service_Task.
The IEEE-488 interrupt handler is invoked by the operating system to handle interrupts generated by the iSBX 488 GPIB Multimodule board. The interrupt handler is declared by the IEEE-488 interrupt service task. The handler directly handles Byte In and Byte Out interrupts; the other interrupts are passed on to the interrupt service task for processing:
Common IEEE_488_EVENT_QUEUE - Interrupts that have occurred. IEEE_488_INPUT_QUEUE - Data input from the IEEE-488 bus. IEEE_488_OUTPUT_BUFFER - Current output buffer. BEGIN IEEE_488_Interrupt_Handler DO for each event that occurred IF event is a Byte Out interrupt THEN IF more bytes to be output THEN IF last byte in output buffer THEN Assert EOI on next byte output ENDIF ; Output the next byte in the output buffer ENDIF ; IF output buffer exhausted THEN Add the interrupt to the event queue ; Signal the IEEE-488 interrupt service task ENDIF ELSEIF event is a Byte In interrupt THEN Input the byte and add it to the input queue ELSEIF event is an Interface or Device Clear interrupt THEN Assert INIT on the Multibus ; Add the interrupt to the event queue ; Signal the IEEE-488 interrupt service task ELSE Add the interrupt to the event queue ; Signal the IEEE-488 interrupt service task ENDIF ENDDO ; /* For each event. */ IF no event detected THEN /* Software interrupt from the driver task? */ Add null to the event queue ; Signal the IEEE-488 interrupt service task ENDIF END IEEE_488_Interrupt_Handler.
The RS-232C driver task controls input from and output to the RS-232C serial link. Output mailbox messages received by the RS-232C driver task specify data that is to be output over the RS-232C serial link. Input from the RS-232C interface is buffered; when a complete record has been assembled, the data is transferred to a dynamically allocated memory segment and an input mailbox message is sent to the RPU interface task. The physical source for input mailbox messages is the driver task itself (232); the logical destination is the test rack download or main applications task (TIR). The RPU interface task determines the logical source (i.e., when the RS-232C serial link is the source of RPU messages) and physical destination for the messages.
The driver task is the asynchronous source of the following message type:
Message function: INPUT/DELETE Message text : input data
Requests sent to the RS-232C driver task are queued to the RS-232C interrupt service task for processing when the interface is idle. The following function is available:
Message function: OUTPUT { /DELETE } Message text : output data
Semaphore MEMORY$WAIT - Implements round-robin scheduling of tasks attempting to allocate memory segments. REBOOT - Set to inform the user job initialization task that re-initialization is to take place. RPU_EXCHANGE - Set to indicate that an event has occurred to which the RPU interface task must respond. 232_EXCHANGE - Set to indicate that an event has occurred to which the RS-232C driver task must respond. Mailbox RPU_MESSAGE - Input message mailbox for the RPU interface task. 232_MESSAGE - Input message mailbox for the RS-232C driver task. Common RS_232C_COMPLETION_QUEUE - Functions completed on the RS-232C interface. RS_232C_REQUEST_QUEUE - Functions requested for the RS-232C interface. Local INPUT_LIST - Temporary list of completed reads. BEGIN RS_232C_Driver_Task Create and catalog the 232_EXCHANGE semaphore with initial value of 0 ; Create and catalog the 232_MESSAGE mailbox ; Lookup the REBOOT semaphore ; Lookup the RPU_EXCHANGE semaphore ; Lookup the RPU_MESSAGE mailbox ; Create the RS-232C interrupt service task ; Wait on the 232_EXCHANGE semaphore for subtask activation ; Signal the RPU_EXCHANGE semaphore to indicate task activation ; DO forever Wait on the 232_EXCHANGE semaphore ; /* Check for incoming requests from the RPU interface task. */ DO WHILE more messages in 232_MESSAGE mailbox Read the next message from the 232_MESSAGE mailbox ; Add (WRITE$232, message packet) to the request queue ; IF request queue was empty THEN Issue software interrupt to the RS-232C interrupt service task ENDIF ENDDO ; /* For each mailbox message. */ /* Check for completed operations. Delay handling input operations (which require memory segments) until after any possible memory deallocation has taken place. */ DO WHILE completion queue is not empty Get next entry from the completion queue ; IF READ$232 completed THEN Get the last byte pointer from the completion queue ; Add (READ$232, last byte pointer) to the input list ELSE Get mailbox message packet from the completion queue ; IF message text segment is to be deleted THEN Delete the message text segment ENDIF ; Delete the mailbox message packet ENDIF ENDDO ; /* For each completed operation. */ /* Check for completed input operations. */ DO WHILE input list is not empty Get next entry from the input list ; Get last byte pointer from the input list ; Determine length of input data record ; Allocate a memory segment of that length ; Move data record from input queue to memory segment ; Allocate a mailbox message packet ; Message source = "232" ; Message destination = "TIR" ; Message function = "INPUT/DELETE" ; Message length = input data length ; Message location = address of input data segment ; Send the message to the RPU_MESSAGE mailbox ENDDO /* For each input completed. */ ENDDO /* Forever. */ END RS_232C_Driver_Task.
The RS-232C interrupt service task and its associated interrupt handler respond to interrupts generated by the 8274 MPSC channel assigned to the RS-232C serial link. Interrupts are initially received by the interrupt handler. Receive Character Available (RCA) and Transmit Buffer Empty (TBE) interrupts are processed directly by the handler. For the other interrupts, the handler adds the interrupt to an event queue and signals the interrupt service task. The interrupt service task processes the interrupt as necessary. If an operation has been completed (i.e., end of input or output complete), then the operation is queued to the driver task for final processing. After any operation completes (indicating that the interface is now idle), the interrupt service task initiates the processing of requests queued to it by the driver task. The following events are signalled to the interrupt service task by the interrupt handler:
Semaphore 232_EXCHANGE - Set to indicate that an event has occurred to which the RS-232C driver task must respond. Common RS_232C_COMPLETION_QUEUE - Functions completed on the RS-232C interface. RS_232C_REQUEST_QUEUE - Functions requested for the RS-232C interface. Common RS_232_EVENT_QUEUE - Interrupts that have occurred. RS_232_INPUT_QUEUE - Data input from the RS-232C interface. RS_232_OUTPUT_BUFFER - Current output buffer. BEGIN RS_232C_Interrupt_Service_Task Lookup the 232_EXCHANGE semaphore ; Configure channel B of the 8274 MPSC RS-232C interface ; Declare the RS-232C interrupt handler and associate this task with it ; Signal the 232_EXCHANGE semaphore to indicate task activation ; DO forever Wait on an RS-232C interface interrupt ; DO WHILE event queue is not empty Get next entry from the event queue ; IF event is input completion THEN Add (READ$232, input queue rear) to the completion queue ; Signal the 232_EXCHANGE semaphore ELSEIF event is output completion THEN Add (WRITE$232, message packet) to the completion queue ; Signal the 232_EXCHANGE semaphore ELSEIF no event THEN /* Used by the driver task to wake up the interrupt service task. */ ELSE Add (ERROR, event) to the completion queue ; Signal the 232_EXCHANGE semaphore ENDIF ENDDO ; /* For each event. */ DO WHILE request queue is not empty AND no operation is in progress Get next entry from the request queue ; IF WRITE$232 requested THEN Get the message packet from the request queue ; Set up the output buffer parameters for the interrupt handler ENDIF ENDDO /* Process requests. */ ENDDO /* For each interrupt. */ END RS_232C_Interrupt_Service_Task.
The RS-232C interrupt handler is invoked by the operating system to handle interrupts generated by the 8274 MPSC RS-232C interface. The interrupt handler is declared by the RS-232C interrupt service task and processes the following interrupts:
Data is input until a non-printing ASCII character (i.e., control characters) is received, at which point the interrupt handler signals the interrupt service task. Data is output until the output buffer is exhausted, at which point the interrupt service task is signalled.
Common RS_232_EVENT_QUEUE - Interrupts that have occurred. RS_232_INPUT_QUEUE - Data input from the RS-232C interface. RS_232_OUTPUT_BUFFER - Current output buffer. BEGIN RS_232C_Interrupt_Handler DO for each event that occurred IF Receive Character Available THEN Input the byte and add it to the input queue ; IF new byte is a non-printable ASCII character THEN Add the interrupt to the event queue ; Signal the RS-232C interrupt service task ENDIF ELSEIF Transmit Buffer Empty THEN IF more bytes to be output THEN Output the next byte in the output buffer ENDIF ; IF output buffer exhausted THEN Add the interrupt to the event queue ; Signal the RS-232C interrupt service task ENDIF ELSE Add the interrupt to the event queue ; Signal the RS-232C interrupt service task ENDIF ENDDO ; /* For each event. */ IF no event detected THEN /* Software interrupt from the driver task? */ Add null to the event queue ; Signal the RS-232C interrupt service task ENDIF END RS_232C_Interrupt_Handler.
The console driver task controls input from and output to the console terminal. Output mailbox messages received by the console driver task specify text that is to be displayed on the console screen. Input from the console keyboard is buffered; when a complete line has been assembled, the text is transferred to a dynamically allocated memory segment and an input mailbox message is sent to the RPU interface task. The physical source and logical destination for input mailbox messages are both unknown (UNK); the RPU interface task determines the logical source and physical destination for the messages, thereby allowing the console to simulate any of the other interfaces.
A number of special commands can be entered at the console terminal to modify the source/destination translation tables or to simulate different interfaces. Normally, the user is presented with this prompt:
XXX->YYY?
where source substitution "UNK->XXX" and destination mapping "UNK->YYY" are the current definitions. The user can then enter the text of a message to be sent to the destination task. The first character of the line entered specifies the function type of the message ("I" for INPUT, "O" for OUTPUT, and "S" for SPECIAL):
Message function: INPUT/DELETE Message text : input data
Message function: OUTPUT/DELETE Message text : output data
Message function: SPECIAL/DELETE Message text : special text
Hitting the escape key elicits the following prompt:
Universal?
The user can then enter one of the following commands:
- DEBUG
- Enter the system debugger.
- ECHO {ON/OFF} {NUL/TIR/RPU/488/232}
- Control echoing of messages with the specified logical destination.
- REDIRECT {TIR/RPU/488/232/CON} TO {NUL/TIR/RPU/488/232/CON}
- Redirect messages with the specified logical destination to the specified physical destination. For example, "REDIRECT 488 TO CON" redirects output for the IEEE-488 bus to the console (note that this is not the same as ECHO). "REDIRECT XXX TO NUL" causes messages with destination XXX to be discarded.
- RESET
- The hardware is reset and the applications firmware is re-downloaded.
- RESTART
- The applications firmware is restarted (the firmware is not downloaded again).
- SEND {TIR/RPU/488/232/CON} TO {NUL/TIR/RPU/488/232/CON}
- Specify the logical source and physical destination for messages originating at the console. For example, "SEND RPU TO TIR" allows the user to enter RPU messages at the console and send them to the applications firmware.
- SOURCE {TIR/RPU/488/232/CON} AS {TIR/RPU/488/232/CON}
- Substitute the specified logical source (second argument) for the the specified physical source (first argument) in messages from the physical source. For example, "SOURCE 232 AS RPU" lets the RS-232C serial link act as a source of RPU messages.
- STATUS
- Displays the status of the I/O network; i.e., the echo, source substitution, and destination mapping tables.
Requests sent to the console driver task are queued to the console interrupt service task for processing when the interface is idle. Since the console can simulate any of several destinations, the response to any request is simply to display the request's source, destination, function type, and message text on the console (i.e., the console can't perform IEEE-488 functions, etc.). The format of the display is as follows:
SRC->DST[F]: message text
The function types include:
Message function: INPUT { /DELETE } Message text : input data
Message function: OUTPUT { /DELETE } Message text : output data
Message function: SPECIAL { /DELETE } Message text : output data
Semaphore MEMORY$WAIT - Implements round-robin scheduling of tasks attempting to allocate memory segments. REBOOT - Set to inform the user job initialization task that re-initialization is to take place. RPU_EXCHANGE - Set to indicate that an event has occurred to which the RPU interface task must respond. CONSOLE_EXCHANGE - Set to indicate that an event has occurred to which the console driver task must respond. Mailbox RPU_MESSAGE - Input message mailbox for the RPU interface task. CONSOLE_MESSAGE - Input message mailbox for the console driver task. Common CONSOLE_COMPLETION_QUEUE - Functions completed on the console. CONSOLE_REQUEST_QUEUE - Functions requested for the console. Local INPUT_LIST - Temporary list of completed reads. BEGIN Console_Driver_Task Create and catalog the CONSOLE_EXCHANGE semaphore with initial value of 0 ; Create and catalog the CONSOLE_MESSAGE mailbox ; Lookup the REBOOT semaphore ; Lookup the RPU_EXCHANGE semaphore ; Lookup the RPU_MESSAGE mailbox ; Create the console interrupt service task ; Wait on the CONSOLE_EXCHANGE semaphore for subtask activation ; Signal the RPU_EXCHANGE semaphore to indicate task activation ; DO forever Wait on the CONSOLE_EXCHANGE semaphore ; /* Check for incoming requests from the RPU interface task. */ DO WHILE more messages in CONSOLE_MESSAGE mailbox Read the next message from the CONSOLE_MESSAGE mailbox ; Add (WRITE$CONSOLE, message packet) to the request queue ; IF request queue was empty THEN Issue software interrupt to the console interrupt service task ENDIF ENDDO ; /* For each mailbox message. */ /* Check for completed operations. Delay handling input operations (which require memory segments) until after any possible memory deallocation has taken place. */ DO WHILE completion queue is not empty Get next entry from the completion queue ; IF READ$CONSOLE completed THEN Get the last byte pointer from the completion queue ; Add (READ$CONSOLE, last byte pointer) to the input list ELSE Get mailbox message packet from the completion queue ; IF message text segment is to be deleted THEN Delete the message text segment ENDIF ; Delete the mailbox message packet ENDIF ENDDO ; /* For each completed operation. */ /* Check for completed input operations. */ DO WHILE input list is not empty Get next entry from the input list ; Get last byte pointer from the input list ; Determine length of input data record ; Allocate a memory segment of that length ; Get first character of data record indicating function type ; Move rest of data record from input queue to memory segment ; IF function character is escape THEN Get the command and arguments from the input line ; CASE OF command IS DEBUG: Software interrupt into the system debugger ECHO: IF arg1 is OFF THEN Turn off echo for arg2 ELSEIF arg1 is ON THEN Turn on echo for arg2 ENDIF REDIRECT: Map destination arg1 to arg2 RESET: Signal the REBOOT semaphore RESTART: Signal the DOWNLOAD semaphore ; Signal the REBOOT semaphore SEND: Substitute source arg1 for UNK ; Map destination UNK to arg2 SOURCE: Substitute source arg2 for arg1 STATUS: Display the echo table ; Display the source substitution table ; Display the destination mapping table ELSE Ignore ENDCASE ; Delete the input memory segment ELSE Allocate a mailbox message packet ; Message source = "UNK" ; Message destination = "UNK" ; CASE OF function character IS "I": Message function = "INPUT/DELETE" "O": Message function = "OUTPUT/DELETE" "S": Message function = "SPECIAL/DELETE" ELSE Message function = "OUTPUT/DELETE" ENDCASE ; Message length = input data length - 1 ; Message location = address of input data segment ; Send the message to the RPU_MESSAGE mailbox ENDIF ENDDO /* For each input completed. */ ENDDO /* Forever. */ END Console_Driver_Task.
The console interrupt service task and its associated interrupt handler respond to interrupts generated by the 8274 MPSC channel assigned to the console terminal. Interrupts are initially received by the interrupt handler. Receive Character Available (RCA) and Transmit Buffer Empty (TBE) interrupts are processed directly by the handler. For the other interrupts, the handler adds the interrupt to an event queue and signals the interrupt service task. The interrupt service task processes the interrupt as necessary. If an operation has been completed (i.e., end of input or output complete), then the operation is queued to the driver task for final processing. After any operation completes (indicating that the interface is now idle), the interrupt service task initiates the processing of requests queued to it by the driver task. The following events are signalled to the interrupt service task by the interrupt handler:
Semaphore CONSOLE_EXCHANGE - Set to indicate that an event has occurred to which the console driver task must respond. Common CONSOLE_COMPLETION_QUEUE - Functions completed on the console. CONSOLE_REQUEST_QUEUE - Functions requested on the console. Common CONSOLE_COMPLETION_QUEUE - Functions completed on the console. CONSOLE_REQUEST_QUEUE - Functions requested for the console. Common CONSOLE_EVENT_QUEUE - Interrupts that have occurred. CONSOLE_INPUT_QUEUE - Data input from the console. CONSOLE_OUTPUT_BUFFER - Current output buffer. BEGIN Console_Interrupt_Service_Task Lookup the CONSOLE_EXCHANGE semaphore ; Configure channel B of the 8274 MPSC interface for the console terminal ; Declare the console interrupt handler and associate this task with it ; Signal the CONSOLE_EXCHANGE semaphore to indicate task activation ; DO forever Wait on a console interface interrupt ; DO WHILE event queue is not empty Get next entry from the event queue ; IF event is input completion THEN Add (READ$CONSOLE, input queue rear) to the completion queue ; Signal the CONSOLE_EXCHANGE semaphore ELSEIF event is output completion THEN IF prolog output complete THEN Set up the text output parameters for the interrupt handler ELSEIF text output complete THEN /* Output epilog of carriage return and line feed. */ Set up the epilog output parameters for the interrupt handler ELSEIF epilog output complete THEN Add (WRITE$CONSOLE, message packet) to the completion queue ; Signal the CONSOLE_EXCHANGE semaphore ENDIF ELSEIF no event THEN /* Used by the driver task to wake up the interrupt service task. */ ELSE Add (ERROR, event) to the completion queue ; Signal the CONSOLE_EXCHANGE semaphore ENDIF ENDDO ; /* For each event. */ DO WHILE request queue is not empty AND no operation is in progress Get next entry from the request queue ; Get the message packet from the request queue ; Construct the output prolog ; /* "SRC->DST[F]: " */ Set up the prolog output parameters for the interrupt handler ENDDO ; /* Process requests. */ IF no operation is in progress THEN Construct the input prompt ; /* "SRC->DST? " */ Set up the prompt output parameters for the interrupt handler ENDIF ENDDO /* For each interrupt. */ END Console_Interrupt_Service_Task.
The console interrupt handler is invoked by the operating system to handle interrupts generated by the 8274 MPSC console interface. The interrupt handler is declared by the console interrupt service task and processes the following interrupts:
Data is input until a non-printing ASCII character (i.e., control characters) is received, at which point the interrupt handler signals the interrupt service task. Data is output until the print buffer is exhausted, at which point the interrupt service task is signalled.
Common CONSOLE_EVENT_QUEUE - Interrupts that have occurred. CONSOLE_INPUT_QUEUE - Data input from the console. CONSOLE_OUTPUT_BUFFER - Current output buffer. BEGIN Console_Interrupt_Handler DO for each event that occurred IF Receive Character Available THEN Input the byte and add it to the input queue ; IF new byte is printable ASCII character THEN Inhibit pending Transmit Buffer Empty interrupt ; Poll Transmit Buffer Empty status ; Echo the byte ELSE Add the interrupt to the event queue ; Signal the console interrupt service task ENDIF ELSEIF Transmit Buffer Empty THEN IF more bytes to be output THEN Output the next byte in the output buffer ENDIF ; IF output buffer exhausted THEN Add the interrupt to the event queue ; Signal the console interrupt service task ENDIF ELSE Add the interrupt to the event queue ; Signal the console interrupt service task ENDIF ENDDO ; /* For each event. */ IF no event detected THEN /* Software interrupt from the driver task? */ Add null to the event queue ; Signal the console interrupt service task ENDIF END Console_Interrupt_Handler.