SYSTEM FOR DIVIDING PROCESSING TASKS INTO SIGNAL PROCESSOR AND DECISION-MAKING MICROPROCESSOR INTERFACING

Abstract: Architectures and methods are provided for efficiently dividing a processing task into tasks for a programmable real time signal processor (SPROC) (10) and tasks for a decision-making microprocessor (2120). The SPROC is provided with a non-interrupt structure where data flow is through a multiported central memory. The SPROC is also programmed in an environment which requires nothing more than graphic entry of a block diagram of the user's design. In automatically implementing the block diagram into silicon, the SPROC programming/development environment accounts for and provides software connection and interfaces with a host microprocessor (2120). The programming environment preferably includes: a high-level computer screen entry system which permits choosing, entry, parameterization, and connection of a plurality of functional blocks; a functional block cell library (2015) which provides source code representing the functional blocks; and a signal processor scheduler/compiler (2040) which uses the functional block cell library (2015) and the information entered into the high-level entry system to compile a program and to output source program code for a program memory and source data code for the data memory of the SPROC, as well as a symbol table which provides a memory map which maps SPROC addresses to variable names which the microprocessor (2120) will refer to in separately compiling its program.

Description: "SYSTEM FOR DIVIDING PROCESSING TASKS INTO SIGNAL PROCESSOR AND DECISION-MAKING MICROPROCESSOR INTERFACING" Index of Contents Related Patent Applications Background of the Invention 1. Field of the Invention 1 State of the Art Summary of the Invention Brief Description of the Drawings Detailed Description of the Preferred Embodiments A. The Signal Processor (SPROC) A.1 Functional description of The Parallel Port A.2 Master SPROC Chip Read from Slave SPROC Chip or Peripheral A.3 Master SPROC Chip Write to Slave SPROC Chip or Peripheral A.4 Read from Slave SPROC Chip by an External Controller A.5 Write to Slave SPROC Chip by an External Controller A.6 Data Transfer Modes A.7 Boot Mode A.8 Watchdog Timer A.9 Multiple I/O Lockout A.10 Input/Output Flags and Lines A.11 Parallel Port Registers B. SPROC Development and Software B.l Overview B.1.1 The SPROCcells Function Library B.2 Entering a Diagram B.3 Defining a Filter B.4 Defining a Transfer Function B.5 Converting a Block Diagram B.6 The MakeSDL Module B.7 The Schedule Module B.8 The MakeLoad Module B.9 Loading and Running a Design B.10 Using the Micro Keyword B.l 1 Using a Listing File B.12 Using Subroutines B.13 Using Time Zones B.14 Summary C. SPROC Description Language C.1 Overview of SDL C.2 Compiling SDL Files C.3 Concepts and Definitions C.4 Rules for Creating Asmblocks C.5 Asmblock Structure C.6 SPROC Chip Architecture, Instructions and Registers D. The SPROC Compiler E. The Microprocessor E.1 SPROClink Microprocessor Interface E.2 SMI Components E.3 The Development Process E.4 Input Requirements E.5 Signal Processing Design Considerations E.6 Embedded System Development Considerations E.7 Using the SPROC Configuration File E.8 Using the Symbol Translator E.9 Using the SPROC C Function Library E.10 Accessing SPROC Chip Memory Values F. Low Frequency Impedance Analyzer Example Qairns Abstract of the Disclosure Appendix A - MakeSDL Source Code (pgs. 1-73) Appendix B - Selections from SPROCcells Function Library Source Code (pgs. 1-17 ) Appendix C - Symbol Translator Source Code (pgs. 1-26) Appendix D - MakeLoad Source Code (pgs. 1-21) Appendix E - SPROC Scheduler/Compiler Phantom Block Source Code (pgs. 1-22) Appendix F - Program File yhpduaLspp Generated for Fig. 11 Example (pgs. 1-7) Appendix G - Data File yhpdual.spd Generated for Fig. 11 Example (pgs. 1-27) Appendix H - Symbol File yhpdual.sps Generated for Fig. 11 Example (pgs. 1-11) Appendix I - Boot File hypduaLblk Generated for Fig. 11 Example (pgs. 1-8) Appendix J - Maintestx File Generated to Accompany Fig. 11 Example and for Compilation by Microprocessor (pgs. 1-7) Appendix K - yhpdual.c File Generated by Symbol Translator for Fig. 11 Example (pgs. 1-3) Appendix L - yhpdual.h File Generated by Symbol Translator for Fig. 11 Example (pgs. 1-6) Appendix M - SPROC Scheduler/Compiler Source Code (pgs. 1- 673) SPROC, SPROCbox, SPROCboard, SPROCcells, SPROCdrive, SPROClab, and SPROClink are all trademarks of the assignee hereof. RELATED PATENT APPLICATIONS This is a continuation-in-part of copending Serial No. 07/217,616 filed July 11, 1988 which is hereby incorporated by reference in its entirety herein. This is a continuation-in-part of copending Serial No. 07/474,742 (also PCT/US89/02986) filed July 10, 1989 which is hereby incorporated by reference in its entirety herein. This is a continuation-in-part of copending Serial No. 07/525,977 filed May 18, 1990 which is hereby incorporated by reference in its entirety herein. This is a continuation-in-part of copending Serial No. 07/583,508 filed Sept. 17, 1990 which is hereby incorporated by reference in its entirety herein. This is a continuation-in-part of copending Serial No. 07/663,395 filed March 1, 1991 which is hereby incorporated by reference in its entirety herein. BACKGROUND OF THE INVENTION 1. Field of the Invention The present invention generally relates to prograrnmable real time signal processor devices and methods utilizing such devices. More particularly, the present invention relates to architectures and methods for efficiently dividing a processing task into tasks for a real time signal processor and tasks for a decision-making microprocessor, wherein the real time signal processor is programmable in an environment which accounts for and provides software connection and interfaces with a host microprocessor. 2. State of the Art Digital signal processing has evolved from being an expensive, esoteric science used primarily in military applications such as radar systems, image recognition, and the like, to a high growth technology which is used in consumer products such as digital audio and the compact disk. Single chip digital signal processors (SCDSPs) were introduced in the early 1980's to specifically address these markets. However, SCDSPs are complex to design and use, and have significant performance limitations. In particular, SCDSPs are limited to a frequency spectrum from DC to the low tens of KHz. Moreover, most SCDSPs have other development environment and hardware performance problems which stem from their Von Neuman, microprocessor origins. In an attempt to overcome these limitations, attempts have been made to use parallel processors and math coprocessors. However, these "solutions" have required considerable expertise on the part of the software engineer and have typically yielded minimal gain; particularly in the real-time environment. Generic signal processing based products can be segmented as shown in Figure 1 and described as follows: analog input output (I/O), and A/D and/or D/A conversion; signal conditioning and processing; sample rate decision processing; and logic, decision, and control processing. The analog interface (I/O) typically performs preamplification and anti-alias filtering prior to A D conversion in the input direction, as well as D/A conversion, reconstitution filtering, and power amplification in the output direction. The signal conditioning and processing circuitry conducts precision signal processing functions such as filtering, amplification, rectification, etc., as well as fast Fourier transforms and the like. The sample rate decision circuitry includes window comparators, quantizers, companders, expanders, etc. which make simple logic decisions on each and every sample forwarded to it. Finally, the logic, decision, and control processing circuitry in the mcoming direction uses the signals emerging from the signal conditioning and processing and the sample rate decision processing circuitry, and makes decisions to control external equipment in some useful manner. In order to control the external equipment, in the outgoing direction, the logic, decision, and control processing circuitry generates signals which require further signal processing to drive or interact with some analog device or equipment. Li making decisions, the logic, decision, and control processing circuitry typically utilizes highly data dependent code which runs asynchronously from the signals it utilizes. Examples of such circuitry include speech and image recognition algorithms, disk drive controllers, speech generation algorithms, numerically controlled machine tool controllers, etc. Based on the above break-down of tasks it can be seen that SCDSPs are called upon to do both of what may be termed "signal processing" and "logic processing". Signal processing is typically computationally intensive, requires low latency and low parasitic overhead for real time I/O, must efficiently execute multiple asynchronous deterministic processes, and be controllable. Real time signal processors are typically controllable processors which have very large I/O bandwidths, are required to conduct many millions of computations per second, and can conduct several processing functions in parallel. In contrast to signal processing, logic processing is usually memory intensive (as opposed to computationally intensive), must efficiently handle multiple interrupts particularly in a multiprocessor system), and acts as a controller (as opposed to being controllable). A common type of logic processor is the microprocessor which relies on extensive decision oriented software to conduct its processes. This software is typically written in a high level language such as "C". The code often contains numerous "if...then...else" like constructs which can result in highly variable execution times which are readily dealt with in non- real time applications, but present highly problematical scheduling problems for efficient real time systems. Comparing the signal and logic processing requirements, it is seen that they are far from similar. Nevertheless, depending upon the circumstances, it is common for logic processors to be called upon to do signal processing, and vice versa. Since the microprocessor art is the older and more developed art, it is not surprising that the architectures of many DSPs have broadly borrowed from the architectures of the microprocessors. Thus, DSPs are often constructed as controllers having an interrupt structure. This type of architecture, however, is not properly suited for the primary functions of digital signal processing. SUMMARY OF THE INVENTION It is therefore the primary object of the invention to provide architectures and methods for efficiently dividing a processing task into tasks for a real time signal processor and tasks for a decision-making host microprocessor, wherein the real time signal processor is programmable in an environment which accounts for and provides connection and interfaces with the host microprocessor. It is another object of the invention to provide a programmable, configurable, real time signal processor which is particularly suited to the requirements of signal processing and which conducts deterministic real time signal processing and interfaces with a microprocessor which conducts logic processing. It is a further object of the invention to provide a graphic user interface system for a real time signal processor interfacing with a host microprocessor where the real time signal processor program is compiled separately from the program of the microprocessor but, as part of the compiling procedure provides a microprocessor-related file to the microprocessor which then translates the file and incorporates the translated file into its compilation, and thereby automatically provides for the signal processor - microprocessor interface. Yet another object of the invention is to provide a user interface system incorporating a real time signal processor and a microprocessor which automatically share processing tasks in an efficient manner and which automatically compile and interface to accomplish the desired processing task. In accord with the objects of the invention a development system for the microprocessor- interfacing signal processor is provided. For purposes of clarity and simplicity, the signal processor which interfaces with the microprocessor is referred to hereinafter as a SPROC (a trademark of the assignee hereof). Details of the SPROC are set forth in parent application 07/525,977. The development system (hereinafter referred to as SPROClab - a trademark of the assignee hereof) which is provided to permit a user to simply program and use the SPROC generally includes: a high-level computer screen entry system (graphic user interface) which permits choosing, entry, parameterization, and connection of a plurality of functional blocks; a functional block library which provides source code representing the functional blocks; and a signal processor compiler for incorporating the parameters of the functional blocks as variables into the functional block library code and for compiling the library code as well as other code which accounts for scheduling and functional block connection matters, etc., whereby the signal processor compiler outputs source program code for a program memory of the signal processor (SPROC), source data code for the data memory of the SPROC, and a symbol table which provides a memory map which maps variable names which the microprocessor will refer to in separately compiling its program to SPROC addresses. Besides the symbol table which is used by the microprocessor for interfacing with the SPROC, the SPROClab preferably provides means for generating a boot file which is compatible for storage in the microprocessor and which is provided by the microprocessor to the SPROC in order to boot up the SPROC. In this manner, the microprocessor can act as the host for the SPROC. With the signal processing and logic processing aspects of tasks being divided (with the SPROC handling the signal processing, and the microprocessor handling the logic processing), the compiling of the SPROC and the microprocessor are handled separately. In order to accomplish the separate handling while still providing the graphic entry system, at least two schemes are provided. A first scheme effectively provides graphic entry for the signal processing circuit only. If desired, in the first scheme limited graphic entry for the microprocessor can be used to provide SPROC interfaces with the microprocessor (as shown in Fig. 10). With the first scheme, the user must provide suitable code for the microprocessor separately, and the symbol table generated by the SPROClab compiler is provided together with the code hand-generated by the user for microprocessor compiling. A second scheme permits graphic entry for both the signal processing and logic processing (microprocessor) circuits, and uses any of several methods for distinguishing between the two. Among the methods for distinguishing between which portion of the circuit is intended for signal processing and which for logic processing are: user entry (e.g., defining a block as block.spr or block.mic); hierarchical block entry which is programmed to allow entry of both logic processing and signal processing blocks; and the sample rate of the block (with slow sampling rates being handled by the microprocessor). Of course, if all blocks are predefined (i.e., are contained in a library), the precoded library code divides the code into code intended for the SPROC and code intended for the microprocessor. Regardless, where graphic entry for both signal processing and logic processing is permitted, the graphic entry eventually results in separate automatic compilation for both the SPROC and the microprocessor, with the SPROClab compiler again providing the necessary symbol table for incorporation during compilation of the microprocessor code. Additional objects and advantages of the invention will become apparent to those skilled in the art upon reference to the detailed description taken in conjunction with the provided figures. BRIEF DESCRIPTION OF THE DRAWINGS Figure 1 is a high level block diagram of the SPROC device of the invention, and its connection to an external host or memory; Figure 2 is a timing diagram of the access of the various components and ports of the SPROC to the data RAM of the SPROC; Figures 3a and 3b together comprise a block diagram of the internal processors of the SPROC device of the invention; Figures 4a and 4b are block diagrams of the input and output sides of the data flow manager of the invention; Figure 4c is a representation of a FIFO which is implemented in the multiported data RAM, and which is utilized by the data flow manager of the invention; Figures 5a and 5b are block diagrams of the serial input and serial output ports of the invention; Figure 6 is a simplified block diagram of the host port of the invention; Figure 7 is a block diagram of the access port of the invention; Figure 8 is a block diagram of the probe of the invention; Figure 9 is a simplified diagram illustrating the coupling of a plurality of SPROC devices of the invention into a system acting as the front end to a logic processor, Figure 10 is a flow diagram of the development system of the invention where the SPROC code and microprocessor code are compiled separately. Figure 11 is a block diagram of a low frequency impedance analyzer example entered into a graphic user entry system and programmed onto a SPROC for use in conjunction with a microprocessor; and Figure 12 is a high level flow chart of the compiler utilized in the development system of the invention. DETAJLED DESCRIPTION OF THE PREFERRED EMBODIMENTS A. The Signal Processor (SPROC) A high level block diagram of the preferred SPROC subsystem 10 of the invention is seen in Figure 1. The preferred SPROC 10 preferably includes: a central "multiported" (as broadly understood) data RAM 100 accessed via data RAM bus 125; a multiported program RAM 150 accessed via program RAM bus 155; a plurality of internal processors (GSP) 400 coupled to the data RAM bus 125 and the program RAM bus 155 and which perform general processing functions; a data flow manager (DFM) 600 which is coupled to the data RAM bus 125 and which generally controls the flow of data into and out of the SPROC and relieves the GSPs from dealing with that data flow; a plurality of serial data ports 700 coupled to the DFM 600; a host port 800 coupled to both the data RAM bus 125 and the program RAM bus 155, the host port serving to couple the SPROC via the host bus 165 to either an EPROM 170 in stand-alone mode or to a host processor 180 in host mode; an access port 900 coupled to both the data RAM bus 125 and the program RAM bus 155; a probe 1000 coupled to the data RAM bus 125; and an internal boot ROM 190 with boot ROM bus 157 coupled via switch 192 to a GSP 400, the boot ROM 190 being used to control a master SPROC 10 in start-up mode, as well as to control the GSPs 400 of a SPROC 10 when the GSPs are in break mode; and a flag generating decoder 196 coupled via flag bus 198 to the DFM 600 and the GSPs 400 for flagging the DFM and GSPs when particular addresses of the data RAM 100 are being addressed (as determined by values on the data RAM bus 125). The SPROC 10 of the invention can function in several different modes, some of which are determined by externally set pins (not shown). In particular, the SPROC 10 has a boot mode, an operational mode, and a development mode which includes a "break" mode. In addition, the SPROC may be a master SPROC or a slave SPROC which is either coupled to a master SPROC (see Figure 9) or a host 180 such as a microprocessor. In the boot mode (powering up), where the SPROC 10 is a master, the SPROC 10 is required to program both itself and any other slave SPROCs which might be part of the system. To do that, upon power up, switches 192 and 194 are toggled to connect to the B (boot) nodes. With switches 192 and 194 so set, the boot ROM is coupled to a GSP 400 such as GSP 400a, and the program RAM 150 is coupled to the data RAM bus 125. As boot ROM 190 is coupled to the GSP 400a, the GSP 400a is able to read the boot code in boot ROM 190. The code is arranged to cause the GSP to seize control of the host port 800 and to load information into the SPROC from EPROM 170 via the host port 800. The information contained in EPROM 170 includes the program code for the program RAM 150 (which is sent via data RAM bus 125), configuration information for the DFM 600 and the serial, host, and access ports 700, 800, 900, and parameter information including initialization information for the data RAM 100. This information, which was compiled by the development system of the invention (as discussed in more detail hereinafter) and stored in the EPROM, causes the SPROC to perform the desired functions on data typically received via serial ports 700. In boot mode, after the master SPROC is programmed, the remaining (slave) SPROCs of the system (see Figure 9) are programmed by having the master SPROC 10 read the EPROM 170 and forward the information via the common host bus 165 to the other SPROCs which reside in different address spaces. The slave SPROCs do not require a boot ROM for boot mode purposes, although the boot ROM 190 is also used to control the break mode operation of the SPROC (as described with reference to Figures 4). After initialization is completed, boot mode is exited by the writing of a predetermined value (fOH) to a predetermined memory address (0401H) which causes switch 192 to toggle to node O (operation), and switch 194 to toggle to an open position. Then the SPROC is ready to operate for its intended signal processing purposes. Although slave SPROCs may be programmed in boot mode by a master SPROC, a slave SPROC may also be programmed by a microprocessor host such as host 180 of Figure 1. In slave mode where a host such as host 180 is coupled to the host bus 165, the internal boot ROM 190 is not active. In fact, switches 192 and 194 are set in the operating mode position. In order to program the SPROC, the host 180 preferably utilizes the host bus 165 and sends program data via host port 800, and program RAM bus 155 to the program RAM, and data RAM data via host port 800 and the data RAM bus 125 to the data RAM. Configuration information for the serial ports 700 and data flow manager 600, is sent by the host 180 via host port 800 and the data RAM bus 125 as hereinafter described. As will be described hereinafter with reference to the development system (SPROClab), where a microprocessor is the host for a SPROC, the program, data, and configuration information is typically generated by SPROClab in a microprocessor readable and storable format. In operational mode, serial data flow into and out of the SPROC 10 is primarily through the serial ports 700, while parallel data flows through the host port 800. Serial data which is to be processed is sent into an input port 700 which is coupled to the data flow manager 600, which in turn forwards the data to appropriate locations (buffers) in the data RAM 100. In certain circumstances, described below, the DFM 600 will also write additional information to particular data RAM locations which are monitored by flag generating decoder 196. Decoder 196, in turn, causes the flags to be triggered over trigger or flag bus 198 as described in detail in previously incorporated U.S. Serial No. 07/583,508. Other flags are triggered by pulsing hardware pins (not shown) via lines called "compute lines". The hardware pins are particularly useful in providing external timing information to the GSPs 400 and the DFM 600 of the SPROC. Once the data has been sent to the data RAM 100, and typically after the GSPs 400 have been apprised via the flag bus 198 of the arrival of the information, the GSPs 400 can process the data. The processing of the data is conducted in accord with one or more programs stored in the multiported program RAM 150 which in turn represents the functions, topology, and parameters of a schematic diagram generated by the user of the development system. In processing the data, the GSPs 400 can read from and write to the data RAM 100. However, in order to shield the GSPs from I/O functions which would interrupt and burden the GSPs, the GSPs do not address each other directly, and do not read from or write to the DFM 600 or the input or output serial ports 700. Similarly, the GSPs do not have direct access to the host port 800 or the access port 900. Thus, in order for the processed data to be output from the SPROC 10, the processed data must be sent by the GSP 400 to the data RAM 100. The data in the data RAM is then either read by the DFM 600 and sent out serially via an output port 700, or is sent out over the host bus 165 in a parallel form via the host port 800. The development mode of the SPROC device (which will be discussed in more detail hereinafter with reference to the development system) is used prior to the final programming of the EPROM 170 and is basically utilized in conjunction with a host 180. The development mode permits a user to easily and advantageously develop an integrated circuit signal processor by permitting the user access to the internals of the SPROC device. For example, if during a test operational mode it is desirable to obtain a data "dump" of the registers of the GSPs, the GSPs 400 can be put into break mode by causing a GSP to write to memory address 406H. As a result of writing to that address, a decoder (not shown) causes switch 192 to toggle, and instructions from the break section of the boot ROM 190 are used by the GSP 400 via bus 157. While boot ROM 190 is coupled to the GSP 400 in this manner, the GSP runs a routine which causes each register of the GSP to dump its contents to predetermined locations in the data RAM 100. That data may then be accessed by the user and changed if desired via the access port 900 or host port 800. Then, the break section of boot ROM 190 reloads the data into the GSP, writes to memory address 407H, and another decoder (not shown) causes switch 192 to toggle again such that the program RAM 150 is coupled to GSP 400, and the program continues. Other tools useful in the development mode of the SPROC device are the access port 900 and the probe 1000. The access port permits the user to make changes to the program held in program RAM 150, and/or changes to parameters stored in the program RAM 150 or the data RAM 100 while the SPROC is operating. The probe 1000, which is described in greater detail in previously incorporated U.S. Serial No. 07/663,395 permits the user to see internal signals generated by the SPROC in analog or digital form by monitoring the values of data written to any particular data RAM location. By using the access port 900 and the probe 1000 together, the effect of a change of a parameter value entered via the access port 900 may be immediately monitored by probe 1000. Before turning to the details of each of the blocks which comprise Figure 1, it should be appreciated that central to functioning of the SPROC is a multiported data RAM 100 and a multiported program RAM 150. As aforementioned, the RAMs may either be multiported by time division multiplexing a single access to the RAMs (as seen by the solid lines of Figure 1) or by providing true multiported RAMs (as suggested by the dashed lines of Figure 1). As indicated in Figure 2, in the preferred embodiment hereof, access to the program RAM 150 by the GSPs 400 and the host port 800 and access port 900 is via time division multiplexing of a single input. Similarly, access to the data RAM 100 by the GSPs 400, the DFM 600, the host port 800, the access port 900, and the probe 1000 is also via time division multiplexing of a single input. As seen in Figure 2, in the preferred embodiment of the invention, there are five principle time slots of the basic 50MHz SPROC clock 147 (shown in Fig. 1): one for each GSP; and one shared by all of the other blocks of the SPROC. Each GSP 400 is able to read from the program RAM (p-rd) once over five clock cycles, effectively providing each GSP with a 10MHz access to the program RAM 150. In the fifth clock cycle, the host is given preferred access to either read from or write to the program RAM. If the host does not need to read or write to the program RAM, the access port is given access. Alternatively, the host and access ports can be given 50/50 access to the fifth time slot by additional time division multiplexing. In the boot mode, only one GSP of the SPROC (e.g. GSP 400a) accesses the boot ROM 190. Because boot mode is used to program the program RAM 150 with program data from EPROM 170,, the program RAM bus 155 must be used by the GSP 400a for writing to the program RAM 150 (via data RAM bus 125 and switch 194). Thus, a program RAM write (p-wr) is provided as shown in Figure 2 to allow for this situation (as previously discussed with reference to Figure 1). The data RAM 100 is similarly multiported via time division multiplexing. As indicated in Figure 2, each GSP 400 is given a single time slot to either read or write from the data RAM 100. The fifth time slot (time slot 2) is subdivided in time as follows: 50% for the host interface; and the remaining fifty percent equally divided among the access port 900, each of eight sections of the DFM 600 relating to eight serial ports 700, and the probe 1000. The RAMs 100 and 150 of the invention are preferably separate RAM devices and do not share memory space. For example, the program RAM 150 is preferably a IK by 24 bit RAM which is assigned address locations 0000 to 03ff Hex. The data RAM 100, on the other hand is preferably a 3K by 24 bit data RAM with primary data RAM space of 2K assigned address 0800 to Offf Hex, and auxiliary register based space of IK assigned addresses 0400 to 07ff Hex. Of the primary data RAM addresses, addresses 0800 through 0813 Hex relate to the trigger bus flags as is discussed hereinafter, while addresses 0814 through Offf are used as data buffers, scratch pad locations, etc. Of the auxiliary space, certain addresses are used as follows: 0401H Exit boot mode (write fOH) (generate GSP hard reset) 0405H Serial port reset (write) 0406H Global break entry (write) (generate GSP soft reset) 0407H Global break exit (write) (generate GSP soft reset) 0408H GSP1 break entry (write) (generate GSP soft reset) 0409H GSP2 break entry (write) (generate GSP soft reset) 040aH GSP3 break entry (write) (generate GSP soft reset) 040bH GSP4 break entry (write) (generate GSP soft reset) 040cH GSP1 break exit (write) (generate GSP soft reset) 040dH GSP2 break exit (write) (generate GSP soft reset) 040eH GSP3 break exit (write) (generate GSP soft reset) 040fB GSP4 break exit (write) (generate GSP soft reset) 0410H Serial Port 1 internal clock rate select (write 00 = CK/2048) (write 01 = CK/1024) (write 02 = CK/512) (write 03 = CK/256) (write 04 = CK/128) (write 05 = CK/64) (write 06 = CK/32) (write 07 = CK/16) where CK is the SPROC clock (50 MHz) 0411H Serial Port 2 internal clock rate select 0412H Serial Port 3 internal clock rate select 0413H Serial Port 4 internal clock rate select 0414H Serial Port 5 internal clock rate select 0415H Serial Port 6 internal clock rate select 0416H Serial Port 7 internal clock rate select 0417H Serial Port 8 internal clock rate select 0440H to 0447H Serial Port 1 (pradd = 0800H) 0448Hto 044fH Serial Port 2 (pradd = 0801H) 0450Hto 0457H Serial Port 3 (pradd = 0802H) 0458Hto 045fH Serial Port 4 (pradd = 0803H) 0460Hto 0467H Serial Port 5 (pradd = 0804H) 0468Hto 046fH Serial Port 6 (pradd = 0805H) 0470H to 0477H Serial Port 7 (pradd = 0806H) 0478Hto 047fH Serial Port 8 (pradd - 0807H) 0480Hto 0487H DAC (probe) input port (pradd = 0808H) 0488Hto 048fH DAC (probe) serial output port 04fcHto 04ffH Host interface registers Memory locations 1000 to ffff Hex refers to external address space (e.g. slave SPROCs, other devices, or memory). Of the auxiliary memory locations in the data RAM 100, it should be noted that each GSP is given a break entry and break exit data address. While the embodiment of Figure 1 causes bus 155 to be connected to the boot break ROM 190 when a break is implemented such that all GSPs must break together, different circuitry would allow for individual GSP breaks. The eight twenty-four bit locations provided for each serial port are used to configure the serial ports as well as the DFM section associated with each serial port as hereinafter described. Similarly, the eight words of memory assigned the input and output ports of the probe are used to configure the probe, while the eight words of memory assigned the host port are used to configure the host port as described hereinafter. Further, with regard to the memory locations, it is noted that when information is written to any of the serial port locations indicated, another address (pradd), which turns out to be a trigger flag address is generated by the DFM 600 (as discussed in more detail hereinafter) and written to the data RAM bus 125. The writing of particular addresses to the data RAM bus 125 is monitored by decoder 196 which is discussed in more detail in Ser. No. 07/583,508. Turning to Figures 3a and 3b, a block diagram of the preferred general signal processor (GSP) 400 of the invention is seen. The GSP is coupled to a program RAM 150 via program RAM bus 155. Because the program RAM 150 is preferably shared by a plurality of GSPs 400, access to the program RAM bus is time division multiplexed as indicated in Figure 2. The program RAM bus 155 is comprised of a data bus of width twenty-four bits, and an address bus of ten bit width where a IK program RAM is utilized. Of course, if a larger program RAM is desired, additional bits are required to address the same, and the program RAM bus would be wider. As indicated in Figures 3a and 3b, the GSP 400 writes to the address section of the program RAM bus to indicate which instruction (RAM location) is desired. However, under ordinary operating conditions the GSP 400 is not capable of writing data to the program RAM 150. Under ordinary operating conditions, data is written into the program RAM 150 only via the host or access ports shown in Figure 1 which are also coupled to the program RAM bus 155 in a time division multiplexed manner. The GSP 400 is also coupled to the multiported data RAM 100 via a data RAM bus 125. Because the data RAM 100 is central to the processor architecture, and because non-arbitrated access to the data RAM 100 is desired, the data RAM 100 must either be a true multiported data RAM, or access to the data RAM 100 via the data RAM bus 125 must be time division multiplexed so as to effectively create a multiported RAM. The data RAM bus preferably comprises a data RAM address bus of sixteen bit width, an a data RAM data bus of twenty-four bit width. As indicated in Figures 3a, 3b and 4, the GSP may write to the address section of the program RAM 100. Also, the GSP may both read and write to the data section of the data RAM bus. The GSP is substantially described by the details and functioning of six sections: a block controller 410; a program control logic block 420; a multiplier block 430; an ALU block 450; a flag block 460; and a data RAM address generator block 470. Coupling all six sections, as well as a break register 492, a data access register 494, and a temporary register 496 is an internal twenty- four bit bus 490. All access from any of the sections or from the registers 492, 494, or 496 onto the internal bus 490 is via tristate drivers 429, 449a, 449b, 459, 469, 489, and 499. Block controller 410 is comprised of instruction decoder 412, and sequencer 414. The instruction decoder 412, when enabled, takes fourteen bits (nine bits of opcode, and five bits of operand) off of the data portion of the program RAM bus. Six of the nine opcode bits are used to indicate the operation (instruction) which the GSP is to perform (e.g. add, shift, jump, etc.), with up to sixty-four instructions being accommodated. Li the preferred embαliment an additional three bits of opcode are utilized to specify the addressing mode the GSP is to use. In particular, in the "absolute" mode (code 000), the fifteen bits in the O register 472 of the address generator block 470 are used to select an address in the data RAM 100, and the data in that address of data RAM is used for the operation. In the "register" mode (code 001), the five operand bits obtained by the instruction decoder 412 are used to specify which register of the numerous registers of the GSP is to place its contents onto the internal bus 490. In the "immediate left" mode (code 010), the fifteen bits of data in the O register are to be put into the fifteen msb slots of the internal bus 490, while in the "immediate right" mode (code 011), the fifteen bits are put into the fifteen Isb slots of the internal bus. In the remaining four modes, "BL indexed" (code 100), "B indexed" (code 101), "FL indexed" (code 110), and "F indexed" (code 111), as described in more detail hereinafter, values in base registers B or F are added to the value of the fifteen bit operand stored in the O register and, where appropriate, to the value in the L (loop) register, and are output onto the data RAM bus 125. Instruction decoder 412 is not only coupled to the program RAM bus, but to the numerous multiplexers, tristate drivers, registers, etc. of the GSP via lines 416. Based on the instruction which is decoded by instruction decoder 412, various of those lines 416 are enabled in a sequence as determined by the sequencer 414. In effect, instruction decoder 412, and sequencer 414 are simply look-up charts, with instruction decoder 412 looking up which lines 416 must be enabled based on the code found in the nine bits of opcode, and sequencer 414 looking up the sequence to which the enabled lines must subscribe. While instruction decoder 412 decodes whatever instruction is on the program RAM bus 155 when the GSP 400 is granted access to that bus, the instruction which is on the bus is generated and dictated by the program logic block 420. Program control logic block 420 is comprised of a tristate driver 422, a program address value register 424 (also called the "P" register), an incrementer 425, an increment (I) register 426, a jump (J) register 428, a multiplexer 430, and a branch logic block 432. The P register 424 contains the location of the program RAM 150 which contains the microinstructions which are to be used by the GSP 400. P register 424 writes that address onto the program RAM bus 155 by sending it to tristate driver 422 which acts as the bus interface. Updating of the P register 424 is accomplished via muxP 430 which chooses one of the twelve bit addresses stored in the I register 426 or the J register 428 based on information from branch logic block 432. The address stored in the I register is simply the next numerical address after the address stored in the P register, as a value of one is added at incrementer 425 to the value stored in P register 424. In most situations, muxP 430 will permit the P register 424 to be updated by the I register, and the sequential addressing of the program RAM will continue. However, in some situations, such as where a jump in the routine is desired, the multiplexer 430 will permit the address in the J register 428 to be loaded into the P register 424. The decision to jump is made by the branch logic block 432 which reads the status of a plurality of status flags as is hereinafter discussed. The address to which the jump is made is obtained by the J reg 428 from the internal bus 490, which may obtain the address from any of the sections of the GSP 400 (or from the data RAM 100). Coupled to the program control logic block 420 is a break register 492 in which upon the execution of a break instruction is loaded status flag information as well as the value of the P register plus one. The status flag and P register information is stored in the break register 492 which is coupled to internal bus 490 via tristate driver 429 because it is otherwise not available for placement on to the internal bus 490. A program break is typically executed when an information dump is desired by the system user, and is accomplished by putting an instruction in the program RAM 150 which causes the GSP 400 to write to a certain address (e.g. 0406H) of the data RAM 100. A decoder (not shown) on the data RAM bus 125 is used to determine that the program break is to be executed (based on the location to be written to), and a control signal is provided by the decoder to the break register 492. The program break instruction in the program RAM 150 causes instructions in a boot/break ROM 190 (shown in Fig. 1) which is coupled to the program RAM bus 155 to be accessed by the program control logic block 420. The instruction code in the boot break ROM 190 in turn causes the values of each of the registers in the GSP 400 to be written into desired locations in the data RAM 100. Then the GSP 400 is kept waiting until the wait flag stored in its wait flag register (discussed below) is cleared. During the wait period, if desired, the user can change the values of data in the data RAM as described in more detail below with reference to the access port 900. Then, when the wait cycle is terminated, the instructions in the boot break ROM 190 causes the values in the data RAM, including any new values, to be written back to their appropriate registers in the GSP. The location of the next desired microinstruction contained in a program RAM 150 location is loaded into the P register, so that the GSP can continue in its normal fashion. The multiplier block 430 and the ALU block 450 of the GSP perform the numerical computations for the GSP. The multiplier block 430 is comprised of two input registers Xreg 432 and Yreg 434, a multiplexer 436 which is coupled to the internal bus 490 via tristate driver 449a, a multiplier 438 with a post Xreg 439, and a multiplier control 441, a summer 442, an output register Mreg 444, and a second multiplexer 446 which selects which of six words is to be output onto internal bus 490 via tristate driver 449b. Typically, the multiplicand is loaded into Xreg 432. Then the multiplier is loaded into Yreg 434 while the multiplicand is loaded into post Xreg 439. The multiplier control 441 permits the multiplier 438 to function over several machine clock cycles (e.g. three clock cycles totaling 300 nanoseconds = fifteen internal GSP cycles). If in multiplying, the multiplier overflows, a status flag M is set, and this information is conveyed to the branch logic block 432 of the program logic section 420. Regardless, the product of the multiplier and multiplicand is forwarded to summer 442 which, in a multiply with accumulate mode, adds the new product to the sum of previous products and forwards the sum to the multiply register M 444. Li a pure multiply mode, the contents of the summer are cleared so that the product is forwarded through the summer which adds zero and send the product to the M register. The contents of the M register 444 are available to the internal bus 490. However, because the M register can accommodate a fifty-six bit word, and the internal bus 490 is a twenty-four bit bus, only a portion of the M register word may be placed on the bus at one time. Thus, multiplexer 446 is provided to either select the twenty-four least significant bits (lsb's) in the M register, the twenty-four next lsb's in the M register, or the eight most significant bits (msb's) in the M register. If the eight msb's are chosen, the eight msb's are placed in the eight lsb slots of the internal bus 490, and the msb of the eight bits is extended through to the msb slot on the bus (e.g. if the msb is a "1", the first seventeen msb's on the bus will be "1"). The multiplexer 446 is also capable of selecting a left shifted by two (zero filling the right) twenty-four or eight bit word. Thus, in all, multiplexer 446 can provide six different outputs based on the product in the M register 444. The ALU block 450 of the processor is basically a standard ALU, having an arithmetic- logic unit 452 with input register 454, and an output accumulator register 456. The arithmetic-logic unit 452 is capable of the standard functions of similar units, such as adding, subtracting, etc., and produces values for Areg 456, as well as status flags including carry (C), overflow (O), sign bit (S), and zero (Z). The status flags are used by the branch logic block 432 of the program logic block 420 to determine whether a conditional jump in the microcode program should be executed. The Areg contents are output onto internal bus 490 via tristate driver 459. Wait flag block 460 is comprised of two wait flag registers WFreg 462 and DFreg 464, a multiplexer 466, and OR gate 468. The bits of the wait flag registers may be set (i.e. written to) by data sent over the internal bus 490. Also, registers WFreg 462 and DFreg 464 are coupled to a flag bus 198 which is written to each time predetermined locations in the data RAM 125 are addressed as hereinbefore described with reference to Figures 2 and 13. In this manner, each bit of the wait flag registers 462 and 464 may be selectively cleared. When all of the bits in register WFreg 462 have been cleared due to the occurrences of specified events (e.g. the data RAM has received all the information which is required for another computation), OR gate 468 is used to provide a status flag W which indicates the same. Status flag W is read by the branch logic block 432. In this manner, "jump on wait flag" commands may be executed. The DFreg 464 of the wait flag block 460 functions similarly to the the WFreg 462, except that no signals indicating the presence of all zeros (or ones) are output by the DFreg. In order to check the contents of the DFreg (or the WFreg, if all values in the WFreg are not zero), the register must be selected to put its contents on the internal bus 490. The selection of one of the registers is made by the instruction decode 412 and sequencer 414, and the contents are forwarded via multiplexer 466 and the tristate driver 469. An easy manner of determining whether the DFreg 464 has all zeros is to forward the contents of the DFreg 464 to the ALU 452, which will provide a status flag Z if the contents are zero. The final large block of the general signal processor is the data RAM address generator block 470 which includes bus wide OR gate 471, registers Oreg 472, Dreg 473, Lreg 474, Breg 476, Freg 477, adders 481, 482, and 483, multiplexers muxBFL 484, muxL 485, muxA 486, muxBF 487, muxO 488, and an address access block 489. As previously indicated, the Oreg 472 obtains the fifteen least significant bits of the instruction on the program RAM bus. If "absolute" addressing is desired, i.e. the address to be written onto the data RAM bus is included in the program RAM microinstruction itself, the address is written into the Oreg 472, and then forwarded to the data RAM bus (a sixteenth bit having been added by a zero extender, not shown) via muxA 486 and the address access block 489. The sixteen bit address is then placed on the data RAM bus at the appropriate time. All other situations constitute "indexed" addressing, where the address to be put out on the data RAM bus is generated internally by the data RAM address generator block 470. Addresses are generated by adding the values in the various registers. In particular, and as indicated in Fig. 4, the Oreg 472 is the offset register, the Dreg 473 is a decrement register, the Lreg 474 is a loop register which sets the length of a loop, the Breg 476 is a base address register, and the Freg 477 is a frame address register which acts as a second base address register. The O register obtains its data off of the program RAM bus, while registers D, L, B and F obtain their data from the internal bus 490. If it is desired to add some offset value to the value in the base or frame register (i.e. the "B indexed mode" or "F indexed mode") in order to generate an address, muxBF 487 selects appropriately the Breg 476 or the Freg 477, muxBFL 484 selects the value coming from muxBF 487, and the Breg or Freg value is added to the offset value of the Oreg by the adder 483. That value is then selected by muxA 486 for output over the data RAM bus via the address access block 489. Similarly, if it is desired to add some offset value and some loop value to the value in the base or frame register (i.e. the "BL indexed mode" or the "FL indexed mode"), the value in the L register is added to the value in the B or F registers at adder 482, and the sum is passed via muxBFL 484 to adder 483 which adds the value to the value in the O register. By providing adder 481, and by coupling the decrement register Dreg and the loop register Lreg to the adder 481, registers an address loop is effectuated. In particular, the Lreg sets the length of the loop, while the Dreg sets the value by which the loop is decremented. Each time the Dreg is subtracted from the Lreg 475 at adder 481, the new value is fed back into the Lreg 475 via muxL 485. Thus, each time a DJNE instruction is executed (as discussed below), the resulting value in the Lreg is decreased by the value of the Dreg. If added to the Breg or Freg, by adder 482, the address generated is a sequentially decrementing address where the value in the Dreg is positive, and a sequentially incrementing address where the value in the Dreg is negative. The ability to loop is utilized not only to provide a decrementing (or incrementing) address for the data RAM bus, but is also utilized to effect changes in the program RAM address generation by providing a "decrement and jump on not equal" (DJNE) ability. The output from the adder 481 is read by OR gate 471 which provides a status flag L Coop) to branch logic block 432. The status flag L maintains its value until the L register has looped around enough times to be decremented to the value zero. Before that point, when the Lreg is not zero, the next instruction of the GSP is dictated by the instruction indicated by the Jreg 428. In other words, the program jumps to the location of the Jreg instruction instead of controlling with the next instruction located in the I register. However, when the Lreg does decrement to the value zero, the OR gate 471 goes low and toggles flag L. On the next DJNE instruction, since the "not equal" state does not exist (i.e. the Lreg is zero), branch logic 432 causes muxP 430 of the program logic block 420 to return to obtaining values from the lreg 426 instead of from the Jreg 428, and the program continues. The values of any of the O, D, L, B, or F registers may be placed on the internal bus 490, by having muxO 488 (and where appropriate mux BF 487) select the appropriate register and forward its contents via tristate driver 489 to the internal bus. Coupled to the internal bus 490, and interfacing the internal bus 490 with the data slots on the data RAM bus is the data access port 494. The data access port 494 is capable of reading data from and writing data to the data RAM and is given access to the data RAM in a time division multiplexed manner as previously described. In writing to the data RAM, the data access port 494 and the address access port 489 are activated simultaneously. In reading data from the RAM, the address access port 489 first places on the data RAM bus the data RAM address in which the desired data is stored. The data is then placed on the data RAM bus by the data RAM, and the data access port 494 which is essentially a dual tri-state driver, receives the data and passes it onto the internal bus 490 for storage in the desired GSP register. If desired, additional registers such as Z register 496 may also be coupled to the internal bus 490, and may be used as temporary storage. The contents of Zreg 496 are output onto the internal bus 490 via tristate driver 499. Details of the functioning of the GSP as well as example microcode may be seen with reference to previously incorporated U.S. Serial No. 07/525,977. Turning to Figures 4a, 4b, and 4c, block diagrams of the input and output circuitry of the data flow manager (DFM) 600 of the invention, and an example FIFO related to the DFM are seen. As previously described, the DFM serves the important function of handling the flow of data into and out of the processor apparatus so that GSPs of the processor apparatus need not be interrupted in their processing tasks. In accomplishing this function, the DFM takes data received by the serial port from the "world" outside of the particular processor apparatus and organizes it inside a FIFO such as the FIFO of Fig. 4c which is implemented in desired locations of the data RAM 100 of the SPROC apparatus 10. Also, the DFM 600 takes data in a FIFO, and organizes it for output to a serial output port of the SPROC apparatus. The DFM is also capable of directing data into a FIFO and drawing data from a FIFO at desired speeds so as to accommodate a decimation operation performed by the SPROC. Further, the DFM causes decoder 196 to write flags to the flag bus 198 (and hence to the GSPs 400) of the SPROC apparatus 10 regarding the status of the buffers. The DFM 600 of the SPROC apparatus may either be central to the apparatus, or distributed among the serial input and output ports 700 of the apparatus, with a single DFM serving each port 700. Where distributed, the circuitry seen in block diagram form in Figures 4a and 4b is duplicated for each serial input and output port 700 of the SPROC apparatus, although certain circuitry could be common if desired. The circuitry for receiving data from a serial port and organizing it for storage in a FIFO of the data RAM 100 is seen in Figure 4a. The data flow itself is simple, with the data being sent from the serial port 700, via multiplexer 611 and tri-state driver 613 to the data slots of the data RAM bus 125. Multiplexer 611 permits either data corning from serial port 700a or data generated as hereinafter described to be forwarded to driver 613. Driver 613 is controlled as indicated such that data is only output on the data RAM bus 125 when the DFM 600 is enabled by the system- wide multiplexer clock scheme. The organization of the data for output onto the data RAM bus as a twenty-four bit word is conducted by the serial port 700, as hereinafter described. Besides the data flow circuitry, each DFM is arranged with buffers, counters, gates, etc. to generate data RAM FIFO addresses for the mcoming data. As shown in Figure 4a, the DFM 600 has three registers 620, 622, 624, three counters 630, 632, and 634 associated with the three registers, an adder 636, a divide by two block 637, a multiplexer 638, seven logic gates 641, 642, 643, 644, 645, 646, and 647 (gates 642, 643, 645, and 647 being bus wide gates), and two delay blocks 648 and 649. The three registers are respectively: the start of FIFO register 620 which stores the start location in the data RAM for the FIFO to be addressed by the particular serial port coupled to the particular part of the DFM; the index length register 622 which stores the number of buffers which comprise the FIFO (for the FIFO of Fig. 4c, the index length register would be set at four), and the buffer length register 624 which stores the length of each buffer, i.e. the number of words that may be stored in each buffer (for the FIFO of Fig. 4c, the buffer length register would be set at eight). When a data word (twenty-four bits) is ready for sending to the data RAM for storage in a FIFO, the serial port 700a provides a ready signal which is used as a first input to AND gate 641. The second input to AND gate 641 is a data enable signal which is the time division multiplexed signal which permits the DFM to place a word on the data RAM bus. With the data enable and ready signals high, a high signal is output from the AND gate which causes driver 613 to output the data on the data RAM bus along with an address. The address is that which is computed by the twelve bit adder 636, or a prewired address, as will be described hereinafter. When AND gate 641 provides a high output, the high output is delayed by delay blocks 648 and 649 before being input into clock counters 630 and 634. As a result, counters 630 and 634 increase their counts after an address has been output on the data RAM bus. When counter 630 increases its count, its count is added by the twelve bit adder 636 to the FIFO start location stored in register 620. If selected by multiplexer 638, the generated address will be the next address output in the address slots of the data RAM bus in conjunction with the data provided by driver 613. Thus, as data words continue to be sent by the serial port for storing in the data RAM FIFO, they are sent to incremental addresses of the data RAM, as the counter 630 increasingly sends a higher value which is being added to the FIFO start location. As is hereinafter discussed, the counter 630 continues to increase its count until a clear counter signal is received from circuitry associated with the index length register 622. When the clear counter signal is received, the counter starts counting again from zero. As aforementioned, each time the AND gate 641 provides a high output, the counter 634 associated with the buffer length register 624 is also incremented (after delay). The outputs of the buffer length register 624 and its associated counter 634 are provided to bus wide XNOR gate 643 which compares the values. When the counter 634 reaches the value stored in the buffer length register 624, a buffer in the data RAM FIFO has been filled. As a result, the output of XNOR gate 643 goes high, causing three input OR gate 644 to pass a high signal to the reset of counter 634. The high signal from bus wide XNOR gate 643 is also fed to the counter 632 associated with the index length register 622, to the multiplexer 638, and to the multiplexer 611. As a result of the buffer being filled, multiplexer 638 enables the prewired address to be placed in the address slots of the data RAM bus 125, along with one of two predetermined (or generated) data words which are generated as discussed below. The placement of the prewired address and a data word on the bus at the end of buffer signal occurs upon the next data enable signal received by the DFM, which is before another word is assembled by the serial port 700a for sending to the data RAM 100. Also, the placement of the prewired address and data word is used for signalling purposes, as a decoder 196 (seen in Figure 1) monitors the data RAM bus 125 for the particular prewired addresses of the DFMs; the triggering of these addresses occiirring because of conditions in the DFM, i.e. the filling of buffers. The decoder 196 in turn, can set a flag (the setting of the flag can be dependent on the value of the data accompanying the prewired address) on the trigger bus 198 which signals the GSPs 400 of the SPROC of the occurrence. In this manner, the GSPs 400 can determine that the data required to conduct an operation is available to the GSP, thereby causing the GSP to exit a wait loop. The predetermined or generated data word placed on the bus after a FIFO buffer has been filled preferably uses a "1" as the msb of the data word if the FIFO buffer that has been filled causes the FIFO to be half filled (as described hereinafter), or a "0" as the msb otherwise. The remainder of the data word may be null information. Or, if desired, the data word may include the next location to which the DFM will write (i.e. the location computed by the twelve bit adder 636) which is inserted in appropriate locations of the data word. This predetermined or generated data word is then passed via multiplier 611 to driver 613 which places the data word on the bus at the same time the prewired address is placed on the data RAM bus 125. As aforementioned, when an indication of a full buffer is output by bus wide XNOR gate 643, counter 632 is incremented. Counter 632 therefore tracks the number of the buffer in the FIFO that is being filled. When the number of the FIFO buffer being addressed (as determined by counter 632) is half of the FIFO length (as determined by the length stored in register 622, divided by divide by two block 637), a flag is raised by the DFM via the bus wide XNOR gate 647. The "mid buffer" flag indicates that the buffer in the FIFO being written to is halfway through the FIFO. Hence, if all previous buffers in the FIFO are still full with data, the FIFO is half full. In addition, the mid buffer flag causes the generated data input to multiplexer 611 to be changed, such that the msb of the data is a "1" instead of a zero. Thus, upon filling the buffer which causes the FIFO to be half filled, a slightly differently coded data word is placed in the data slots of the data RAM bus. When the value of counter 632 is incremented to the value stored in the index length register 622, the last location in the FIFO has been addressed. Accordingly, it is desirable to recirculate; i.e. to continue by addressing the first location in the FIFO. With the value of counter 632 equal to the value of register 622, bus wide XNOR gate 645 provides a high signal which is passed through three input OR gate 646. As a result, counters 630, 632, and 634 are reset. As indicated in Fig. 4a, a "clear counter" signal may also be generated by a power up reset (PUR) signal which is generated by applying a signal to a predetermined pin (not shown) of the SPROC, and by a SYNC signal which is generated by writing to address 0405H of the data RAM 100. The SYNC signal permits different DFMs to be synchronized to each other. If desired, the input section of one DFM can be synchronized to the output section of the same or another DFM. This synchronization is accomplished via a pin (not shown) on the SPROC which generates the "en buf ' input into OR gate 644. In turn, OR gate 644 provides a high signal which resets counter 634 in synchronization with the resetting of a similar counter in a DFM output section such as described with reference to Fig.4b. Turning to Fig. 4b, the serial output section of the DFM 600 is seen. The function of the output section of the DFM is to take data in the FIFO, and organize it for output to a serial output port 700b of the SPROC apparatus. The output section of the DFM is preferably comprised of several registers and counters, logic elements including AND gates, comparators, and inverters, divide and add blocks, flip- flops, a buffer and a parallel to serial converter. Basically, the data flow through the serial output section of the DFM is simple. An address generated by the the start address register 652 is added by adder 654 to the value in the offset counter 656, and that address is output onto the address section of the data RAM bus. The data RAM receives the address information and then places the data located at that data RAM address on the data RAM bus. That data is received by the DFM and latched and stored in buffer 694 prior to being forwarded to the serial output port 700b. The remaining circuitry of Fig. 4b serves the functions of not permitting the data to be forwarded to the serial output port 700b unless certain conditions (i.e. triggers) are met, as well as generating synch pulses and error flags depending on internal logic and received signals. In particular, each DFM has a wait register 660 which holds flag information which must be cleared in the wait flag register 662 before a signal will be generated. The bits in the wait flag register are only cleared upon receipt of appropriate trigger bits received from the trigger bus 198. When the appropriate flags are cleared, bus wide NOR gate 664 resets the wait flag register 662 by permitting it to be reloaded from wait register 660. The NOR gate 664 also passes the signal on to divide by N (N = 0, 1, ..., n) block. Upon the divide by N block 666 receiving N pulses from NOR gate 664, it outputs a pulse to AND gate 668. If N is one, no clock decimation occurs. However, if N is greater than one, decimation is effected; i.e. the clock is reduced to match the decimation of data which occurred in the GSP. If the other input to AND gate 668, is also high (which occurs when the DFM is running as hereinafter described), a pulse is sent to offset counter 656 which increases its count In this manner the address output by adder 654 is changed to the next address. Likewise, when the output of AND gate 668 is high, a pulse is sent to the serial output port 700b which outputs a data signal from the DFM, and to the sample counter 684 which increases its count The DFM also includes a IE (initiation/error) register 661 which supplies the flag data which must be cleared by the trigger bits to the LF flag register 663. The outputs from IE flag register 663 are fed to bus wide NOR gate 665 which is used in a feedback manner to reset the IE flag register 663 so that it can be reloaded by IE register 661. The output from bus wide NOR gate 665 is also sent as the clock input into a D type flip-flop 667. The data (D) input into the D type flip-flop 667 should be the msb (bit twenty-three) of the data word being input into the DFM's data RAM buffer by the input side of the DFM, which is arranged to be a value "1" only when the word is being taken from the half-full location of the data RAM buffer. The value of the msb input to the D input, is then clocked over to the Q output of the flip-flop which is forwarded as the first of two inputs to each of two AND gates 670 and 672. As will be discussed hereinafter, AND gate 670 is used to set an error flag. AND gate 672, on the other hand, is used to set block 675 which is used to indicate the state of the DFM (i.e. is it presently running). If the DFM is presently causing data to be read from the data RAM and output via the DFM to a serial port, the DFM is in the running mode, and the output from block 675 is already high. As a result, inverter 676 provides a low signal to AND gate 672 which is not affected by the output from flip-flop 667. On the other hand, if the DFM is not running, the output from block 675 is low, and inverter 676 provides a high value to AND gate 672. Thus, if flip-flop 667 provides a low signal (which will happen until the buffer in the data RAM for the DFM has received enough data to be half full), the DFM will not start running. On the other hand, if flip-flop 667 provides a high signal indicating that the data RAM has now been filled halfway, block 675 changes its output and the DFM starts running. It should be noted that when the DFM is not running, the high output from inverter 676 is forwarded via OR gate 677 to the clearing input of offset counter 656, thereby causing the address count to be generated by adder 654 to be initialized upon start-up of the DFM. As aforementioned, AND gate 670 is used to set an error flag. Thus, if D type flip-flop 667 provides a high output while the DFM is running (as indicated by the output from block 675), AND gate 670 passes a high value to AND gate 698, which in turn will generate an error flag if other criteria are met, as hereinafter described. The remaining blocks of the DFM output section include a FIFO length register 680, a buffer length register 682, a sample counter 684, a divide by two block 685, comparators 686 and 687, a bus wide OR gate 689, and a set reset block 690. The FIFO length register 682 stores the full length of the FIFO. When the value of the offset counter 656 is equal to the FIFO length stored in buffer 680, a sync pulse is generated by bus wide XNOR gate 686 which is used to synchronize the incoming data signal into an input section of a DFM with the outgoing data signal from the described output DFM. The sync pulse generated is received by the input section of the DFM (seen in Fig. 4a) as the signal enbuf 1, previously described. In addition the sync pulse may be used to reinitialize the DFM by clearing the offset counter 656 and reloading the registers. When the value in the offset counter 656 is equal to one-half the value of the FIFO length register 680 (as determined by divide by two block 685), comparator 687 provides a pulse to set/reset block 690 which is indicative of the fact that the address placed on the data RAM bus is the address half-way through the data RAM buffer associated with the particular DFM. When the data RAM address is the half-full address, the data being written into the data RAM buffer should not be written into the half-full address (i.e. there should never exist a situation where the address is being written to and read from at the same time). Thus, if D type flip-flop 667 provides a high signal to AND gate 670 while the DFM is running, and the output from set/reset block 690 is also, high, AND gate 698 provides a high output which sets an error flag for the DFM. Finally, with respect to the output side of the DFM, the buffer length register 682 stores a value equal to the length of each buffer in the data RAM FIFO associated with the DFM. The sample counter 684 is a down counter which is preloaded with the buffer length stored in register 682. When a high pulse is received from XNOR gate 687 (i.e. the offset counter is half of the FIFO length), RS flip-flop 690 is set and the down counter of sample counter 684 is enabled. Each time sample counter 684 receives a pulse from AND gate 668, the count is decremented. When the sample count goes to zero, the RS flip-flop 690 is reset. However, while the RS flip- flop 690 is set and outputs a high pulse to AND gate 698, the DFM is looking for an error. If before being reset a high msb value is seen by flip-flop 667, the DFM is apparently attempting to read and write to the same buffer location at the same time. As a result, AND gate 698 provides a high signal which sets an error flag for the DFM. Turning to Fig. 4c, an example of a FIFO associated with the DFM is seen. The FIFOs associated with DFMs are contained in a preferably predetermined portion of the data RAM of the processor apparatus. The FIFO of Fig. 4c, as shown contains four buffers. Also as shown, each buffer contains storage for eight data samples. Thus, as shown, the FTFCLof Fig. 4c has storage for thirty-two data samples. Of course, a FIFO can contain a different number of buffers, and the buffers can store different numbers of data samples. The size of the each FIFO associated with a DFM and the size of its buffers is either set automatically by intelligent software which calculates the requirements of the particular DFM, or by the user of the processor system during initial programming of the processor system. Turning to Figure 5a, a block diagram of the serial input port 700a of the invention is seen. The basic function of the serial input port is to receive any of many forms of serial data and to convert the received serial data into parallel data synchronous with the internals of the SPROC and suitable for receipt by the DFM 600 and for transfer onto the data RAM bus 125. To accomplish the basic function, the serial input port has a logic block 710, a data accumulation register 720, and a latched buffer 730. The logic block 710 and the data register 720 are governed by seven bits of information programmed into the serial input port 700a upon configuration during boot-up of the SPROC 10. The seven bits are defined as follows: • Bits 0, 1, and 2 are used to govern the logic block 710. If the incoming data is a twenty- four bit word, the logic block takes the bits in a bit by bit fashion and forwards them to the data accumulation register 720. If the incoming data is a sixteen bit, twelve bit, or eight bit word, the logic block takes the bits of the word in a bit by bit fashion and zero fills them to extend them into a twenty-four bit word. Which bit of the received serial data is forwarded into the msb slot of the register 720 is governed by control bit 2. Once the data is properly accumulated in register 720, it is latched into buffer 730 where it is held until it can be forwarded through the input section of the DFM 600 for storage in the multiported RAM 100. The holding of the data in the buffer 730 until the appropriate signal is received effectively causes data which is asynchronous with the SPROC 10 to become synchronized within the SPROC system. Bits 3, 4, and 5 governing logic block 710 are respectively used to control the type of strobe, the type of clock, and the location of clock control for the input port 700, all of which are necessary for the proper communication between the SPROC and an external device. Because port 700 preferably includes the circuitry of both an input port 700a and an output port 700b (described in more detail hereinafter), an extra bit (bit 6) is used to control the functioning of port 700 as one or the other. The serial data output port 700b seen in Fig. 5b is similar to the data input port 700a in many ways, except that its function is the converse. The serial output port 700b includes a buffer 740, an parallel load shift register 750, and controlled multiplexers 760 and 770. The data to be written from the SPROC via the output port 700b is received by the buffer 740 from buffer 694 of the DFM 600. The twenty-four bits received are then loaded in parallel into the parallel load shift register 750 which functions as a parallel to serial converter. The twenty-four bits are then forwarded in a bit serial fashion via multiplexer 760 which receives the control signals dwO and dwl, and via multiplexer 770 which receives the msb control signal to the transmit data line. Multiplexers 760 and 770 effectively transform the twenty-four bit word received by the parallel load shift register into the desired format for communication with a desired device external the SPROC. The twenty-four bits may be transformed into an eight bit word (e.g. the eight msb's), a twelve bit word, or a sixteen bit word (the eight lsb's being truncated), with either the lsb or the msb being transmitted first. A twenty-four bit word may similarly be sent lsb or msb first. Where the SPROC is communicating with another SPROC (i.e. output port 700b of one SPROC is communicating with the input port 700a of another SPROC), multiplexers 760 and 770 are preferably controlled to send a twenty-four bit word, msb first Turning to Figure 6, details of the host port 800 are seen. Under most circumstances the host port 800 serves to interface the SPROC 10 with a host 180 (see Fig. 2), although where the SPROC 10 is a master SPROC which is in boot mode, host port 800 serves to interface the SPROC 10 with an EPROM and with any slave SPROCs which are part of the system. As indicated in Figure 8, the host port 800 is coupled to the data RAM bus 125 as well as to the program RAM bus 155 on the SPROC side, while on the host side, the host port 800 is coupled to the host bus. The host bus includes three data sections D0-D7, D8-D 15, and D 16-D23, and three address sections A0-A11, S0-S3, andEAO-EAl. The remaining interfaces shown on the host side are pins (e.g. master/slave, reset, mode) which control the functioning of the SPROC 10 and the host port 800, and the read/write strobes for the host bus 165. In slave mode (master/slave pin 801 set to slave mode), the SPROC 10 appears to other apparatus, including host microprocessors or DSPs as a RAM. Because it is desirable that the SPROC interface with as many different types processors as possible, the host port 800 is a bit parallel port and is arranged to interface with eight, sixteen, twenty-four, and thirty-two bit microprocessors and DSPs. The mode pins 802, 804, and 806 are used to inform the host port 800 as to whether the host processor is an eight, sixteen, twenty-four bit, or thirty-two bit processor, and whether the word being sent first is the most or least significant word. For sending data from the host processor to the SPROC in slave mode, a data multiplexer 810, a data input register 812, and. two drivers 815 and 817 are provided. The data multiplexer 810 receives three eight bit data inputs (D0-D7, D8-D15, and D16-D23) from the data bus section of host bus 165 and causes the data to be properly arranged in the data input register 812 according to the control of mode pins 802, 804, and 806. If the host processor is a thirty-two bit processor, the host port 800 of the SPROC takes two sixteen bit words and processes them in a manner described below with reference to a sixteen bit processor. Where the host processor is a twenty- four bit processor as indicated by mode pins 802 and 804, data is passed directly to the data input register 812 without adding bits or dividing bytes into segments. Where the host processor is a sixteen bit processor as indicated by mode pins 802 and 804, the host port takes sequentially takes two sixteen bits from two of the three eight bit data input lines (D0-D7, D8-D15, D16-D23), discards the eight lsb's of the least significant word, and uses the remaining bits to provide a twenty-four bit word to the data RAM bus 125 or the program RAM bus 155 of the SPROC. Where the host processor is an eight bit processor as indicated by mode pins 802 and 804, three eight bit bytes are received over the D0-D7 data input line and are concatenated in the data input register 812 in order to provide the SPROC with a twenty-four bit signal. Regardless of how the data input register 812 is filled, after the data is assembled, the host port 800 awaits an enabling signal from the SPROC timing so that it can write its twenty-four bit word to the data RAM bus 125 via driver 817 or the program RAM bus 155 via driver 815. In this manner, the host port 800 synchronizes data to the SPROC 10 which was received in a manner asynchronous to the SPROC 10. The address to which the data is written is obtained from the twelve bit address section A0-A11 of the host bus 165. The twelve bit address is forwarded from host bus 165 to the address input register 820. When the host port 800 is enabled, if the address contained in the address input register 820 is indicative of a data RAM location, the address is placed via driver 822 on the sixteen bit address section of the data RAM bus 125. Because the address bus is a sixteen bit bus, while the address in address input register 820 is a twelve bit address, four zeros are added as the msbs of the address via driver 824 when the address and data are put on the data RAM bus. If the address contained in the address input register 820 is indicative of a program RAM location (address location IK and below), the address is placed via driver 826 on the twelve bit address section of the program RAM bus 155. In the slave mode, when the host processor wishes to read information from the SPROC, the host processor causes the read strobe to go low. The address received by the host port over address lines A0-A11 is read by the host port 800 and latched into the address input register 820. When the host port 800 is allowed access to the data or program RAM buses, the address is placed on the appropriate bus, and the twenty-four bit data word located at the data or program RAM address which was placed on the appropriate bus is read and latched either into the program data output register 832 or the output data register 834. That information is then forwarded via multiplexer 836 to data demultiplexer 840 arranges the twenty-four bits of information onto locations D0-D23 of the host bus 165. Demultiplexer 840 serves the opposite function of multiplexer 810. When sending data to the twenty-four bit host processor, the demultiplexer 840 simply takes its twenty-four bits and passes them unchanged. When sending data to a sixteen bit host processor, the SPROC 10 divides its twenty-four bit word into two sixteen bit words (with zero filling as appropriate). Similarly, when sending data to an eight bit host processor, the SPROC 10 divides its twenty-four bit word into three eight bit bytes. In the master mode, on the "host" side of the host port 800 is located either an EPROM or one or more slave SPROCs. In the boot mode of master mode, data from the internal boot ROM 190 of the SPROC is written into the sixteen bit mode register 850 which is used to configure the internals of the host port 800. Then the GSP of the SPROC, which executes the program in the internal boot ROM, writes the sixteen bit addresses of the EPROM it wants to read in order to initialize the SPROC. Each address is received by the address output register 855 of the host port. The host port then sends a read strobe onto the host bus 165 and places via drivers 856 and 858 the address of the EPROM address it wishes to read. If the EPROM is an eight bit EPROM, the desired address is extended by extended address generator 860, and three read strobes are generated by the strobe generator 865 so that three eight bit bytes of the EPROM can be accessed. When the EPROM places its data onto the data locations of the host bus 165, that data is forwarded through data multiplexer 810, and is placed in a master mode receive register 867. The assembled twenty-four bit data word may then be read by the controlling GSP of the SPROC. After the word is read, the entire sequence repeats until all of the desired information stored in the EPROM is read into the SPROC. Where the master SPROC is acting to boot up slave SPROCs as well as itself, the master SPROC follows the same boot-up procedure just described. However, upon the host port 800 receiving information in the master mode receive register 867 which is bound for a slave SPROC as deteimined from information previously obtained from the EPROM, the master SPROC causes that data to be written to the host bus 165 (via bus 125, GSP 400, bus 125 again, register 834... as previously described) along with a sixteen bit address generated by the GSP 400 and sent to address output register 855 and then onto lines A0-A11, and S0-S3. In this manner, the data is forwarded to the appropriate SPROC so that it may be booted in a slave mode. It will be appreciated by those skilled in the art, that if the EPROM is wide enough to contain data and address information, that information can be written to host bus 165 and read directly by a slave SPROC or other device outside the memory space of the master SPROC. Because external memories vary in speed, the host port 800 is provided with a wait state generator 870 which can lengthen the read or write strobe generated by strobe generator 865. The host port 800 is also provided with a host interface controller 880 which is essentially distributed circuitry which controls the internal timing of the host port 800. A.1 Functional description of The Parallel Port The parallel port (PPORTO) is a 24-bit asynchronous, bidirectional port with a 16-bit (64K) address bus. The port allows for 8-, 16-, or 24-bit parallel data transfers between the SPROC chip and an external controller, memory-mapped peripheral, or external memory. The port has programmable WALT states to allow for slow memory access. A data acknowledge signal is also generated for this interface. Two operating modes — master and slave — allow the SPROC chip to operate either as a system controller (master mode), or as a memory-mapped peripheral to an external controller (slave mode). An input pin, MASTER, is dedicated to setting master or slave mode operation. In master mode, the SPROC chip automatically up-loads its configuration program from an external 8-bit PROM into internal RAM, at the initiation of boot. In slave mode, the chip relies on an external controller for its configuration. A system using multiple SPROC chips should have a single bus controller. This may be an external controller or a master SPROC chip. All other SPROC chips in the system should be configured in slave mode. The bus controller should individually enable the chip select input, CS , of each slave SPROC chip while the slave chip is being configured. The 16-bit address field (ADDRESS [15:0]) supports up to 16 SPROC chips interconnected in the same system. The external controller, memory-mapped peripheral, or memory may communicate with a SPROC chip in 8-,16-, or 24-bit format. Format selection is accomplished with the MODE[2:0] pins. In 8- or 16-bit formats, the data may be most significant (msb) or least significant (lsb) byte or v/ord first. In 16- and 24-bit modes, data is preferably always msb-justified within the word being transferred, and the lsb byte is zero-filled for 32-bit data transfer (i.e., in the second 16-bit word). To accommodate 8- and 16-bit modes, two extended address bits are included. These bits (EADDRESS[1:0]) are located at the lsb-end of the address bus. In master mode, these are driven output lines. In slave mode, they are configured as inputs and are driven by the external controller. The following subsections describe data transfers via the parallel port for different sources and destinations. In all types of parallel port data transfers, signal values at the slave SPROC chip's mode (MODE[2:0]) and address (ADDRESS[15:0]) inputs must be stable before the chip select ( CS ) and read ( RD ), or chip select and write ( WR ) request goes LOW. At that time, the address is latched into the slave SPROC chip. Subsequently, after values on the data bus (DATA[23:0]) become valid, data is latched at the destination on the rising edge of the request. To allow asynchronous communication with slow peripherals in master mode, the parallel port supports programmable WAIT states. In a preferred embodiment a maximum of seven WATT states are possible, where each state corresponds to one SPROC chip machine cycle, or five master clock pulses. The parallel port also generates a handshaking signal, DTACK (data transfer acknowledge) in slave mode. This normally-HIGH signal goes LOW when the SPROC chip presents valid data in a read operation, or is ready to accept data in a write operation. DTACK is cleared when the external RD or WR strobe goes HIGH. If enabled, a watchdog timer monitors all data transfers, and resets the parallel port if the transaction time is greater than 256 machine cycles. A.2 Master SPROC Chip Read from Slave SPROC Chip or Peripheral A master SPROC chip initiates a read operation from a memory-mapped peripheral or external memory by reading an off-chip memory location. Prior to initiating the READ, the master SPROC chip should set up the communication mode. This includes 8-, 16-, or 24-bit data select, msb lsb byte order, and number of WAIT states required for the peripheral. The master's internal parallel port mode register controls these options, and therefore should have been previously written to. In master mode, three bits of the parallel port mode register determine number and order of bytes transferred and are output at pins MODE[2:0]. These pins should be connected to the corresponding slave SPROC chip pins, which function as inputs in slave mode, to ensure the slave's communication mode matches the master's. After a read cycle is initiated by the master SPROC chip, no further read or write requests to the parallel port are possible until the current read cycle has been completed. The parallel port will setup a stable address and then drive the RD strobe LOW. The strobe will remain LOW for the number of WAIT states configured in the master's parallel port mode register, and will then be driven HIGH. The data resident on the data bus will be latched into the master SPROC chip on the rising edge of the RD strobe. If the transmission mode is 8- or 16-bit format, the read cycle will be repeated with the next extended address output as deteπnined by the state of EADDRESS[1:0], until 24 bits of data have been received. The master's parallel port input register is then updated, and the read cycle is complete. The GSP in the master that initiated the read operation must then read the contents of the parallel port input register. With the read cycle completed, the data bus I/O drivers will be reconfigured as output drivers to prevent the data bus from floating. The address bus will be driven with the last address. A.3 Master SPROC Chip Write to Slave SPROC Chip or Peripheral A master SPROC chip initiates a write operation to a memory-mapped peripheral or external memory by writing to an off-chip memory location. Prior to initiating the WRITE, the master SPROC chip should set up the communication mode. This includes 8-, 16-, or 24-bit data select, msb/lsb byte order, and number of WALT states required for the peripheral. The master's internal parallel port mode register controls these options, and therefore should have been previously written to. In master mode, three bits of the parallel port mode register determine number and order of bytes transferred and are output at pins MODE[2:0]. These pins should be connected to the corresponding slave SPROC chip pins, which function as inputs in this mode, to make the slave's communication mode match the master's. After a write cycle is initiated by the master SPROC chip, in the preferred embodiment no further read or write requests to the parallel port are possible until the current write cycle is complete. The parallel port will output a stable address and then drive the WR strobe LOW. The strobe will remain LOW for the number of WATT states configured in the master's parallel port mode register. Valid data will be setup on the data bus, and the WR strobe will be driven HIGH after the WALT interval, latching the data into the slave SPROC chip or peripheral. If the interface is configured in 8- or 16-bϊt mode, the cycle will be repeated until all bytes have been output. After transmission of the last byte or word, the address bus and data bus will remain driven. A.4 Read from Slave SPROC Chip by an External Controller The external controller will set up address, extended address, and mode inputs, and drive the SPROC chip's chip select input LOW. (If the communication mode will never change, the SPROC chip's MODE[2:0] inputs could be tied to the appropriate logic levels.) The external controller will then drive RD LOW, which will latch the address, extended address (EADDRESS[1:0]), and mode inputs into the slave SPROC chip. The SPROC chip will asynchronously fetch data from the requested internal RAM location. Data will be latched into the external controller when it drives the RD line HIGH again. The controller must ensure that enough time has been given to the slave SPROC chip to fetch the data, given the asynchronous nature of the interface. Alternatively, the SPROC chip drives its normally-high DTACK (data transfer acknowledge) LOW after it has completed the READ, and the controller need only wait for this event before raising \X\TO(RD). At that time, the SPROC chip would correspondingly raise DTACK . If the interface is configured for 8- or 16-bit communication, the external controller must set up multiple extended addresses and RD strobes. A.5 Write to Slave SPROC Chip by an External Controller The external controller will set up address, extended address, and mode inputs, and drive the SPROC chip's chip select input LOW. (If the communication mode will never change, the SPROC chip's MODE[2:0] inputs could be tied to the appropriate logic levels.) The external controller will then drive WR LOW, which will latch the address, extended address, and mode inputs into the slave SPROC chip. When the controller returns WR to HIGH, the data present on the data bus will be latched into the SPROC chip. If the interface is configured for 8- or 16-bit communication, the external controller must set up multiple extended addresses and WR strobes. After the final byte or word has been transferred, the data will be asynchronously written to the requested address in SPROC chip RAM. A.6 Data Transfer Modes MODE[0] and MODE[l] determine the number of bytes transferred per RD / WR strobe. MODE[0] distinguishes between a partial word of 8- or 16-bits, and a full 24-bit word. MODE[l] distinguishes between the partial transfers of 8- and 16-bits. All data transfers are aligned with the least significant byte of the data bus. For 16-and 24-bit modes, the most significant byte is left- justified within the data word, with descending order of significance in lower order data bus bytes. MODE[l] MODE[0] DATA 0 0 8-bit 1 0 16-bit X 1 24-bit MODE[2] determines the byte or word ordering for 8- and 16-bit modes: MODE[2] BYTE/WORD ORDER 0 msb first 1 lsb first EADDRESS[1,0], the extended address, specifies which portion of the full 24-bit word is currently being output on the data bus for 8- and 16-bit modes: In receive data mode, the lower byte of the lsb 16-bit word is unused by the SPROC chip. Similarly, in transmit mode, the lower byte of the lsb 16-bit word is filled with zeros. All data is msb-justified. The word ordering for 16-bit data is determined by EADDRESS[1]: 16 BIT MODE, MODE[2]=0 EADDRESS[1] EADDRESSLO] WORD 0 X msb 1 X lsb 16 BIT MODE, MODE[2]=l EADDRESS[1] EADDRESSLO] WORD 0 X lsb 1 X msb Data transfer in 8- and 16-bit modes is completed when the EADDRESS lines designate the final byte or word, namely, the lsb when MODE[2] is LOW, or the msb when MODEf2] is HIGH. A.7 Boot Mode A SPROC chip enters boot mode when it is configured as a master SPROC chip (its MASTER input is HIGH) and the reset input ( RESET ) executes a LOW to HIGH transition. During boot, the parallel port is set for 8-bit mode with the maximum number of WAIT states (seven). The master SPROC chip runs an internal program, stored in its control ROM, to upload its configuration from an external 8-bit EPROM into internal RAM. The master SPROC chip will then configure any slave SPROC chips present in the system. The EPROM will be selected by a HIGH on the master SPROC chip's chip select ( CS ) pin, which is an output in master mode. Slave SPROC chips or memory-mapped peripherals will be selected by a LOW at this signal. In master mode, the value of the CS output is controlled by a bit set in the transmit mode register, which is the second byte of the parallel port mode register. A.8 Watchdog Timer The parallel port incorporates a simple watchdog timer circuit to prevent any undesirable lockup states in the interface. In both master and slave modes, a read or a write flag is set (in the parallel port status register) on the initiation of a read or write operation. This flag is reset on a successful completion of the operation. If, for some reason, the host controller hangs-up in slave mode, or an invalid condition occurs in master mode, the watchdog timer will detect the situation and clear the interface flags, allowing the next operation to be accepted and executed. The watchdog timer is fixed at 256 machine cycles (1280 master clock cycles). The watchdog timer is enabled by setting bit 16 of the parallel port mode register. SPROC reset will disable the watchdog timer. If the watchdog timer is triggered, a flag is set in the parallel port status register. A.9 Multiple I O Lockout If the parallel port is performing a read or write operation in master mode, and a second write or read operation is initiated before the first I/O operation is completed, the second I O request is locked out. A lockout flag is set in the parallel port status register. A.10 Input/Output Flags and Lines The RTS and GPIO signals can be used for communication protocols between master and slave SPROC chips. These signals could be used as data-ready signals, requests for data, or microprocessor interrupt requests. RTS[3:0] (request to send) are four pins that function as inputs for a master SPROC chip and as outputs for a slave SPROC chip. The RTS signals of a slave SPROC can be individually set or cleared via the parallel port, as described below. GPL3:0] are four general purpose pins that are individually configurable as either inputs or outputs. During reset when RESET is LOW, all GPIO signals are set up as inputs. In addition to being subject to internal program control, the configuration of each GP pin, and the value of each GPIO signal configured as an output are also individually controllable via the parallel por A.11 Parallel Port Registers The parallel port utilizes five memory-mapped registers for status and control functions. The tables below list the registers and their bit definitions. Parallel Port Register Bit Definitions The parallel port status register, a 16-bit register, contains signal values of selected SPROC chip pins and I O status flags. This register is updated every machine cycle (5 master clock cycles). Bits 0 through 3 contain the current signal values at the GP pins, which could individually be configured either as inputs or outputs. Similarly, bits 12 through 15 contain the current values at the RTS pins, which are inputs for a master SPROC chip and outputs for a slave. Bits 4 through 6 contain the current value of the MODE configuration. Parallel port status register bit 10 contains the read flag, which is set while the parallel port is performing a read operation. Similarly, bit 11 contains the write flag, which is set during a write operation. (For 8- and 16-bit modes, these flags remain set until the entire 24-bit data word has been transferred.) Bit 7 is set while the parallel port is busy servicing an I O transaction. Bit 8 is set if the parallel port is busy in master mode and another read or write request is received. The second request will be locked out and the lockout flag set Bit 9 is set if the watchdog timer is enabled and it detects a timeout out condition. Bits 8 and 9 can only be cleared by a SPROC reset or any write to the lockout and watchdog flag clear register. Any write to the Watchdog Lockout Flag Clear Register clears watchdog and/or lockout flags set in the parallel port status register. The parallel port input register, a 24-bit register, holds the data word received during a read operation for subsequent storage at the destination address. This register also buffers and assembles the incoming data for 8- and 16-bit modes. This register must be read by a GSP or the access port The parallel port GPIO/RTS Control register, a 24-bit register, is used to independently configure each GP pin as either an input or an output It is also used to individually set and clear GP pins that are outputs, and slave SPROC chip RTS pins. Each RTS or GPIO signal has a dedicated pair of SET and CLEAR bits in the parallel port GPIO/RTS control register. SET and CLEAR bits for RTS signals are in the low byte; SET and CLEAR bits for GPIO signals are in the mid byte. LOW values written to both SET and CLEAR bits results in no change to the associated signal. A HIGH value at the SET bit sets the associated signal HIGH. A HIGH value at the CLEAR bit sets the associated signal LOW. If a HIGH value is written to both SET and CLEAR bits, the CLEAR dominates. Each GPIO signal additionally has a dedicated pair of OUTPUT and INPUT bits in the high byte of the parallel port GPIO/RTS control register to configure the signal as either an output or an input LOW values written to both OUTPUT and INPUT bits results in no change to the associated signal. A HIGH value at the OUTPUT bit configures the associated GPIO signal as an output A HIGH value at the INPUT bit configures the associated GPIO signal as an input If a HIGH value is written to both OUTPUT and INPUT bits, the INPUT dominates. The master SPROC chip's parallel port mode register, a 16-bit register, controls the parallel port mode and timing. When the master SPROC chip is reading from a slave SPROC chip or peripheral, bits 0 through 2 of the parallel port mode register (the RX MODE bits) are output at the master SPROC chip's MODE pins. Register bits 3 through 5 contain the number of WAIT states programmed for the read operation (Le., they determine the duration of the read strobe LOW level generated by the master SPROC chip). The HIGH level between read strobes is 2 master clock cycles; this duration can be stretched to 5 master clock cycles for slower peripherals by setting bit 6 of the mode register (the RX strobe delay bit). Similarly, when the master SPROC chip is writing to a slave SPROC chip or peripheral, bits 9 through 11 of the parallel port mode register (the TX MODE bits) are output at the master SPROC chip's MODE pins. Register bits 12 through 14 contain the number of WATT states programmed for the write operation. The HIGH level between write strobes can be stretched for slower peripherals by setting bit 15 of the mode register (the TX strobe delay bit). Bit 8 of the mode register is output at the master SPROC chip's CS pin. A soft reset of the parallel port, which resets the interface flags and RTS lines (but not the GPIO or MODE signals), can be initiated by setting bit 7 of this register. Parallel Port Signal Definitions DESCRIPΉON ADDRESS BUS BUS GRANT causes the SPROC chip to three-state the address and data buses, and MODE pins, when LOW. BUSY O PARALLEL PORT BUSY is set LOW when an I/O operation is occurring, set HIGH when completed. Also reset HIGH by watchdog timer if a timeout occurs. CRESET Tied LOW. CS O(M) I(S) CHIP SELECT signal. A slave SPROC chip is selected by setting its CS input LOW. A master SPROC chip generates this signal as an output, expecting to select a slave SPROC chip by setting CS LOW, and an external ROM (containing every slave SPROC chip's configuration) by setting it HIGH. DATA[23:0] I/O PARALLEL PORT DATA BUS— 24-bit input/output/three-statable bidirectional bus. DTACK O DATA TRANSFER ACKNOWLEDGE. In slave mode, set LOW by SPROC chip after RD or WR has gone LOW and the SPROC chip has completed the data transfer, set HIGH after RD or WR line goes HIGH. This output is always HIGH for a master SPROC chip. EADDRESS[1:0] O(M) I(S) EXTENDED ADDRESS specifies which portion of the full 24-bit word is currentiy being transferred in 8- and 16-bit modes. GP[3:0] I/O GENERAL PURPOSE I/O lines, individually configurable as either input or output. Can be used to interface SPROC chips with each other or with an external controller as data-ready, microprocessor interrupt requests, etc. Controlled and configured by a write to parallel port GPIO/RTS control register. MASTER MASTER causes SPROC chip to operate in master mode when HIGH, and in slave mode when LOW. MODE[2:0] O(M) I(S) MODE[0] differentiates between full 24-bit mode (HIGH) and partial (8- or 1 6-bit) modes (LOW). MODEfl] differentiates between 8-bit mode (HIGH) and 16-bit mode (LOW) for partial data transfers. MODE[2] specifies whether the first 8- or 16-bit transmission contains the lsb (HIGH) or the msb (LOW). RED TiedLOW. " RD " O(M)I(S) READ strobe generated by master SPROC chip or external controller. A LOW value on RD initiates a READ operation. RD must remain LOW long enough to successfully complete the READ; programmed WAIT states or DTACK handshaking may be utilized for this purpose. Data latches at the destination when RD returns HIGH. RESET RESET must be held LOW for a minimum of 25 master clock cycles, after power and clock have stabilized. This input is a Schrnitt trigger type which is suitable tor use with an RC time constant to provide power-on reset. While RESET is LOW, a master mode SPROC chip will force address, extended address, and SPROC select address LOW, while driving CS , RD , and WR HIGH. Slave SPROC chips connected to the bus will then be deselected and have driven inputs. MODEL2:0] will be configured for 8-bit boot mode with msb byte first and zero WATT states. The data bus will be driven. RTS[3:0] I(M) O(S) REQUEST TO SEND flags. These pins are outputs for slave SPROC chips and inputs for master SPROC chips. Can be used to interface slave with master or external controller as data-ready, microprocessor interrupt requests, etc. Controlled and configured by write to parallel port GPIO/RTS control register. WR O(M) I(S) WRITE strobe generated by master SPROC chip or external controller. A LOW value on WR initiates a WRITE operation. WR must remain LOW long enough to successfully complete the WRITE; programmed WAIT states or DTACK handshaking may be utilized for this purpose. Data latches at the destination when WR returns HIGH. * (M) = master mode, (S) — slave mode, I = input O = output While the SPROC 10 aforedescribed with a data RAM 100, a program RAM 150, a boot ROM 190, GSPs 400, DFMs 600, serial ports 700, and a host port 800, is a powerful programmable signal processor in its own right it is preferable that the SPROC be able to be programmed in a "user friendly" manner. Toward that end, a compiler system which permits a sketch and realize function is provided, as described more particularly with reference to Figure 12. In addition, an access port 900 and a probe 1000 are provided as tools useful in the development mode of the SPROC device. As aforementioned, the access port 900 permits the user to make changes to the program data stored in RAM 150, and/or changes to other data stored in data RAM 100 while the SPROC is operating. In other words, the access port 900 permits memory contents to be modified while the SPROC is running. In its preferred form, and as seen in Figure 9, the access port 900 is comprised of a shift register 910, a buffer 920, a decoder 925, and a switch 930 on its input side, and a multiplexer 940 and a parallel load shift register 950 on its output side. On its input side, the access port 900 receives serial data as well as a clock and strobe signal from the development host computer. The data is arranged by the shift register 910 and stored in buffer 920 until the access port is granted time division access to the data RAM bus 125 or the program RAM bus 155. A determination as to which bus the data is to be written is made by decode block 925 which decodes the msbs of the address data stored in buffer 920. The decode block 925 in turn controls switch 930 which connects the buffer 920 to the appropriate bus. The msbs of the address data in the buffer 920 are indicative of which RAM for which the data is destined, as the data RAM and program RAM are given distinct address spaces, as previously described. On the output side, data received via the program RAM bus 155 or the data RAM bus 125 is forwarded via demultiplexer 940 to a shift register 950. The shift register 950 effects a parallel to serial conversion of the data so that serial data may be output together with an appropriate strobe and according to an external clock to a development host computer or the like. By providing the ability to write and read data to the program and data RAMs, the access port 900 has several uses. First, by writing to a particular location (e.g. 406, or 408-40b Hex) in the data RAM, a program break can be initiated. The contents of the various registers of the GSPs which are written into data RAM as a result of the break can than be read. This information is particularly important in the debugging process. Second, if desired, the contents of the registers of the GSPs (as stored in the data RAM) can be modified prior to exiting the break mode by writing data to desired data RAM locations, thus providing an additional tool in the debugging process. Third, if desired, the program (including microinstructions and/or parameters stored as part of microinstructions) stored in the program RAM itself can be altered "on the fly", and can provide the developer with the ability to monitor (in conjunction with the probe 1000 hereinafter described) how a change in a parameter(s) or a change in the program could effect the functioning of the SPROC. The probe 1000 seen in Figure 8 permits the user to see internal signals generated by the SPROC by monitoring the data RAM bus 125 and capturing the values of data written to one or more data RAM locations. The probe 1000 is generally comprised of a comparator 1010, a DFM 1060 with an input section 1060a and an output section 1060b, and a digital to analog converter 1070. The comparator 1010 is programmable such that any data RAM address may be monitored. The data RAM address is monitored by coupling the comparator 1010 to the data RAM bus 125 and comparing via XNOR gates (not shown) die programmed address to the addresses placed on the bus. When the addresses match, and it is determined that data is being written to the data RAM as opposed to being read from the data RAM, the data is read into the input DFM section 1060a which stores the data until the probe is granted access for writing data to the data RAM 100. At mat time, the probe 1000 writes the data to its own buffer in the data RAM. When the probe 1000 is granted access for reading data from the data RAM 100, the output DFM section 1060b of the data probe 1000 pulls the data from its data RAM buffer at the speed set by the output DFM section's divide by N block. The data is then forwarded to the D/A converter 1070 where it is converted into analog format so that it can be viewed on an oscilloscope. In this manner, signals which are being written to any data RAM location may be monitored in real time as desired. By using the access port 900 and the probe 1000 together, the affect of a change of a parameter value entered via the access port 900 may be immediately viewed as an analog signal via probe 1000. Additional details of the probe may be seen with reference to previously incorporated SN 07/663,395. As seen in Figure 9, a plurality of SPROC devices 10a, 10b, 10c,... may be coupled to together as desired to provide a system of increased signal processing capabilities. Typically, the SPROC devices are coupled and communicate with each other via their serial ports 700, ahhough it is possible for the SPROCs to communicate via their parallel host ports 800. The system of SPROCs can act as a powerful signal processing front end to a logic processor (e.g., microprocessor) 1120, or if desired, can interface direcdy with electromechanical or electronic components. B. SPROC Development System and Software The above-disclosed SPROC devices 10 are preferably programmed via a development system (SPROClab). The SPROClab development system is a complete set of hardware and software tools for use with a PC to create, test, and debug digital signal processing designs. It was created as a design tool to support the development of code for the SPROC signal processing chip. B.l Overview The development system provides an interactive design environment to create processing subsystems in graphical form, as signal flow diagrams, and implement those subsystems easily and efficiently on the SPROC chip. Using the system, one can develop efficient signal processing subsystems without having to manually write code or lay out and tune analog circuits. Together with a PC and oscilloscope or other verification equipment, the development system supports the entire development process, including interactive debugging and design verification. Once the designer completes design development the designer can easily include the signal processing subsystem in the actual application using a SPROC chip and the code generated by the development system. The preferred process of programming a SPROC is as follows. The designer must first define the signal processing application and determine design requirements. The design is then preferably placed by the designer in a signal flow diagram (using a graphic user interface). Parameters for the various blocks of the design are defined by the designer, including parameters of filters (e.g., low-pass or high pass, and cut-off frequency) and, if desired, transfer functions. Once the signal flow diagram and parameters of the blocks in the signal flow diagram are set, the diagram and parameters are automatically converted into code by the software. The development system's SPROCview graphical design interface enables a simple graphical approach to design capture. Capturing the design consists of entering the design as a signal flow diagram. To enter the diagram, the designer arranges and connects icons that represent processing functions into a schematic diagram defining the signal flow of the system. As the designer selects and places the icons, certain variables and parameters must also be entered that define how the functions represented by the icons will operate. For example, if a design includes an amplifier function, its gain value must be specified. Some functions, like filters and transfer functions, are too complex to be defined using simple parameters. For these functions, one must create a separate data file that includes the detailed definition of the function. When using a filter or a transfer function in a diagram, one must enter a parameter to identify the data file that contains the definition of the function. The schematic diagram and its associated definition data files are the representation of the design upon which all other steps of the process build. The designer should consider them the base record of the design, and always make sure they are current. In designs that include filters or transfer functions, the designer must create the data files ■ that specify the definition of the functions. The SPROCfil filter design interface provides an interactive environment for designing filters. The designer must define transfer functions using a text editor. After the designer captures the design and defines any necessary filters or transfer functions, the diagram and definition data files must be converted into code and a configuration file must be generated to run on the chip. The SPROCbuild utility completes this for the designer by automatically converting the diagram and data files into code, scheduling and linking the code, and generating a configuration file for the chip. Each time the designer modifies the diagram or the definition data files, the files must be converted again to produce an up-to-date configuration file. To debug a design, the designer must transfer the configuration file onto the chip and run the design. The SPROCdrive interface (SDI) allows one to write the configuration to the chip and begin design execution. Using SDI, the designer can evaluate design performance by accessing the value of data in chip memory. If the development system is connected to an oscilloscope, one can view the waveforms represented by this data. If the development system is connected to a target analog subsystem, one can see how the design performs in the actual application. To optimize the design, the designer can modify the values of data and observe the corresponding changes in design performance. If the development system is connected to a signal generator, one can simulate various input signals and evaluate how the design reacts. Changes made to design parameters using SDI are temporary. The designer must modify the schematic diagram and/or definition data files, then convert the files again and generate a new configuration file to make design modifications permanent Once the designer has debugged and optimized the design, modified the diagram, and generated the final configuration file, the signal processing design can be ported for use in the end application. If the application is to run from a self-booting chip, the configuration file can be used to bum an EPROM, and the chip and its EPROM can be placed on a specific printed circuit board. If the application is to run from a microprocessor, the SPROClink microprocessor interface (SMI) helps the designer develop a microprocessor application that can use the signal processing design. The designer must generate a special version of the configuration file, create uie microprocessor application, and memory map the chip into the microprocessor configuration. The development system comprises both hardware and software tools designed to help the designer complete the development process. The tools are designed in parallel with the SPROC chip to extract maximum efficiency and performance from the chip without compromising ease-of- use. The development system includes hardware and software. The hardware components are described as follows: The SPROCboard evaluation board is a printed circuit board with one SPROC chip, digital-to-analog and analog-to-digital converters, and various communications interfaces and additional components and circuitry necessary to evaluate signal processing design performance during development The designer can connect an oscilloscope, signal generator, or analog subsystem to the evaluation board to verify and evaluate the design. The SPROCbox interface unit provides an I/O connection between the SPROCboard evaluation board and the PC. It also connects the evaluation board to the power supply unit. The power supply unit converts AC power from a standard wall outlet to 5 VDC and 12 VDC power for use by the interface unit and evaluation board. An RS-232 cable connects the PC serial I/O port to the SPROCbox serial I/O port. A special access port cable connects the SPROCbox interface unit to the SPROCboard evaluation board. A security key connects to the PC parallel port. It enables use of the development system software. An integral power cord connects the power supply unit to the AC outlet. A positive-locking DC power cable connects the power supply to the SPROCbox interface unit. An auxiliary DC power cable daisy chains power from the interface unit to the SPROCboard evaluation board. The software components of the development system are described as follows: The SPROClab development system shell executes under MS-DOS and provides access to all development system software components from a selection menu. The shell controls function calls among development system software components and provides a means for the designer to change certain system defaults. The SPROCview graphical design interface provides for easy creation of signal flow block diagrams by supporting the import of designs created using several common schematic capture packages. The basic development system configuration supports version 4.04 of OrCAD software and its schematic capture tool, Draft. The graphical design interface includes the library structure required to use the SPROCcells function library with OrCAD software. The SPROCcells function library includes cells containing DSP and analog signal processing functions for use in diagram creation. A cell is a design primitive that includes an icon required to place a function in a signal flow diagram, the code required to execute the function, and specifications for the parameters required to define the cell. The SPROCfil filter design interface supports the definition and analysis of custom digital filters. The filter design interface creates the custom code and definition data for filter cells placed in designs during diagram entry. The SPROCbuild utility converts signal flow block diagrams and their associated data files into the configuration file necessary to run on the chip. The utility interprets the output from schematic entry and incorporates associated code blocks and parameter data for cells, filter design definitions, and transfer function definitions, then schedules and links the instructions to best utilize resources on the chip. It automatically generates efficient code based on the designer's signal flow block diagram. The SPROCdrive interface (SDI) loads the configuration file onto the chip and starts execution. SDI commands give the designer access, through the SPROCbox interface unit, to interactively test and debug the design while it runs on the chip. One can probe and modify signal values and design parameters to tune and optimize the processing subsystem. B.1.1 The SPROCcells Function Library The SPROCcells function library contains over fifty pre-defined functions which can be used through the graphical interface of the SPROClab development system. Some cells have predefined trigger keys that aid in defining cell parameters for designs captured using OrCAD® software. Most cells include code for both inline and subroutine forms. The subroutine form of a cell performs a function identical to the corresponding inline form but includes overhead instructions that make the code in the subroutine body block re-entran Other subroutine versions of the cell do not include the code in their body blocks, but call the code in the body block of the first subroutine version of the cell. Several cells, including those used for microprocessor access, are described in detail below with reference to function, algorithm, terminals, parameters, macro keys, execution time, resource usage, and icon. The function provides a brief description of the operations or calculations performed by the cell. The algorithm (where applicable) details the methodology used to implement the cell function. Terminals are the inputs and outputs for a cell. Each terminal is associated with a pin number on the cell's icon. The variable type, range of legal values, and default value are provided for each terminal. Parameters are specifications that define the function of a particular instance of a cell. Parameter names and default values (where applicable) are provided for each cell. Parameter descriptions use the exclusive OR character ( I ) in listings of legal parameter values. This character indicates that only one of die listed choices may be used. Execution time is the maximum number of instruction cycles required to complete the code for a cell instance. Execution time differs for the in-line form and subroutine form (where applicable) of each cell. Resource usage is the number of memory locations required by d e cell. Resources include program memory allocations for instructions and data memory allocations for variables. Resource usage differs for the in-line form and subroutine form (where applicable) of each cell. Each cell is represented in the graphical display as an icon. Other examples of cell icons can be seen in Figure 11 discussed in detail below. Source code for. several of the cells described below is attached hereto as appendix B. CMULT Function: The complex multiplier cell performs multiplication of the form: i + jq = (x + jy) * (cos + jsin) = (x*cos - y*sin) + j (x*sin + y*cos) Terminals: pin l: i -2.0 <= output < 2.0 (fixed point format) pin 2: q -2.0 <= output < 2.0 (fixed point format) pin 3: x -2.0 <= input < 2.0 (fixed point format) pin 4: y -2.0 <= input < 2.0 (fixed point format) pin 5: cos -2.0 <= input < 2.0 (fixed point format) pin 6: sin -2.0 <= input < 2.0 (fixed point format) Parameters: Required: none Optional: subr = off I on (default is determined by the Schedule module) OrCAD Macro Keys: None defined Execution Time: In line: code duration is 16 cycles maximum Subroutine: code duration is 22 cycles maximum Resource Usage: In line: 16 program RAM locations 6 data RAM locations Subroutine: (5 * #_of_instances) + 17 program RAM locations (11* #_of_instances) data RAM locations Icon: CMULT? CMULT DSINK Function: The dsink cell accumulates two series of input samples (each size determined by the length parameter) into two blocks of data RAM. The blocks are stored beginning at symbolic location 'instance_name.outvectorl' and 'instance_name.outvector2'. Both blocks (vectors) are accessible from an external microprocessor. Terminals: pin 1: ina -2.0 <= input < 2.0 (fixed point format) pin 2: inb -2.0 <= input < 2.0 (fixed point format) Parameters: Required: none Optional: length = 1 <= length <= 256 (default: length = 128) subr = off I on (default is determined by the Schedule module) OrCAD Macro Keys: <ALT> K Execution Time: In line: code duration is 10 cycles maximum Subroutine: code duration is 17 cycles maximum Resource Usage: In line: 10 program RAM locations 2*Iength + 3 data RAM locations Subroutine: (4* #_of_instances) + 13 program RAM locations ((2*length + 5) * #_of_instances) data RAM locations Icon: DSINKRD Function: The dsinkrd cell accumulates two series of input samples (each size determined by the length parameter) into two blocks of data RAM. The blocks are stored beginning at symbolic location 'instance_name.outvectorl' and 'instance_name.outvector2'. Both blocks (vectors) are accessible from an external microprocessor. A reset input is available: if > = 0.5, the cell is held in reset otherwise the cell can capture a series of input samples. The done output is zero if the cell is reset or capturing input samples, else the done output is one. The done output needs to be terminated, either by another block or by a dummy module. Reset is only effective when the sink block is full. Terminals: pinl:done O i 1.0 (fixed point format) pin 2: ina -2.0 <= input < 2.0 (fixed point format) pin 3: inb -2.0 <= input < 2.0 (fixed point format) pin 4: reset -2.0 <= input < 2.0 (fixed point format) Parameters: Required: none Optional: length = 1 <= length <= 256 (default: length = 128) subr = off I on (default is determined by the Schedule module) OrCAD Macro Keys: <ALT> K Execution Time: In line: code duration is 14 cycles maximum Subroutine: code duration is 22 cycles maximum Resource Usage: In line: 20 program RAM locations 2*length + 5 data RAM locations Subroutine: (6 * #_of_instances) + 23 program RAM locations ((2*length + 8) * #_of_instances) data RAM locations Icon: SINK? EXTJN Function: The ext_in cell provides an external (off chip) input into the SPROC device. Typically the extemal input cell is used in conjunction with an extemal microprocessor. Terminals: pin 1 : out -2.0 <= output < 2.0 (fixed point format) Parameters: Required: trigger = SIPORTO I SIPORTl I clO I ell I cl21 cl3 rate = sample rate of trigger in Hz Optional: zone = alphanumeric name of timezone (default is null zone) OrCAD Macro Keys: None defined Execution Time: In line; code duration is 0 cycles Resource Usage: Inline: 0 program RAM locations 0 data RAM locations Icon: EXT_OUT Function: The ext_out cell provides an extemal (off chip) output. Typically die extemal output cell is used in conjunction with an extemal microprocessor. Terminals pin 1: in -2.0 <= output < 2.0 (fixed point format) Parameters: Required: none Optional: none OrCAD Macro Keys: None defined Execution Time: In line: code duration is 0 cycles Resource Usage: In line: 0 program RAM locations 0 data RAM locations Icon: FILTER Function: The filter cell is used for the implementation of filters designed with SPROCfil. For each instance of this cell there must be an associated filter data file produced by SPROCfil, an .fdf file. This is identified with the spec parameter. An optional type parameter allows filter type verification during the compilation process. Algorithm: Each UR filter cell in a SPROCfil design is implemented as a cascade of biquad cells, plus a bilinear cell for odd order filters. An FIR filter cell in a SPROCfil design is split into blocks, with a default of 30 coefficients; this is a scheduler parameter. Terminals: pin L out -2.0 <= output < 2.0 (fixed point format) pin 2: in -2.0 <= input < 2.0 (fixed point format) Parameters: Required: spec = file name (file stored in working directory fdf) Optional: type lowpass I highpass I bandpass I bandstop (allows the Schedule module to check that the filter file chosen matches the filter type desired) OrCAD Macro Keys: <ALT F Execution Time In line: code duration is filter dependent Resource Usage In line: program RAM usage is filter dependent data RAM usage is filter dependent Icon: LN Function: The natural logarithm is calculated using an eight term truncated series: ln(in) = ln(l+x) = x - x 2 /2 + x 3 /3 - χ /4 + x 5 /5 - x 6 /6 + x 7 7 - x 8 /8. In order to increase accuracy at the ends of the range of the input the following compression approach is applied: if in > 1.375, in = in/2 and out = ln(in) + ln(2); if 0.1353 <= in < 0.6875, in = 2*in and out = ln(in) - ln(2); if 0.6875 <= in <= 1.375, out = ln(in). The percentage accuracy varies, with the highest error in the input range of 0.32 to < 2.0 being 0.003%, and the highest error in the input range below 0.32 being 0.9%. OrCAD Macro Keys: None defined Execution Time: In line: code duration is 47 cycles maximum Subroutine: code duration is 50 cycles maximum. Resource Usage Inline: 52 program RAM locations 8 data RAM locations Subroutine: (4 * #_of_instances) + 50 program RAM locations (4 * #_of_instances) + 5 data RAM locations Icon: SINK Function: The sink cell accumulates a series of input samples (size determined by the length parameter) into a block of data RAM. The block is stored beginning at symbolic location 'instance_name.outvector'. This block (vector) is accessible from an extemal microprocessor. Terminals: pin 1: in -2.0 <= input < 2.0 (fixed point format) Parameters: Required: none Optional: length = 1 <= length <= 512 (default: length = 128) subr = off I on (default is determined by the Schedule module) OrCAD Macro Keys: <ALT> K Execution Time: In line: code duration is 8 cycles maximum. Subroutine: code duration is 13 cycles maximum Resource Usage: In line: 8 program RAM locations length + 2 data RAM locations Subroutine: (3 * #_of_instances) + 11 program RAM locations ((length + 4) * #_of_instances) data RAM locations. Icon: SINKRD Function: The sinkrd cell accumulates a series of input samples (size determined by the length parameter) into a block of data RAM. The block is stored beginning at symbolic location 'instance name.outvector'. This block (vector) is accessible from an extemal microprocessor. A reset input is available: if >= 0.5, the cell is held in reset otherwise the cell can capture a series of input samples. The done output is zero if the cell is reset or capturing input samples, else the done output is one. Reset is only effective when the sink block is full. Terminals: pin 1: done 01 1.0. (fixed point format) pin 2: in -2.0 <= input < 2.0 (fixed point format) pin 3: reset -2.0 <= input < 2.0 (fixed point format) Parameters: Required: none Optional: length = 1 <= length <= 512 (default: length = 128) subr = off I on (default is determined by the Schedule module) OrCAD Macro Keys: <ALT> K Execution Time: In line: code duration is 12 cycles maximum Subroutine: code duration is 18 cycles maximum Resource Usage In line: 18 program RAM locations length + 4 data RAM locations Subroutine: (5 * #_of_instances) + 20 program RAM locations ((length + 6) * #_of_instances) data RAM locations Icon SINK? SOURCE Function: The source cell repetitively reads a block of user specified sample values. The samples must be contained in a file, one sample per line, within the working directory, before scheduling. Source reads the samples one at a time from the block in data RAM, and the number of samples is specified by the length parameter. The block's position in RAM begins at symbolic location 'instance_name.in vector'. This block (vector) is accessible from an extemal microprocessor. Values of the sample data must be in the range from -2.0 to < 2.0 fixed point, but values can also be represented in hexadecimal and signed integer notation. Terminals pin 1: out -2.0 <= out < 2.0 (fixed point format) Parameters: Required: file = a file of data samples, e.g. "filblock.dat" trigger = SIPORTO I SIPORTl I clO I ell I cL21 cl3 rate = sample rate of trigger in Hz Optional: length = 1 <= length <= 512 (default: length = 128) zone = alphanumeric name of time zone (default is null zone) subr = off I on (default is determined by the Schedule module) OrCAD Macro Keys: <ALT> R Execution Time: In line: code duration is 9 cycles maximum. Subroutine: code duration is 17 cycles maximum Resource Usage: In line: 9 program RAM locations length + 2 data RAM locations Subroutine: (3 * #_of_instances) + 14 program RAM locations (flength + 4) * #_of_instances) data RAM locations Icon: Other cells in the function Ebrary include: ACOMPRES, AEXPAND, AGC, AMP, ANTTLN, BILINEAR, BIQUAD, DECIM, DIFFAMP, DLFFCOMP, DIFF_LDI, FIR, FWG_NEG, FWR_POS, GP_IN, GP_OUT, HARDLJM, HWR_NEG, HWR_POS, INTERP, INT_LDI, INT_RECT, INTR_LDI, INT_Z, MINUS, MULT, NOISE, PLL_SQR, PULSE, QUAD_OSC, RTS_LN, RTS_OUT, SCALER, SER_IN, SER_OUT, SLNE, SLNE_OSC, STEO_IN, STEO_OUT, SUM2 through SUM10, TRANSFNC, UCOMPRES, UEXPAND, VCO_SQR, and VOLTREF. B.2 Entering a Diagram The SPROClink microprocessor interface (SMT) provides software components necessary to develop microprocessor applications in ANSI C that include the SPROC chip as a memory- mapped device. Using the development system the designer captures the signal processing subsystem design by creating a signal flow block diagram that represents it. The diagram is created by using a schematic capture package to arrange and connect signal processing functions, or cells, in an order representing the signal flow of the subsystem. A cell is a design primitive corresponding to a specific block of SPROC description language (SDL) code. The SPROCcells function library includes many commonly used cells, and the designer can create additional cells in SDL to meet special needs. Each cell has a graphical symbol, or icon, that represents the cell and illustrates the number of inputs and outputs the cell uses. A function is inserted into the signal processing flow by placing the icon for that cell into the signal flow diagram and connecting, or wiring, the icon to other icons in the diagram. In addition, each cell has a set of characteristics, called parameters, that identify the cell and allow its detailed operational specifications to be defined. Most cells have parameters that specify simple operational values, but some cells are more complex. For example, filter and transfer function cells require entire data files to completely define their operations. In such cases, the cell's parameter does not define a simple operational value, it specifies the name of a data file containing the complex definition. When the icon for a cell is inserted into a signal flow diagram, the inputs and outputs are connected, and parameters for that occurrence of the cell are specified, the designer must create an instance of the cell. A cell instance includes the function, identification, connection, and parameter definition for a single occurrence of a cell within a diagram. Each instance of a cell in a signal flow diagram is identified by a specific and unique instance name. For example, if the signal processing subsystem requires four (4) amplifiers, the diagram that represents that subsystem must include four amplifier cells (and their parameters and connections) with four different cell instance names. A netlist is a listing of all cell instances (functions, instance names, parameters, and connections) included in a signal flow block diagram. It is a textual description corresponding to the graphical representation of a signal processing design. The development system uses the netlist to generate code and a chip configuration file for the design represented on the signal flow block diagram. OrCAD software requires that icons for function cells be grouped into structures called libraries. The software uses these structures to organize the cells and create menus through which the designer can access them. A library contains all of the icons for a specific grouping of functions. The functions in the SPROCcells function library are organized into a single OrCAD library. In OrCAD, parameter specifications, including cell instance names, are recorded in part fields. All cell instances have at least one part field containing the instance name. If an instance name is not specified, a default name is created. Parameter values are specified using the parameter names. As parameters are defined, the part fields containing those parameters are organized sequentially according to the order in which definitions are entered. (The instance name always occupies a special unnumbered part field.) To edit the contents of a part field once it has been defined, the part field's sequence number must be specified. For example, inserting the icon for an amplifier cell into a diagram and specifying a value for the gain parameter, the default instance name for the cell occupies an unnumbered part field, and the gain specification occupies the first numbered part field. To edit the gain parameter after it is defined, part field number 1 must be accessed. B.3 Defining a Filter If a signal processing design includes one or more filters, the designer must create a data file, called a filter datafile, that defines the detailed specifications and coefficient data for each filter. A parameter in each filter cell instance entered on the signal flow block diagram identifies the name of the filter data file to use with that filter. The SPROCbuild utility is used to convert the signal flow block diagram into code and generate a chip configuration file, the utility reads the filter data file for each filter cell instance and generates the appropriate code to implement the filter as specified. The generated code uses the coefficients from the filter data file and a cascade of special filter cells to implement the filter. The special cells are provided in the SPROCcells function library, but reserved for internal use by the SPROCbuild utility. The SPROCfil filter design interface helps the designer create filter data files that specify the coefficients and processing order to use in implementing a filter design. The filter design interface provides an interactive design environment that lets the designer define a filter using a graphical representation of the filter shape. Otiier tools in the filter design interface automatically generate the coefficients corresponding to the filter design, and write these coefficients to the filter data file. The filter design interface supports design of the following major categories of digital filters: Infinite Impulse Response (UR) or recursive filters, and Finite Impulse Response (FIR) or nonrecursive filters. In the UR category, four familiar analog types of filters are available: Butterworth, Chebyshev I, Chebyshev II (or inverse Chebyshev), and Elliptic function (or Cauer parameter). In the FIR category, two filter types are available: Optimal Chebyshev approximation, commonly referred to as the Equiripple or Parks-McClellan-Remez (PMR) design, and Kaiser window design. The designer can use these types to design lowpass (LP), highpass (HP), bandpass (BP), and bandstop (BS) filters. All filter data files created using the filter design interface are in ASCH format with the data clearly labeled; any file can thus be viewed using the DOS command type filename, or any word processor or editor. The coefficients calculated by the filter design interface are written to the filter data file in floating point precision. Quantizing to the 24-bit word length of the SPROC chip is done automatically by the SPROCbuild utility. The frequency-domain properties of a filter may be evaluated for any wordlength. Computation of a frequency response using quantized coefficients serves to illustrate the degree of sensitivity of the filter performance to the use of finite precision coefficients, i.e., the degree to which the poles of UR filters, and the zeros of UR and FIR filters, are modified by the finite- precision coefficient values. The following limitations apply to filters designed using the filter design interface: Maximum order for UR filters is 20. Maximum length for PMR (Equiripple) FIR filters is 200. Maximum length for Kaiser window FIR filters is 511. Frequency response for UR and FIR filters is limited to up to 500 spectrum values covering any desired segment of the frequency range between d-c and one-half of the sampling frequency. The response computation may be specified either by the number of points in a frequency range or by the spacing between points on the frequency axis. As an additional option for FIR filters, up to 512 spectrum values between d-c and one- half of the sampling frequency may be efficiently computed with up to a 1024-pointFFI. After the initial specifications are entered, modification of the design to meet certain program Umitations may be performed by an interactive process. For example, if the design is an UR filter, it may be necessary to modify the design to produce a filter order that is an even integer, relax some specification to produce a filter order that is 20 or less, or modify the design to make transition ratios in BP and BS filters equal. If the design is a PMR FIR filter, it may be necessary to relax some specification to produce a shorter filter length, or to modify the design to make the transition bands of BP or BS filters of equal width. When the design has been modified to meet program limitations, the following steps are required to complete the design and write the filter data file: For UR filters, completing the design involves determining the sequence of biquad sections and scaling the design to avoid overflow. For PMR FTR filters, completing the design involves computing the actual filter length. The estimated filter lengtii can be increased or decreased. All UR designs are given by sets of coefficients of cascaded second order (or biquad) sections, with a first order section for odd-order filters (LP and HP only). When an UR filter is designed the coefficients for each biquad section are displayed/printed as the set A, B, C, D, and E. The coefficients D and B can be as large as 2 in magnitude. For all four UR filter types — Butterworth, Chebyshev I, Chebyshev 11, and Elliptic ~ the same user interface applies. Hence the discussion here applies equally well to any IIR filter design activity. Several categories of IIR filters may be designed: lowpass, highpass, bandpass, or bandstop. Although all digital filters are properly characterized on a normalized frequency basis, for the user's convenience, the filter design interface allows specification of all critical frequencies in Hz, KHz, MHz, or GHz. Values must be provided for the passband and stopband edge frequencies, and for the attenuations in the passbands and stopbands. The filter response has a maximum value of unity (0 dB) in the passband. It is not unusual to approach the design of a filter without specific values for all of the critical frequencies, having only a general idea of passband and stopband locations. To aid in the design process, the filter design interface provides full capability for adjusting all parameters of the filter to achieve a best compromise between performance and complexity (as measured by filter order). The procedure is fully interactive; all computations are done by the filter design interface. Before discussing this interactive process it may prove helpful to review the way in which the order of UR digital (and analog) filters depends upon the filter specifications. Filter order is proportional to Arnin and inversely proportional to Amax; i.e., small passband ripple and large stopband attenuation mean high order. In addition, the filter order is inversely proportional to the transition ratio, which measures the relative narrowness of the transition band — the region between passband and stopband. Because the filter design interface uses the technique of bilinear-z mapping to convert analog prototypes to digital designs, the transition ratio is not FP/FA (for lowpass), or FA/FP (for highpass). Instead, one must use the ratio of the pre-warped critical frequencies: tan(π FP/Fs) and . tan(π FA/Fs) where Fs is the sampling frequency. For bandpass and bandstop filters the critical frequencies for the pass- and stopbands are denoted by FP1, FP2, FA1, FA2. Here there are two possible transition ratios. The values for a bandpass filter are: Lower transition ratio = tan(π FAl Fs)/tan(π FPl/Fs); Upper transition ratio = tan(π EP2/Fs)/tan(π FA2/Fs). The filter design interface uses the standard lowpass-to-bandpass transformation method which requires that these two ratios — using pre-warped values — be equal. This is called the geometric symmetry constraint. It is not necessary to precompute these ratios; the filter design interface will perform all necessary adjustments. After the initial specifications are entered tiiere follows an interactive process which has the goal of modifying the design to meet program limitations. It may be necessary to find an integer- valued filter order which satisfies the design specifications. It may be necessary to adjust transition ratios to meet the requirements for geometrical symmetry in transition ratios. After developing an acceptable set of specifications and value for filter order tiiere follows another module for the purpose of completing the design by establishing a sequence for the biquad sections, optionally scaling for 0 dB transmissions, and creating a filter data file which will hold the specifications and floating-point precision coefficients. The sequencing and scaling steps are intended to guard against overflow in fixed-point arithmetic. Before the order for bandpass and bandstop filters is computed it is necessary that the geometric symmetry constraint be satisfied. E the values of FP1, FP2, FA1, and FA2 do not yield equal upper and lower transition ratios, the transition ratios (UR) or transition bands (FIR) are unequal. They can be easily adjusted in the selected design module. The filter order/length values shown below are for the smaller transition ratio, or band width, value. This indicates that the input band edge values do not exactly satisfy the equal transition ratio requirement for UR, but these values can be adjusted in a number of ways. It is almost impossible to enter values which do satisfy the πR filter requirement unless the values are calculated beforehand. The designer has three choices: use the upper transition ratio; use the lower transition ratio; use the mean of the upper and lower transition ratios. These choices are presented in terms of new values for certain of the critical frequencies, and the computed filter order associated with each choice. For a bandpass filter the passband edge frequencies are preserved as originally specified, and the stopband edge frequencies are adjusted in value. The adjusted values for the bandstop filter will be the passband edge frequencies, with the stopband edges remaining as specified. If the stopband edges are to be adjusted to obtain equal transition ratios, then the set of choices may look something like the following: 1. End of lower stopband (Hz) = 255.702 (Order = 14.6); 2. Beginning of upper stopband (Order = 11.1) (Hz) = 3.52793E+03; 3. End of lower stopband (Hz) = 227.878 (Order = 12.6), Beginning of upper stopband (Hz) = 3.46362E+03. The designer has the choice of adjusting either the lower or upper transition ratio — choices 1 and 2 — or using the mean of the transition ratios — choice 3. In some cases the difference in filter order is substantial. In most software for filter design the highest order filter is automatically chosen — the designer has no control. Here, all trade-offs between filter order and specifications are under the designer's control. If the filter order determined by the initial filter specifications is not an integer, select an order that is an integer. The designer will have the opportunity to improve the filter performance if a higher filter order is chosen, some performance specification is relaxed in order to obtain a lower filter order. The choice of a value for filter order sets the stage for adjusting filter specifications in conformity with the selected order. For each choice of filter order there are three possibilities for parameter adjustment, relating to stopband and passband attenuations and to band edge frequencies. The operating rule is that passband frequencies should not be adjusted for lowpass and bandpass filters, and that stopband frequencies should not be modified for highpass and bandstop filters. The designer may decide to do otherwise - the choice of adjusting either the passband or stopband is always available. Either of the attenuation values can be adjusted. The designer may try all three parameter adjustments, for any choice of filter order. If none of these adjustments results in a satisfactory set of specifications the designer may try another value for filter order, or can go back to the beginning and modify the set of initial specifications. This interactive process of iteration should give the designer a good idea of the quantitative range of trade-offs between filter performance and order that is available. Realization of high performance filters — by which is usually meant sharp cutoff — is restricted in the analog domain by component precision and tolerance. For digital filters, precision refers to the wordlength of the computation used in implementing the filter. There is no direct counterpart to component tolerance; clock stability is a possible analogy. The SPROC chip uses a 24-bit computational word, which is equivalent to a resolution of better than 1 part in 106. The development system's crystal controlled clock provides superior stability. All of this gives digital filters on the SPROC chip a performance level that is far better than any analog implementation. Because this high performance is so seemingly easy to achieve, the designer is often seduced into overspecifying filter performance, with the penalty being increased computational load and increased memory usage. In some cases there will be additional signal-to-noise ratio degradation due to an accumulation of quantization noise originating in the arithmetic rounding process; this effect is significant only for UR filters, because it is their inherent feedback operation which can lead to an amplification of quantization noise. If a filter on the SPROC chip is overdriven there may be an arithmetic overflow internal to the filter cell. This is most likely with UR filters. Although all UR filters designed by the filter design interface can be scaled so as to protect against overflow, the scaling process is based upon a sine wave input signal. For almost all designs, the filter design interface can achieve a maximum level of 0 dB for all internal signals based upon an input sine wave at a 0 dB level. In actual operation with real input signals it is possible for phase distortion in the UR filter to cause "signal pile-up" so that an internal signal, or even the filter output, can slightly exceed the 0 dB level. In such cases one will have to scale down the input to the filter. Experience has shown a 2 to 3 dB decrease in signal level (a gain of 0.8 to 0.7) is all that is needed should an overflow problem occur. Each UR filter is first designed as a normalized lowpass analog prototype. The appropriate band transformation, incorporating bilinear-z mapping, is performed in order to get a initial set of digital filter coefficients from which the poles and zeros of the filter are determined. As a first step in the process of miriimizing overflow problems in fixed-point, or integer, arithmetic these poles and zeros are automatically grouped so as to minimize the peak gain of each biquad section. The next steps are to establish a sequence for cascading the biquads, and then to select the multiplier coefficient for each biquad so that the transmissions from the input of the filter to the output of each biquad have a peak that is less than ore equal to 0 dB. When these steps have been performed satisfactorily then the filter data file name is created and the filter specifications and coefficients are written to the file. More than one ordering and/or scaling may be performed and each set of coefficients saved to a different filter data file. (Note that different orderings and scalings affect only the A coefficients...the numerator and denominator coefficients are determined by the filter's poles and zeros which do not change.) The pairing of poles and zeros, and the establishing of a sequence for the biquad sections in an UR filter realization, are of great importance in fixed-point arithmetic. The filter design interface uses a standard procedure for pairing poles and zeros to form the biquad sections, and allows the user complete freedom in choosing the sequence for the cascaded biquad sections. Problems associated with roundoff noise buildup and accumulator overflow can be substantially reduced by ensuring that the peak gain for each biquad is as small as possible. The greatest peak is associated with the complex-conjugate pole pair having the highest Q (i.e., greatest magnitude, or closest to the unit circle). In fact this is a resonance peak. As the first step in reducing the peak of each biquad frequency response as much as possible one begins with the largest magnitude pole pair and groups it witii the complex zero pair that is closest in frequency — which is angle in the z-plane. One then successively applies the same rule of combination — largest magnitude pole pair with closest-in-frequency zero pair — to the remaining poles and zeros until all assignments are done. Although this procedure reduces the largest peaks as much as possible, the gains of biquads with large magnitude poles may still reach levels as high as 10 to 12 dB. If the cascade of biquads is sequenced with the largest magnitude poles first then the roundoff noise which is generated and amplified in these biquads will be substantially filtered by the lower gain biquads which follow. This reduction in roundoff noise accumulation (and zero- input limit cycle amplitude) at the output of the filter may, however, be accompanied by severe overflow problems at the input stages of the filter. This overflow problem is due to placing the largest magnitude pole pairs (and thus the highest-Q resonances) in the first biquads. If one elects to scale for 0 dB transmissions from the input to each biquad's output then the A coefficients will generally be small for the initial biquads in the cascade. In effect the input signal is scaled down in order to avoid overflow; this can degrade signal-to-noise ratio. As an alternative one can sequence the cascade of biquads so that the smallest magnitude pole pairs are first. This will result in less scaling down of the initial A coefficients, and thus the signal, but it is often not possible for the scaling algorithm in the filter design interface to achieve 0 dB transmission for each biquad. Anodier problem with this sequence is that the roundoff noise in the output is greater, and the ZILC amplitude can be greater. If either of these biquad sequences is unacceptable the designer is free to establish any biquad sequence. Note that for odd-order filters the first-order section is always placed after all of the biquad sections. A new filter data file can be created for each biquad ordering specified. Thus, if three orderings are specified for a fifth-order Butterworth filter then the default file names are buttrO5afdf, buttrO5b.fdf, and buttr05cfdf. The incidence of accumulator overflow in UR filter operation may be reduced through the proper ordering of the cascade of biquad sections. For relatively high order filters there are many possible orderings that can be tried; low order filters give fewer opportunities for ordering of biquads, but usually do not present serious overflow problems anyway. When the filter is designed one is given the option of specifying the order in which the biquads are placed. In addition one has the option of scaling the A coefficients so that the transmission from the filter input to the output of each biquad is less than or equal to 0 dB. Experience shows that the algorithm implemented in the filter design interface achieves this 0 dB transmission goal most often when the biquad sequence has the largest magnitude poles first If this is not true for a particular design then one can try the reverse sequence — smallest magnitude poles first or specify one's own sequence. If one elects to specify an arbitrary biquad sequence, then to strike a balance between overflow problems, roundoff noise accumulation, and ZILC oscillation amplitude, it may be desirable to have the largest magnitude poles in the middle of the cascade, with lower magnitude poles at the beginning and end of the cascade. Obviously this is possible only if the filter is of order 6 or greater, so that there are at least three biquad sections. This sequence can reduce the probability of overflow in the first stages, and often reduces the magnitude of signal frequency components that fall at the peaks of the responses of the biquads with large magnitude poles. Also, if the one of the biquads with large magnitude poles does exhibit a ZILC oscillation, there will be some attenuation of the oscillation by the lower gain biquads which are at the end of the cascade. Nevertheless, there are filter designs for which no ordering of biquads alone is sufficient to prevent overflow, and for which the scaling of A coefficients between sections does not achieve 0 dB transmission for all biquads. Because the filter design interface displays the actual peak responses after the "scaling for 0 dB transmissions" message one can see the effectiveness of alternative biquad sequences and choose the best From the standpoint of having the filter perform the function that it was designed for, overflow should never be permitted. UR filter behavior after a 2's-complement overflow is totally erratic, and can degenerate into an overflow-induced oscillation; should this occur the filter must be reset in order to stop the oscillation. The best design is that in which scaling of data and gain coefficients guarantees that overflow will not occur. BADefining a Transfer Function Although the SPROClab development system does not provide a tool for defining transfer functions, the SPROCbuild utility can implement user-defined transfer functions of two types: s- domain transfer functions and z-domain transfer functions when generating code and creating a SPROC chip configuration file. The SPROCcells function library includes a transfer function cell so that the designer can include transfer functions in the signal processing designs. When placing this cell in a diagram, one must specify a parameter that names the file defining the transfer function. The SPROCbuild utility uses z-domain transfer functions directly, and automatically converts s-domain transfer functions into z-domain transfer functions. It implements the transfer function as a cascade of lst-order or 2nd-order sections using the coefficients you define. When creating transfer function files, one must not mix 2nd-order and lst-order sections in one file. To implement a 5th-order transfer function, one must use two transfer function cells in cascade in the signal flow block diagram — one with two 2nd-order sections, and the other with a single lst-order section — and define separate transfer function files for each cell. If all the poles and zeroes are real- valued, one can use a single transfer function cell with five lst-order sections.) An s-plane transfer function file may be composed of either a number of 2nd-order sections in cascade, or a number of lst-order sections in cascade. One must use a text editor to create an ASQI file containing the definitions for the coefficients for the transfer function. In addition to the coefficient values, one must specify the number of 1st- or 2nd-order sections, and also supply the sampling frequency and a critical frequency. These two parameters are needed for the bilinear-z mapping procedure which converts the s-plane transfer function to a z-plane transfer function. The bilinear-z conversion method is used because it eliminates spectrum aliasing. However, in accordance with the well known principle of conservation of difficulty, it introduces a warping of the frequency axis. With F denoting frequency in the s-plane, Fs the sampling frequency, Fc the critical frequency, and f representing frequency in the z-plane, the relationship between s-plane and z-plane frequencies is 2πf = Ktan(πF/Fs) where K = 2πFc/tan(πFc/Fs). Clearly, when F = Fc, f = Fc. Thus, the role of the critical frequency is to serve as a fixed point in the mapping of die F axis into the f axis. Experience has shown that picking a critical frequency which is near the center of the frequency region of interest is a good choice. The difference between the magnitude response of the s-plane transfer function and the z-plane transfer function is usually negligible, except near the Nyquist frequency, Fs/2. The bilinear-z mapping tends to add one or more zeroes at Fs/2 in order to restrict the signal spectrum, and thus avoid aliasing distortion. B.5 Converting a Block Diagram The SPROCbuild utility provides a set of software modules that automatically converts one's design into SPROC description language (SDL) code, then uses that code to generate a configuration file for the SPROC chip and a table of symbolic references to chip memory locations. To create these files, the utility uses files produced by the SPROCview graphical design interface, the SPROCcells function library, and the SPROCfil filter design interface in the development system, and user-defined cells and transfer functions of the proper form created outside the development system. The SPROCbuild utility includes three modules: MakeSDL, Schedule, and MakeLoad. Each module performs a unique function in the process of converting the signal flow block diagram and associated files into SDL code and then into a SPROC chip configuration file and a symbol file for the design. The development system shell begins the conversion process by issuing an invocation command to the MakeSDL module. When that module is complete, the shell invokes the next module in the process, until all modules have been called and completed or an error occurs. The invocation command for each module has a set of command line switches that determines how the module functions. The conversion process comprises the sequential execution of all modules of the SPROCbuild utility. Each module performs its specific function in the process and produces an output file (or files) required by the next module. The general process is as follows: 1. The MakeSDL module integrates the output from the graphical design interface with data files from the filter design interface and user-defined transfer functions to produce a partial code package containing SDL code and data files. The module also generates instances of certain special cells to implement filter and transfer function cells. These cells are included in the SPROCcells function library but reserved for internal use. 2. The Schedule module takes the files produced by MakeSDL and adds the code blocks for the cells used in the design (from the function library or user-defined cells) and any data files required in addition to those included in the partial code package obtained from MakeSDL, Then die Schedule module schedules the code according to on-chip resource availability and adds special "glue" cells called phantoms that provide control and synchronization functions for the general signal processors (GSPs) on the chip. These cells are included in the SPROCcells function library, but reserved for internal use. The Schedule module produces binary program and data files for the design. It also produces a file of symbolic references to chip memory locations. 3. The MakeLoad module takes the binary program and data files produced by Schedule and packages them into a configuration file for downloading to die chip. B.6 The MakeSDL Module The MakeSDL module takes the basic files that capture and define the signal processing design and converts them into a format that the Schedule module can use. The MakeSDL module takes die following input files: The netlist, mydesign.net, created from the signal flow block diagram in the graphical design interface (where mydesign is the design name). This input is required. The filter data file (or files), filtname.fdf, produced by the filter design interface (where filtname identifies the filter and matches the name specified in a parameter of the filter cell instance on the block diagram). This input is conditional, depending on the design. The transfer function file (or files), transname.tff, created using a text editor (where transname identifies the transfer function and matches the name specified in a parameter of the transfer function cell instance on the block diagram). This input is conditional, depending on the design. Internal reserved cells included in the function library and used for special functions (i.e., to implement filters and transfer functions). This input is required. and produces the following output files: mydesign. sdl, a partial SDL code package that corresponds to the functions noted in the netlist and filter and transfer function definitions. This output is always produced. data files containing the parameters and coefficients noted in the netlist and filter and transfer function definitions. This output is conditional, depending on die design. In addition, the MakeSDL module produces a dependency check file, mydesign.spf, that the development system shell uses to determine which files must be created or updated by the SPROCbuud utility. For some signal processing functions, like filters and transfer functions, the MakeSDL module internally inserts instances of special function cells into a design to implement the function defined by die designer. Thus, a filter cell instance on a signal flow diagram might be implemented as several automatically generated internal filter cells. All internally inserted cells that implement filters and transfer functions are integrated into the SDL code package and converted into the file, mydesign.sdl. B.7 The Schedule Module The Schedule module takes the partial SDL code package produced by the MakeSDL module and integrates the code blocks for all necessary functions to form a complete SDL code package. It also collects all necessary data files. Then die module determines die appropriate order in which to run the code, calculates the chip resources required, and inserts the necessary phantom cells to glue me design togeuier. Then the module converts the code package into a binary program file containing executable instructions, and an associated data file. The Schedule module takes the following files as input: mydesign.sdl, produced by the MakeSDL module; the data files produced by die MakeSDL module; any additional data files; die SDL code blocks for function cells, function.sdl, supplied in the function library or created by the user (where function is the name of an individual signal processing function cell) and produces the following files as outputs: mydesign.spp, the binary program file and mydesign.spd, the associated data file. In addition, the Schedule module produces the symbol file (mydesign.sps) containing a table of symbolic references to SPROC chip memory locations. B.8 The MakeLoad Module The MakeLoad module packages the program and data files produced by die Schedule module into a configuration file for the SPROC chip. Depending on how die MakeLoad module is invoked, it can produce a configuration file in any of the following formats: a load file in modified Motorola s-record format for downloading to die chip via die SPROCdrive interface software and die SPROCbox interface unit; a PROM file in Motorola s-record format for burning into an EPROM; a blockfile containing an initialized array of data for downloading to the chip via a microprocessor. The MakeLoad module takes die following files as input: mydesign.spp, produced by the Schedule module mydesign.spd, produced by die Schedule module and produces the following types of configuration files (depending on command line switch settings): a load file, mydesign od; a PROM file, mydesign.pro; and a block file, mydesign.blk. B.9 Loading and Running a Design The SDI software uses a command-driven user interface witii a prompt line to enter SDI commands. The SDI user interface supports the entry of multiple commands on one command line, the use of command files, and the use of function keys as shortcuts for entering some commands. One can specify definitions for most function keys, and some function key definitions are provided with the SDI software. Certain function keys are reserved and may not be user- defined. SDI uses the load file produced by die MakeLoad module of die SPROCbuild utility. This file includes the program that will execute on the SPROC chip and die data associated with that program. The load file represents the signal processing design specified by the designer using die graphical design interface and filter and transfer function definitions, all packaged in a format that can be downloaded to the chip by die SDI software dirough the SPROCbox interface unit The symbol file produced by the Schedule module of the SPROCbuild utility includes symbolic references to on-chip memory addresses diat correspond to specific nodes and wires in the signal processing design. When die symbol file is loaded into host memory, the SDI software allows the user to monitor and modify the values stored at various on-chip memory locations by accessing their symbolic names. SDI also supports access to on-chip memory locations using direct memory references to addresses. The SDI software provides two operating modes: normal and expert. Both modes support interactive modification and debugging of a design while it runs on the chip, but they provide different levels of debug functionality. In normal mode, the user has access to the design's data space only and can modify signal and parameter values, but cannot modify the actual program. In expert mode, the user has access to program and control space in addition to data space, enabling halt and restart design execution, set breakpoints, and modification of die design running on the chip at assembly level. . The symbol file contains a specification of data type for each symbol. Data types may be integer, fixed point, hexadecimal, or undefined. SDI commands are sensitive to the data types of symbols when accessing memory values using symbolic names. In general, SDI commands display values for addresses accessed by their symbolic names using die data type defined in the symbol file. However, some SDI commands allow the user to specify a display format (integer, hexadecimal, etc.) that may differ from the symbols data type. In addition, the mode command allows the user to specify a display format for values accessed by direct memory reference, and for symbolically accessed values for which the symbol file data type is undefined. SDI provides several methods to access the values stored in SPROC chip memory locations. The commands read and probe allow the user to view the value of a given memory location, either by accessing it directly by address or symbolically by symbol name. The read command displays the value on die screen, and the probe command directs die value to the software-directed probe for display on an oscilloscope. The write command allows the user to modify the value of a given memory location. Depending on the SDI operating mode, the user can access data memory locations corresponding to inputs, outputs, and parameters for cells included in your signal flow block diagram, program memory space, and control memory space. The symbol file includes symbolic names for all SPROC memory addresses. The symbol file provides a hierarchical structure that uniquely identifies nodes and attributes of all cell instances in a signal processing design. In addition, die address for a node or attribute is saved in die symbol file along with its symbol name, so that the symbol file comprises an address map of the symbol names for all nodes and attributes in die design. Levels of hierarchy in symbol names are separated by a dot (.) character. For example, in the symbol name ampl.gain, ampl is the amplifier cell that contains die specific attribute (gain) named by the symbol. Some nodes and attributes can be referenced by multiple symbols (or aliases). For example, a wire that connects two cells is both the output of the first cell and the input of die second. In addition, a label may be specified for die wire. All three symbols, for the output of die first cell, the input of die second cell, and the label for die wire, refer to the same node on die design and to the same location in SPROC chip memory. When such aliases are translated, die symbol translator ensures that all aliases for a symbol refer to the same location in SPROC chip memory. The probe command probes any signal corresponding to a location in the SPROC chip data RAM. The user can examine the values of the inputs and/or outputs for each cell in the signal flow block diagram. In addition, die user can probe all of the internal signals for any cell in the diagram tiiat the SPROCbuild utility implements as a combination of cells. For example, if the signal processing design includes a filter that is sixtii order, the SPROCbuild utility will have cascaded three biquad sections; if eightii order, then four biquad sections. The user can use die probe command to access the outputs — and hence die inputs — of each biquad section even though the individual biquad sections were internally generated cells that do not appear on the signal flow block diagram. In fact, the user could view all of the signals tiiat are internal to each biquad. In the current hardware implementation of the software-directed probe, values accessed using the probe command are made available as output from an on-chip, 8-bit, digital-to-analog converter (DAC). Note that there is a discrepancy between the 24-bit wordlength of SPROC chip memory values and the 8-bit wordlength of the probing DAC. To counter this disparity in wordlength, the probe command supports specification of a scale factor to scale up the input to the probing DAC by as much as 15 bits (215). This provides probe access to low-level signals. B.10 Using the Micro Keyword When using the SPROC chip as a memory-mapped device in a microprocessor application, the microprocessor can only access cells that include a micro keyword in die cell definition code block. This keyword identifies die variables in die cell tiiat are available for microprocessor access. Cells that do not include tiiis keyword cannot be accessed by a microprocessor. The following definition code block for a sink cell illustrates the use of the micro keyword: asmblockmsink {%subr==default, %length=128] (in;) verify (%length>0 && %length<=512), 'Specify length in range 1 to 512.'; variable integer ptr=outvector micro variable outvector[%length]; begin //code here end The definition of outvector is micro variable outvector[%lengdι]. The micro keyword identifies die variable, outvector[%lengdι], as available for access from a microprocessor. The micro keyword can also be used for inputs and outputs. For example, in a sink cell with the following reset and done inputs: asmblock msinkrd {%subr=default, %length=128) (in, micro reset; micro done) The micro keyword defines the interface between the microprocessor and the reset and done inputs of die msinkrd cell and is used to identify only those variables that must be available to the microprocessor. B.l 1 Using a Listing File A listing file can be used to verify cells. It consists of a listing of the source input and die hexadecimal codes for corresponding data and program locations. The user can produce a listing file by invoking the SPROCbuild utility's Schedule module directly from DOS, using the invocation command line switch -1 and specifying the input source file. Because die listing file is generated at compile time, outside die context of a particular instantiation of an assembly language block, it cannot include any data that is not known before the block is instantiated, i.e., any data tiiat must come from a parameter value of a cell instance. For example, if a parameter used in die calculation of an operand value has no default value, then it cannot be known until the block is instantiated. For such operands, the operand field of the instruction is left zero, and a question mark (?) is placed immediately after. The question mark indicates that the operand value is unknown at this time. On the other hand, if a default for die parameter value has been specified, then this value is used for die instruction, and no question mark is added. Similarly, absolute addresses for instruction jumps and relocatable data references cannot be known at compile time. Whenever such an address is encountered as an operand, its absolute address with respect to the start of die block is used, and an apostrophe (') is placed immediately after. The apostrophe indicates that die address operand will be relocated. B.12 Using Subroutines Most cells in the SPROCcells function library include both in-line and a subroutine form code. When a cell instance occurs with the in-line form specified, the instructions for die function are instantiated as one piece of code, along with associated variable allocations. When a cell instance occurs with the subroutine form specified, the instructions for the function are instantiated as two pieces of code: one as a call block, and one as a subroutine body block. (Each piece of code may have associated variable allocations.) When subsequent instances of the same cell are specified witii die subroutine form, only the call block, i.e., the piece of code necessary to call the subroutine body block, is instantiated. Only one instance of the subroutine body block is instantiated, no matter how may times die subroutine version of die cell appears in a design. For example, if five subroutine versions of a particular cell are used in one design, die design will include five call blocks for that function, and one subroutine body block. The subroutine form of a cell performs a function identical to die corresponding in-line form, but includes overhead instructions that make the code in the subroutine body block re¬ entrant. The use of subroutine versions of cells provides a savings in die number of lines of code used in a design, but requires increased execution overhead. This overhead causes an increase in cell duration. In general, use of subroutines requires a trade-off of program speed for a savings in program and data memory space. For example, consider five instances of a sine oscillator function (sine_osc cell) in a design. The in-line form of this cell includes 47 lines of code. Five instantiations of the in-line form require a minimum of 5 x 47 = 235 locations in program memory space, and 5 x 9 = 45 locations of data (variable) memory space. Duration for each instance of the in-line form is 45 cycles, for 5 x 45 = 225 total cycles. By contrast, five instantiations of the subroutine form require five call block segments (3 lines each), one subroutine body block (47 lines), for (5 x 3) + 47 = 62 locations of program memory space. Each call block uses five locations of data space, and die subroutine body block uses five locations of data space, for (5 x 5) + 5 = 30 locations of data memory space. Duration for each instance of the subroutine form is 48 cycles, for 5 x 48 = 240 total cycles. Use of the subroutine form in this example consumes only 26 percent of the program space and 67 percent of the data space required for the in-line form. However, use of the subroutine form creates a 7 percent increase in code duration. The Schedule module of the SPROCbuild utility determines whether to use die in-line or subroutine form for each cell instance in a design when it instantiates the cell instance. This deteπnination is based on two factors: The command line switch settings used in the Schedule module invocation command, and the specification of parameters in individual cell instances. As an default the Schedule module uses die subroutine form of a cell if three or more instances of that cell are used in the design. Under this condition, if a design includes four sine oscillator cell instances, all four are instantiated in subroutine form. A command line switch in the Schedule module invocation command allows the user to specify a direshold, subrcount tiiat triggers the module to use the subroutine form of default cells. The subr= parameter allows the user to specify whether the subroutine form should be used for a specific ceR instance. If the parameter is specified as subr=ON for a cell instance, the Schedule module uses the subroutine form when instantiating that cell instance. If die parameter is specified as subr=OFF for a cell instance, the Schedule module uses the in-line form when instantiating mat cell instance. The Schedule module does not count cell instances witii die subr= parameter set when it evaluates whether the number of default cell instances has passed the tiireshold. Although most cells include code in botii in-line and subroutine forms, some cells include only the in-line form. If the subr= parameter is specified for a cell that does not include subroutine form code, the cell is instantiated in in-line form. B.13 Using Time Zones A time zone is a slice of time particular to a logical partition of operations on the SPROC chip. A time zone can contain any number of operations, up to the bandwidth limitations of die chip. A design may contain any number of independent time zones, up to the bandwidth limitations of the chip. Sets of operations that occur along the same logical wire (serial data path) in a design occupy the same time zone. This is analogous to die physical notion of time division multiplexing, where witiύn a particular slice of time, anytiiing can be accomplished so long as it does not take longer than the length of the time slice. In time division multiplexing, specific time slices are allotted to specific operations, so that a given operation can only be performed in its assigned time slice or number of time slices. Operations that require longer than the length of one time slice must be completed over multiple time slices allotted to tiiat operation. In die same way tiiat time slices are allotted to operations performed under a time division multiplexing scheme, several operations in cascade are related to a particular time zone on die SPROC chip. Only during the time allotted to a particular time zone can operations associated with that time zone be performed. The SPROC chip and die development system tools are very flexible in the structuring of time zones. Essentially, the user can specify time zones using any combination of alphanumeric characters. There is no logical limit to the number of time zones specified for operations. The only restriction on the number of independent time channels through which operations can be performed is determined by the bandwidth limitations of die chip. Consider a design in which four filters, each on an independent channel, must operate on a SPROC chip witii four GSPs, and each filter uses one complete GSP. Such a design requires four time zones. To determine die maximum sample rate for each of die time zones, consider a 20 Mhz SPROC chip operating each GSP at 4 MI-PS. The two serial ports on the chip have access to memory every 70 clock cycles, meaning that each channel can get samples at a rate of 70/20 x 10^ = 3.5μs. Therefore, each time zone has the capacity of 2 x 4 MIPS x 3.5 μs = 28 GSP instructions, because each time zone has an entire GSP allocated to it. (The factor of two at the front of die last equation is due to the fact tiiat one channel will service two GSPs in an equal fashion for tiiis example.) Considering all of die above figures, we see tiiat each channel (or time zone) will be a total of 7 μs in lengdi. B.14 Summary Turning to Figure 10, a flow diagram of die SPROC and microprocessor development environment is seen. At 2010, using graphic entry packages such as "Draft", "Annotate", "ERC" and "Netlist" which are available from OrCad in conjunction with cell library icons such are provided from a cell library 2015 , a block diagram such as Figure 11 is produced by the user to represent a desired system to be implemented. The OrCad programs permit the user to draw boxes, describe instance names (e.g., multiplier 1, multiplier 2, etc. such as seen in Fig. 11 as MULT1, MULT2,...), describe parameters of die boxes (e.g., spec = filter 1; or upper limit = 1.9, lower limit = -1.9 such as seen in Fig. 11) and provide topology (line) connections. The output of the OrCad programs is a netlist (a text file which describes die instantiation, interconnnect and parameterization of the blocks) which is fed to a program MakeSDL 2020 which converts or translates the netlist output from OrCad into a netlist format more suitable and appropriate for the scheduling and prograπiming of die SPROC. Source code for MakeSDL is attached hereto as Appendix A. It will be appreciated tiiat a program such as MakeSDL is not required, and that the netlist obtained from die OrCad programs (or any other schematic package program) can be used directly. As seen in Fig. 10, a complex filter design package program such as is available from DisPro is preferably provided at 2030. The filter design package permits high level entry of filter parameters and automatically generates coefficients for the provided design. The output of die filter design package is a filter definition file which is also sent to MakeSDL. MakeSDL effectively merges the information being provided by the filter design package with instances of filters contained in the netlist to provide a more complete netlist. In addition, MakeSDL further merges transfer function files provided by the user to parameterize a block into the netiist MakeSDL outputs SDL (SPROC description language) netlist files and data files. The data files represent data values which are intended for die SPROC data RAM and which essentially provide initial values for, e.g., filter coefficients and source blocks. For functions not located in die cell library, a text editor 2035 can be used to generate appropriate SDL and data files. Those skilled in die art will appreciate that any text editor can be used. What is required is that die output of die text editor be compatible witii the format of what die scheduler/compiler 2040 expects to see. Both the netlist and data files output by the MakeSDL program are input to a scheduling compiling program as indicated at 2040. In addition, a cell library 2015 containing other SDL files are provided to enable the scheduler/compiler to generate desired code. Among the signal processing functions provided in the cell library are a multiplier, a summing junction, an amplifier, an integrator, a phase locked loop, an πR filter, a FIR filter, an FFT, rectifiers, comparators, limiters, oscillators, waveform generators, etc. Details of the scheduler/compiler are described in more detail hereinafter, and source code for the scheduler/compiler is attached hereto as Appendix M. The output of the scheduler/compiler contains at least three files: the .spd (SPROC data) file; the .spp (SPROC program) file; and the .sps (SPROC symbol) file. The SPROC data file contains initialization values for the data locations of the SPROC (e.g., 0400 through ffff), which data locations can relate to specific aspects of the SPROC as discussed above with reference to the SPROC hardware. The SPROC program file contains the program code for the SPROC which is held in SPROC program RAM (addresses 0000 to 03ff) and which is described in detail above with reference to the SPROC hardware. The SPROC symbol file is a correspondence map between SPROC addresses and variable names, and is used as hereinafter described by the microprocessor for establishing the ability of the microprocessor to control and/or communicate with the SPROC. If desired, the scheduler/compiler can produce other files as shown in Fig. 10. One example is a .spm file which lists the full file names of all included files. As aforementioned, the scheduler/compiler produces a symbol file (.sps) for use by the microprocessor. Depending upon the type of microprocessor which will act as a host for the SPROC, the symbol file will be translated into appropriate file formats. Thus, as shown in Fig. 10, symbol translation is accomplished at 2050. Source code in accord with the preferred embodiment of the invention is provided in Appendix C for a symbol translator which translates the .sps file generated by the scheduler/compiler 2040 to files which can be compiled for use by a Motorola 68000 microprocessor. In accord with the preferred embodiment, the symbol translator 2050 generates to files: a .c (code) file, and a .h (header) file. The code file contains functions which can be called by a C program language application. The header file contains prototypes and symbol definitions for the microprocessor compiler hereinafter described. Returning to the outputs of die scheduler/compiler 2040, the data and program files are preferably fed to a program MakeLoad 2060 (the source code of which is provided as Appendix D hereto. The MakeLoad program merges die .spp and .spd into a file (.blk) which is in a format for the microprocessor compiler and which can be used to initialize (boot) the SPROC. Of course, if desired, die .blk file can be loaded directly into a microprocessor if the microprocessor is provided witii specific memory for that purpose and a program which will access that memory for the purpose of booting the SPROC. The Makeload program also preferably outputs another file .lod (load) which contains die same information as the .blk (block) code, but which is used by the SPROCdrive interface 2070 to boot the SPROC in stand-alone and development applications. Details regarding the SPROCdrive interface are discussed below. Another input into the SPROCdrive program is the symbol file (.sps) generated by the scheduler/compiler 2040. This allows the SPROCdrive program to configure the SPROC and control the SPROC symbolically. In particular, if it was desired to read the output of a particular block, a command "read blockname.out" can be used. The .sps file then provides the SPROC address corresponding to the symbol blockname.out, and die SPROCdrive interface tiien sends a read and return value command to the SPROC 10 via the SPROCbox 2080. The function of the SPROCbox is to provide an RS232 to SPROC access port protocol conversion, as would be evident to one skilled in die art. C. SPROC Description Language C.1 Overview of SDL SPROC description language (SDL) is the language used to create high-level descriptions of arbitrarily complex signal processing systems to be implemented on die SPROC programmable signal processor. SDL is a block-oriented language that supports heirarchical designs. Blocks may be eitiier primitive or heirarchical. Primitive blocks also called asmblocks contain hardware-specific coding analogous to the firmware in a microprocessor system. Primitive blocks are written in assembly language. They may not contain references to otiier blocks. Code for signal processing functions is written at the primitive level. These primitive blocks comprise the SPROCcells function library. They are optimized for the hardware and efficiendy implemented to extract maximum performance from the SPROC chip. Other primitive blocks include die glue blocks or phantoms required to provide control and synchronization functions for the multiple general signal processors (GSPs) on the SPROC chip. Hierarchical blocks contain references to other blocks, either primitive or hierarchical. The sequence (i.e.,firing order) and partitioning (i.e., allocation over the GSPs and insertion of phantom blocks) of the referenced blocks in a hierarchical block is automatically determined. A hierarchical block that is not referenced by any otiier block is a top-level block. There must be one and only one top-level block in a design. Two types of special-purpose hierarchical blocks are also available: sequence blocks and manual blocks. A sequence block is a hierarchical block that is not automatically sequenced. The order of the references contained in a sequence block specifies die firing order of the referenced blocks. A manual block is a hierarchical block that is neither automatically sequenced nor partitioned. As witii the sequence block, the order of block references in a manual block specifies the firing order of referenced blocks. In addition, referenced blocks are not partitioned, and no phantom blocks are inserted. A block contains a block name, block definition, and block body. The block name identifies the block for reference by hierarchical blocks. The block definition contains an optional list of parameters; a port list declaring the block's input and output signals; optional general declarations for wires, variables, symbols, aliases, time zones, compute lines, and ports; optional verify statements; and optional duration statements (primitive blocks only) The block body contains references to other blocks O ierarchical blocks only) or assembly lines (primitive blocks and manual blocks only). C.2 Compiling SDL Files SDL files are compiled by the SPROCbuild utility in the SPROClab development system. The utility includes three modules: the MakeSDL module, the Schedule module, and the MakeLoad module. The MakeSDL module prepares a top-level SDL file that completely describes die signal processing design using die netiist of the signal flow block diagram, primitive blocks from die function library, and otiier code and data files The Schedule module takes the top-level SDL file and breaks the file apart based on the resource and synchronization requirements of the blocks within the file. Resource requirements include program memory usage, data memory usage, and GSP cycles. Synchronization requirements include the determination of how and when blocks communicate data, and whether a block is asynchronous and independent of other blocks in the design. After breaking up the file to accommodate resource and synchronization requirements, the Schedule module partitions the file by blocks and locates die blocks to execute on the multiple GSPs on the SPROC chip using a proprietary partitioning algorithm. The module inserts phantom blocks as necessary to control the synchronization of the GSPs as tiiey execute die design. Then the Schedule module generates a symbol table file that lists the physical RAM addresses on the SPROC chip for all the parameters, variables, and other elements in the design. The MakeLoad module converts the partitioned SDL file into a binary configuration file to run on the chip. C.3 Concepts and Definitions This subsection provides an alphabetical listing of various concepts and definitions used in SDL. Aliases: An alias maps a new identifier to another existing identifier. Aliases are declared using alias statements. These are more restrictive than symbol declarations, since the translation must be an identifier, not an arbitrary expression. Alias translation is done before any other translation. Data Types: The type of a variable or wire may be FLXED (fixed point), INTEGER (integer), and HEX OJexadecimal). FIXED type specifies a fixed-point representation of a number in the range of -2 to 1.999999762. FIXED type is the data type native to signals in the SPROC chip. Expressions: An expression is a statement of a numerical value. An expression can be simply a number or identifier (like a register name), or a combination of numbers, symbols, and operators that evaluates to a numerical value. Expressions in a block are evaluated when the block is instantiated. Expressions may be used wherever a number is required. The operand field of most instructions may contain an expression. Initial values for variables may be declared as expressions. The table below lists the valid operators tiiat may be used in expressions. Expressions may include identifiers, like parameter names, symbols, and variable, wire, or port names. When translating identifiers to evaluate an expression, if the identifier cannot be found in the current block instance, block instances in successively higher levels are searched until die identifier is found. The identifier is evaluated in the context of the block instance in which it is found. Numbers used in expressions may be real, integer, hex, or binary numbers. An expression containing a real number evaluates to a real number and may be assigned to the FLXED data type. An expression containing no real numbers (only integer, hex, or binary numbers) evaluates to an integer number and may be assigned to an INTEGER data type. An expression must evaluate to a value within die range allowed for the data type of die variable or operand to which it is being applied. Identifiers: An identifier is any series of characters chosen from the following sets: first character — A-Z, a-z, $, %, _ , and subsequent characters — A-Z, a-z, $, %, period (.), 0-9 Labels: A label is a special identifier used for a line of assembly code (asmline). An asmline may begin witii a label followed by a colon; tiiis specifies the label as the identifier for the asmline. Anotiier asmline may use a jump instruction witii die label as an operand to cause die GSP to jump to die memory location associated witii die labeled instruction. A label for an asmline is optional and must start with an alphabetic character and be followed by a colon. Labels are case sensitive, so that XXX and Xxx are two unique labels. Numbers: Numbers may be integer, real, hexadecimal, or binary. Numbers must begin with a digit (0 tiirough 9) or a negative sign (-). Numbers containing a decimal point (.) are real, and may optionally include an exponent, using e or E optionally followed by a signed integer. Hexadecimal number must begin with a digit (0 through 9) and end with a letter H (capital or lower case). Binary numbers must begin witii a digit (0 or 1) and end witii a letter B (capital or lower case). Opcodes: An opcode is an alphanumeric code that specifies an assembly instruction from die GSP instruction set. Opcodes entered in asmlines must be in lower case. Operands: An operand is an expression that specifies the source or destination of an instmction. An operand is present only when required by the specified instruction. An operand can be a simple register identifier, a label, or an expression that evaluates to a specific address. Parameters: A parameter is an identifier or string tiiat provides a means of customizing an occurrence, or instance, of a block. Parameter values may be passed by a hierarchical block to a lower level hierarchical block. They can also provide immediate values and array sizes for primitive blocks. Parameters are declared in the optional parameter listing for a block. A default value for a parameter may be declared-When a block is instantiated, any parameter values supplied for the instance override the default values. Parameters reserve no storage. Parameter names should begin with a percent sign (%). Registers: Registers can serve as source or destination operands for instructions. Registers that may only be read by an instruction are source only registers. Registers that may be read or written by an instruction are source/destination registers. Register names used in operand fields must be all upper case. Strings: A string is a series of characters enclosed within single or double quotes. If the string is enclosed witiiin single quotes, the single quote character is illegal within the string. If the string is enclosed within double quotes, the double quote character is illegal within the string. Symbols: A symbol is a series of characters (an identifier or a string) that names an expression. The symbol for an expression may be used in other expressions. Appropriately chosen symbol names may be used to make SDL code more readable. Symbols are declared using symbol statements. Symbols may be used within blocks as an initial value for a variable or wire, for example. A symbol may also be passed via a parameter value assignment to an instance within a hierarchical block. Time Zones: A time zone declaration is required for every signal source block, like the primitive block for a signal generator function, or a serial input port function. The time zone statement declares a time zone name for die block, and optionally, a sample rate for that zone, in samples per second. A sample rate need only be given in one such time zone statement of multiple blocks that declare the same time zone name. The time zone name is used to determine synchronization requirements of blocks. Time zones which have different names are taken to be asynchronous, even if they have the same sample rate. Variables: Variables are declared using variable statements. Variables may be declared for hierarchical or primitive blocks. A variable may be declared, and an initial value for the variable may also be declared. The value may be a number (or expression) or a string (or an expression witii no value assigned to it) that identifies a file containing the initial values for the variable. If the string (file name) entered as die value for a variable includes a period (.), it must be enclosed in single or double quotes. Numbers in the file must be dehmited by spaces, tabs, or new lines, and may be real, hexadecimal, integer, or binary numbers. If die file contains fewer values than are required by the variable, any missing values are zero filled. Variables may be scalar or dimensioned as single-dimension arrays. If an initial value is declared as a number (or expression) tiiat value is duplicated for array variables. Wires: A wire is a signal between primitive blocks in a design. Wires are declared using die wire statement. Wires may be declared in hierarchical blocks only. A wire may be declared, and an initial value for the wire may also be declared. The value may be a number (or expression) or a string (or an expression with no value assigned to it) tiiat identifies a file containing the initial value for the wire. The wire value is by default type FIXED. Wire values are scalar only. C.4 Rules for Creating Asmblocks 1. Keep state information for asmblocks in variables, not in outputs. Output values are not necessarily maintained between successive calls of an asmblock. 2. Place the assembly code for each asmblock in a separate file unless the asmblock is purely local to another block and is only called by tiiat block. The file name must be the same as die asmblock name defined in die asmblock header, and it must have the extension, .sdl. 3. System identifiers begin witii the prefix _% (underscore percent sign). Do not begin identifiers with these characters. 4. Begin parameter names with a percent symbol (%). 5. Write the output of a block to memory each time the block is executed. The software- directed probe used for debug is triggered by writing block output to memory, and will not function properly if blocks are executed without their outputs being written to memory. 6. Enter opcodes in assembly lines in lower case. 7. Enter register names used as operands in assembly lines in upper case. C.5 Asmblock Structure Each asmblock includes a header called an asmblock_header, optional declaration statements, and the body of die asmblock containing assembly instructions, or asmlines, as follows: asmblockjieader optional declaration statements chosen from: Duration Variable Verify Symbol begin body, composed of zero or more asmlines end The asmblock header (asmblock_header) marks the start of an asmblock definition. It identifies die name of the asmblock and includes optional listings for the parameter characteristics and I/O of die asmblock. An asmblock header must have the following format: asmblock name [{L%parameterL=expression] [, %parameterL=expression]...]]}] L{[in L, in ...]] ; Lout [, out „.]]}] where the name identifies the asmblock. (An asmblock name must be included in the asmblock header.) The parameter listing defines characteristics such as initial values that can be referenced by the assembly code appearing later in the body. When an asmblock is instantiated, any parameter values supplied for the instance override die default values set in die parameter listing. The parameter listing is optional and must be included between braces ({ } ) if present. Zero or more parameters may be included between the braces; multiple parameters must be separated by commas. A parameter may be an identifier or string. A parameter can be followed by an equals sign and a default value expression. Parameter names should begin witii a percent sign (%). The I/O listing defines me input and output arguments of the asmblock. The I O listing is optional and must be enclosed in parentheses if present. Inputs are type INPUT and identify starting values. Outputs are type OUTPUT and identify results. (No type INPUT is allowed.) Botii the input and output sections are made up of zero or more identifiers separated by commas. The input section must be separated from the output section by a semicolon. An output section may have an expression declared for it to provide an initial value. This is useful when the initial state of a signal is important. The keyword micro may be added to the declaration for any input or output of an asmblock. The keyword must precede die identifier in the appropriate section of the I/O listing. This keyword makes the tagged input or output available for access from a microprocessor for applications using the SPROClink microprocessor interface (SMI) software. After the asmblock header, die asmblock may include any combination of zero or more of the following optional declaration statements: Duration, Symbol, Variable, Verify. The duration statement has the format: duration integer_expression; A duration statement declares the maximum number of cycles required to execute the asmblock code. A duration statement is required for all asmblocks that have backward branches, and therefore may loop. If no duration statement is present, a duration for the asmblock is computed assuming that every instruction in the asmblock code will be executed. An integer_expression is an expression that must evaluate to an integer value. The symbol statement has the format: symbol [micro] identifier=expression [, [micro] identifier=expression ...]; or symbol [micro] string=expression [, [micro] string=expression ...]; A symbol statement defines a symbol name for use in expressions. The optional micro keyword makes the symbol available for access from a microprocessor for applications using SMI. The variable statement has the format: variable [micro] [type] identifier [[size]] [=expression] [, [micro] [type] identifier [[size]] [expression] ...]; The variable statement defines storage locations which may optionally be initialized. The micro keyword makes the variable available for access from a microprocessor in applications using SMI. A type specifier defines die type of the variable and must be compatible with the expression, if present. Type can be FIXED, INTEGER, or HEX. FIXED indicates SPROC chip fixed point; INTEGER indicates a base 10 value; and HEX indicates a base 16 value. A size qualifier is used to declare vectors. If present, it must be an integer expression enclosed in square brackets ([ ]). The verify statement has the format: verify expression; or verify expression string; The verify statement defines a check to be performed by die Schedule module of the SPROCbuild utility. The expression is evaluated and compared to zero. If non-zero, an error message will be generated. If string is present, it will be output as the error message. If no string is present, the failed expression will be expanded into English and presented. Verify statements should be used to check that parameter values lie within an acceptable range. Parameter values may come from the parameter list in the asmblock, or from a hierarchical block that references the asmblock. The asmblock body contains the code tiiat specifics operating instructions. The asmblock body includes die begin keyword, the asmlines, and the end keyword. An asmline includes a single assembly instruction for the SPROC chip's general signal processor (GSP). This instruction may be in the form of an opcode, a label, or a label and an opcode. An asmline must have the following format: [LABEL:] [OPCODE] LOPERAND] where LABEL followed by a colon is an identifier for the asmline. A label is optional and must start with an alphabetic character and be followed by a colon. Labels are case sensitive, so that XXX and Xxx arc two unique labels. OPCODE is an alphanumeric code that specifies an assembly instruction from the GSP instruction set. An opcode is optional. Opcodes entered in asmlines must be lower case. OPERAND is an expression that specifies the source or destination of the instruction specified by an opcode. An operand is present only when required by the specified instruction. Any asmline can be terminated by a semicolon. The semicolon is optional and has no meaning; it is purely stylistic. Comments may be included in any asmblock as separate comment lines, or they may be included within any otiier line in the asmblock. When comments are included as separate lines in an asmblock, each comment line must be introduced by the comment characters (//). When comments are included within another line in the asmblock, they must either be enclosed between delimiting characters (/* and */), as in the C language, or appear at the end of the line and be preceded by the comment characters (//). C.6 SPROC Chip Architecture, Instmctions and Registers The instraction format for program ram is shown in the table below: Total Width 24 bits Opcode 6 bits Operand 15 bits Address mode 3 bits, eight modes The data format is shown in the table below: Total Width 24 bits Range fractional -2 to +1.999999762 Code OQ.22, 2's complement with 22 bit fraction The multiplier format is as follows: Input registers 24 bits Output register 56 bits including 8 bits of overflow protection The basic GSP instruction set is listed in the table below: OPCODE OPERAND DESCRIPTION TYPE add source Add without carry. Load operand into ALU and sum with contents of accumulator. Result is stored in the accumulator adc source Add witii carry. and source AND contents of accumulator with operand. Result is stored in accumulator. asl none Aritiimetically shift the accumulator contents 1 bit to the left and store the result in the accumulator. The most significant bit (msb) is shifted into the carry bit C and a zero is shifted in the least significant bit (lsb) of the accumulator. asr none Arithmetically shift the accumulator contents 1 bit to the right and store the result in die accumulator. The lsb is shifted into the carry bit C, and the msb is held constant, (sign extended). Clear carry bit of status register. Compare operand with accumulator contents and update die status register. Accumulator is unmodified by a compare instruction. Test loop flag, jump not equal to zero to specified operand address, then post decrement loop register. Unconditional jump to operand address in die program RAM. Execution continues from the operand address. Jump on condition code true. xx CONDITION TRUE CONDITION cc Carry Clear ~CF execute the multiply/accumulate operation which adds die multipUcation result to the contents of the M register. There is a two cycle latency before the result is available. The X register can be loaded with a new value during this two cycle period. mpy source Load Y register of multiplier with operand value, and execute the multiplication operation, placing the result in the M register. There is a two cycle latency before the result is available. The X register can be loaded with a new value during this two cycle period. nop none No operation. not none Perform a one's complement of accumulator. Result is stored in die accumulator. ora source OR contents of accumulator witii operand. Result is stored in accumulator. Rotate accumulator contents left 1 bit tiirough carry. Rotate accumulator contents right 1 bit tiirough carry. Set carry bit of status register. Store contents of register (r) at destination address. sub source Subtract without carry. Load operand into ALU register and subtract from accumulator. Result is stored in the accumulator register. subc source Subtract with carry. xor source Exclusive OR contents of accumulator with operand. Result is stored in accumulator. The following instructions have restrictions: INSTRUCTION RESTRICTION djne If the starting value placed in the D register is odd, and the decrement is an even value, this instruction can result in an endless loop. str This instruction cannot use immediate addressing. This instruction cannot use register addressing. For register to register "storing", use ldr. Privileged instmctions, reserved for special purposes, are listed below. These instmctions are available but intended solely for use during debug via the SPROCdrive interface (SDI) software using die SPROCbox interface unit. Do not use these instmctions in asmblocks. INSTRUCTION OPERAND DESCRIPTION lbsj source Load BS and jump. Load the program counter plus one and die condition codes into die BS register and jump to operand. ldcc source Load condition codes. Replace 4 bits of condition code register with 4 bits of operand (CF, OF, SF, ZF). xld source Load parallel port input register with contents of externally addressed memory location. The operand specifies an extemal address in the range of 0 through 64K. NOTE: This instruction alters the value in the A register. The state of the CF, SF, and ZF flags is unknown after this instruction. The following source/destination registers are provided: REGISTER FUNCTION SIZE NAME A accumulator 24 bits The break status register is a special purpose source/destination register. It holds a copy of both the program counter incremented by l and die GSP condition code flags, after a break is executed. This register is used only by die SPROCbox interface unit for debug. The bits of the break status register are defined as follows: The multiplier output register, M, is the sole source only register. The M register is a 56- bit register divided into three sections: guard; hi; and lo; tiiat are assigned individual register identifiers. In addition, each of tiiese three sections uses two different register identifiers to distinguish between integer and fixed point access modes. The source only register identifiers for die sections of die multiplier output register are listed below: ACCESS MODE SIZE fixed point 10 bits, sign extended to 24 bits MH multiplier hi fixed point 24 bits The result of an integer multiply will be found in the MLI register. The result of a fixed point multiply will be found in the MH register. All flags are initially in an undefined state until affected by an instruction. The list below shows how each flag is affected by each instruction. OPCODE FLAG NAMES CARRY LOOPING MULTIPLIER OVERFLOW SIGN WAIT ZERO (CF) (LF) ) (SF) (WF) (ZF) u u u u O u - u u u - u u - . . . . u sub U subc U xor where O means clear status flag; 1 means set status flag; U means update status flag; and - means do not change status flag Ahhough the GSPs in the SPROC chip use a 24-bit data word, an instruction opcode can only hold an immediate value of 15 bits. Immediate addressing modes facilitate left or right justification of these 15 bits when forming an immediate data word. The immediate addressing modes differ for data operands and address operands. Eight modes are supported for data operand addressing, and seven modes are supported for address operand addressing. The eight immediate addressing modes for data operands are listed below: MODE FORMAT DESCRIPTION direct XXX Use die 15-bit operand as a data memory address. The address always accesses the data memory. immediate left # < xxx Default for FIXED numbers. Take the 15-bit operand, left justify and zero fill low order bits to generate a 24-bit value for immediate use. This mode is used to represent fractional numbers. immediate right # > xxx #xxx default Take die 15-bit operand, right justify and sign extend high order bits to generate a 24-bit value for immediate use. This mode is used to represent immediate integer numbers. register sa- Source register. Use die 15-bit operand as a register identifier. base indexed B + xxx] Use die 15-bit operand as an offset to die base register (register B) to determine die data memory address. base loop [B +L + xxx] Use die 15-bit operand as an offset to die base indexed register (register B) plus die loop register (register L) to determine the data memory address. frame indexed [F + xxx] Use die 15-bit operand as an offset to the frame pointer register (register F) to determine die data memory address. frame loop [F + L + xxx] Use die 15-bit operand as an offset to the frame indexed pointer register (register F) plus die loop register (register L) to determine the data memory address. If offset is zero, +0 is optional. For jmp and conditional jxx instructions, the operand field specifies the address at which program execution must proceed, when required by the instruction. The immediate addressing modes for address operands are listed as follows: MODE DESCRIPTION direct Use the 15-bit operand as die destination address. The operand must be a relocatable LABEL; no absolute expression is allowed as the destination address. indirect The 15-bit operand, enclosed in square brackets ([ ]) points to a data memory location containing the destination address. register The specified source register contains die address. indirect base indexed Use the 15-bit operand as an offset to the base register (register B) to determine die data memory address containing the jump destination. indirect base loop Use die 1 5-bit operand as an offset to the base register (register indexed B) plus die loop register (register L) to determine the data memory address containing the jump destination. indirect frame indexed Use the 15-bit operand as an offset to the frame pointer register (register F) to determine die data memory address containing die jump destination. indirect frame loop Use the 15-bit operand as an offset to die frame pointer register indexed (register F) plus die loop register (register L) to determine the data memory address containing die jump destination. The following table lists die keywords and other reserved words in SDL. A eor jmp adc exp jne add F jov alias fix jsi and fixed jwf D. The SPROC Compiler Returning to details of the scheduler/compiler 2040, the basic function of the scheduler/compiler 2040 is to take the user's design which has been translated into a scheduler/compiler understandable format (e.g., SPROC Description Language), and to provide therefrom executable SPROC code (.spp), initial data values (.spd), and the symbol file (.sps). The preferred code for the scheduler/compiler is attached hereto as Appendix M, and will be instructive to those skilled in the art. The scheduler/compiler does automatic timing analysis of each design provided by die user, allocating the necessary SPROC resources to guarantee real-time execution at the required sample rate. In order to guarantee real-time execution, the scheduler/compiler preferably performs "temporal partitioning" (although other partitioning schemes can be used) which schedules processors in a round-robin fashion so as to evenly distribute die compute power of die multi-GSP SPROC. Each GSP picks up the next sample in turn, and executes the entirety of die code in a single time zone (i.e., that part of the user's design which runs at the same sample clock). Additional information regarding time zones can be obtained by reference to U.S. Patent #4,796,179 to Lehman et al. which provides time zones for a microprocessor based system. The scheduler/compiler 2040 also insert "phantom blocks" into the user's design which supply the necessary system "glue" to synchronize processors and input output, and mm the user's design specification into executable code to effect a custom operating system for die design. Preferred code for the phantom blocks is found attached hereto as Appendix E (Scheduler/Compiler Phantom Block Source Code). Because it is possible for a block which the user has designated to have a varying execution time, the GSPs running common code under temporal partitioning could conceivably collide or get out of sequence. Phantom blocks called "turnstiles" are inserted at every sample period's worth of code to keep die GSPs properly staggered in time. By computing and using maximum and minimum durations rather than a maximum duration and an assumed minimum duration of zero, the turnstiles may be placed to optimize the code variability. The scheduler/compiler code provided in Appendix M, however, does not optimize in this manner. Also, output FIFOs are created whose size depends on code execution time variability. These output FIFOs can also be optimized. In temporal partitioning, a GSP can overwrite a signal memory location widi its new value before the old value has been used by anodier GSP which requires tiiat value. In order to prevent diis overwriting problem, phantom blocks which create "phantom copies" of signal values are inserted. A different manner of solving this problem is to cause each GSP to maintain its own private copies of signal values, with phantom blocks automatically added, which for each signal, writes successive values to an additional single memory location so that it may be probed at a single memory address. The scheduler/compiler supports asynchronous timing as well as decimation and interpolation. Decimation and interpolation are accomplished within temporal partitioning by "blocking" die signal values into arrays, and operating on tiiese arrays of values rather than on single signal values. Thus, for example, in decimating by four, four input samples are buffered up by die input data flow manager. The code blocks before the decimator are looped tiirough four times, along with any filtering associated witii the decimation, and then the code after the decimator is run once. Various design integrity checks are performed by die scheduler, such as determining if multiple inputs to a cell have incompatible sample rates, or if any inputs have been left "floating". The scheduler/compiler supports feedback loops within a design, and automatically detects diem. A powerful parameter-passing mechanism in the scheduler/compiler allows each instance of a cell to be customized witii different parameters. Parameter values need not be absolute, but can be arbitrary expressions utilizing parameters of higher level cells. The scheduler/compiler provides for cells to verify that their parameter values are legal, and to issue compile-time error messages if not. Arbitrary design hierarchy is supported by die scheduler/compiler, including multiple sample rates within hierarchical blocks. Using only a schematic editor (e.g., die OrCad system), users may build their own hierarchical composite cells made up of any combination of library primitive cells and tiieir own composite cells. Details of component cells may be hidden, while providing any necessary SPROCdrive interface/SPROClink microprocessor interface access to selected internal memory locations. Composite cells may also be built which provide access to internal memory locations direcdy through the composite cell's input output, allowing efficient, direcdy wire control of parameters. A high level flow diagram of the compiler preferably used in conjunction widi die SPROC 10 of die invention is seen in Figure 12. When the user of the development system wishes to compile a design, die user runs die compiler with an input file containing die design. The compiler first determines at 1210 which of its various library blocks (cell library 2015) are needed. Because some of die library blocks will need sub-blocks, die compiler determines at 1212 which sub- blocks (also called child blocks) are required and whetiier all die necessary library block files can be read in. If they can, at 1220 the compiler creates individual instances of each block required, since die same block may be used more than once in a design. Such a block may be called witii different parameters which would tiiereby create a different version of diat block. The instances generated at step 1220 are represented witiύh die compiler data structures as a tree, witii die top level block of die user's design at die root of the tree. At 1230, die compiler evaluates the contents of each instance, and establishes logical connects between die inputs and outputs of child instances and storage locations in higher level instances. In evaluating an instance, the compiler determines code and data storage requirements of that instance, and assembles the assembly language instmctions which comprise die lowest level child instances. At 1240, die compiler sequences die instances by reordering die list of child instances contained in each parent instance. This is die order in which die set of program instructions associated witii each lowest level child instance will be placed in die program memory 150 of die SPROC 10. To do tiiis, die compiler traces forward from the inputs of die top level instance at die root of the tree, descending tiirough child blocks as they are encountered. When all inputs of an instance have been reached, the instance is set as die next child instance in the sequence of its parent instance. Feedback loops are detected and noted. At 1250, die compiler partitions the design over multiple GSPs. Successive child instances are assigned to a GSP until adding one more instance would require the GSP to take more than its • allowed processing time; i.e. one sample period. Succeeding child instances are assigned to a new GSP, and die process continues until all die instances are assigned to respective GSPs. As part of die partitioning step 1250, the compiler inserts instances of phantom blocks at the correct points in a child sequence. Phantom blocks are blocks which are not designated by die user, but which are necessary for the correct functioning of the system; e.g. blocks to implement software FIFOs which pass signals form one GSP to the next GSP in the signal flow. At step 1260, the compiler re-evaluates die instances so tiiat the phantom block instances added at step 1250 will be fully integrated into the instance tree data structure of the compiler. Then, at 1270, the compiler generates program code .spp) by traversing the instance tree in the sequence determined at step 1240, and when each lowest level child instance is reached, by outputting to a file the sequence of SPROC instructions assembled for that instance. It also outputs to a second file desired initialization values (.spd) for die data storage required at each instance. It further outputs to a tiiird file die program and data locations referenced by various symbolic names (.sps) which were eitiier given by die user or generated automatically by the compiler to refer to particular aspects of the design. As aforementioned, additional details of die scheduler/compiler may be seen in the preferred code for die scheduler/compiler which is attached hereto as Appendix M. E. The Microprocessor Referring now to the microprocessor side of Fig. 10, a C compiler and linker available from Intermetrics (including a debugger "XDB" and a compiler/linker "C Tools") is shown for a microprocessor Oogic processor). The inputs to the C compiler include the symbol translation files (.c and .h) provided by die symbol translator 2050, die SPROC boot file (.blk) provided by die MakeLoad software 2060, functions provided by die SPROC C library 2110 hereto, and eitiier manually generated text editor inputs from text editor 2035 or automatically generated code such as might be generated according to die teachings of U.S. Patent #4,796,179 from a block diagram. Because of die code provided by die symbol translator 2050, source code from die text editor can refer symbolically to variables (e.g., filtl.out) which have been compiled by die SPROClab system. This is critical for the ability of die microprocessor to interface witii die SPROC; i.e., for die microprocessor to obtain information via the host or other port from various locations in die SPROC RAM. The SPROC C function library routines are provided to convert SPROC data types to C compatible data types. The SPROC boot file provided to die C compiler and linker 2100 by the MakeLoad routine 2060 is not particularly processed by the compiler, but is fed into a memory block of the microprocessor's memory space. The output of the compiler/linker 2100 can be used direcdy to program the microprocessor 2120, or as shown in Fig. 10 can be provided to a microprocessor emulator 2110. Microprocessor emulator 2110 available from Microtek helps in die debugging process of the microprocessor. As die emulator is not a required part of die system, additional details of die same are not provided herewidi. As shown in Fig. 10, die programmed microprocessor 2120 interfaces with the SPROC 10 tiirough die host (parallel) port of die SPROC, aldiough information can be obtained in a serial fashion from a SPROC access port if desired. As aforementioned, die compiler/linker 2100 for the microprocessor receives code from a text editor or an automatic code generating system. To read and write sample data values, icons are placed on the signal processor block diagram (an example of which is shown in Fig. 11), and die symbol names which might be read from or written to by the microprocessor are made known to the microprocessor compiler/linker by the symbol translator. If the user wishes to read or write signal processor block diagram parameter values (e.g., gain of ampl = x), the user references the symbol name in die microprocessor source code (i.e., die user uses die text editor). In accord with another aspect of the invention, code for the microprocessor may be automatically generated rather than being generated by the user via the text editor. In automatically generating code for the microprocessor, a block diagram of die microprocessor functions can be entered in a manner similar to that described above witii reference to the signal processor block diagram. Then, utilizing the teachings of U.S. Patent #4,796,179, code may be generated automatically. Where automatic programming via block diagram entry of botii the signal processor and microprocessor is utilized, reading and writing by die microprocessor of sample data values of die SPROC is accomplished as before (i.e., icons are placed on die signal processor block diagram and the symbol names which might be read from or written to by the microprocessor are made known to die microprocessor compfler/linker by die symbol translator.) However, the reading or writing by the microprocessor of signal processor parameter values is preferably accomplished by providing "virtual" wires between the microprocessor and SPROC blocks. Because the virtual wires are not real wires, no storage is allocated to the virtual wires by either the SPROC or the microprocessor during compilation. However, the location (e.g., ampl gain) to which die virtual wire refers is placed in die .sps file such tiiat die symbol translator 2050 makes it known to die automatic microprocessor compiler. Jh this manner, the symbolic reference to the parameter is the same for both the SPROC and microprocessor compilers and this permits the microprocessor to read or write that parameter. Where graphic entry and automatic programming are used for botii the microprocessor and SPROC, some means for distinguishing what is to be processed by die microprocessor and what is to be processed by the SPROC is required. A simple manner of distinguishing between the two is to require user entry which will define a block as a block to be executed by die SPROC (e.g., block.spr) or a block to be executed by die microprocessor (e.g., block.mic). Where it is desired to provide blocks which will be executed by botii the SPROC and the microprocessor (possibly also including virtual wires), a hierarchical block should be provided. The hierarchical block will contain child blocks which will be designated as .spr or .rnic blocks as discussed above. Anotiier manner of distinguishing what is to be processed by the microprocessor and what is to be processed by die SPROC is to segment the tasks by die sample rate at which die block is functioning, with die relatively slow sampling rate tasks being handled by die microprocessor and die relatively fast sampling rate tasks being handled by die signal processor. Of course, if all blocks are predefined (i.e., are contained in a library), the preceded library code divides die code into code intended for die SPROC and code intended for die microprocessor. Regardless, where graphic entry for both signal processing and logic processing is permitted, die graphic entry eventually results in separate automatic compilation for both die SPROC and die microprocessor, with the SPROClab compiler again providing the necessary symbol table for incorporation during compilation of the microprocessor code. E.l SPROClink Microprocessor Interface The SPROClink microprocessor interface (SMI) is a set of components used to develop microprocessor applications in ANSI C that include the SPROC chip as a memory mapped device. Witii the components of SMI, one can create microprocessor applications that separate the logic processing tasks that ran best on a microprocessor from the real-time signal processing tasks that ran best on the SPROC chip. Partitioning the design in this way increases die performance and efficiency of the application. The SPROC chip communicates with the microprocessor at high speed via die SPROC chip parallel port and appears as a memory mapped device occupying 16K bytes of microprocessor memory space. SPROC chip memory is 4K of 24-bit words that map to the microprocessor as 32-bit words. SMI supports applications using either Motorola-type (little endian) and Intel-type (big endian) byte ordering. E.2 SMI Components SMI includes a symbol translator (SymTran) and the SPROC C function library (sproclib.c). The symbol translator converts the symbol file produced in the SPROClab development system into a data structure that rnirrors the symbol file. This allows for extemal C references to SPROC chip memory addresses as if the SPROC chip's memory were a C structure. The SPROC C function library contains the source code and header files for basic functions required to access the SPROC chip from a microprocessor. The library includes die SPROC chip load, reset, and start functions, as well as the data conversion functions required for die microprocessor to correcdy access and interpret die 24-bit fixed-point data type native to the SPROC chip. The components of SMI are not like other SPROClab software tools; they are not invoked from die development system environment. Instead, the components of SMI provide source code, in ANSI C, that is used outside of die SPROClab development system, in an embedded system development environment. By accessing diese files using the tools in the embedded system development environment, one can create microprocessor applications in C that include the SPROC chip. Such applications require, however, that one hardware memory map the SPROC. E.3 The Development Process The process required to develop a microprocessor application that includes one or more SPROC chips as memory mapped devices requires work that must be done in the SPROClab development system, and work that must be done in the embedded system development environment In the SPROClab development system, one must create, debug, and tune die signal processing design using die SPROClab development system tools; and mn die SPROCbuild utility to produce the configuration file that the microprocessor application will use to load the signal processing design onto die SPROC chip. In the embedded system development environment, one must translate the symbol file produced by the SPROCbuild utility into the data structure needed to provide microprocessor access to SPROC chip memory addresses; copy the configuration file, the data stracture, and all relevant file sections from the SPROC C function library into the applications work area; and create the microprocessor application. In addition, one must also map the SPROC chip(s) into the microprocessor's memory. It should be noted tiiat aspects of the microprocessor application depend on output from die signal processing design development process. If one develops die portion of the microprocessor application that deals with die SPROC chip in parallel witii the signal processing design, it is important to understand the relationship between the two processes and the dependencies described herein. Otiierwise, changes made to die signal processing design may require changes to die microprocessor application. E.4 Input Requirements Although SMI does not ran under the SPROClab development system, it does require two input files from the development system: a configuration file, and a symbol file. The configuration file is produced by MakeLoad, a module of die SPROCbuild utility in the SPROClab development system. It includes the program and data that comprise the signal processing design. As a default die SPROCbuild utility produces a standard configuration file in Motorola S-record format that can be loaded to die SPROC chip from the SPROCdrive interface. This standard configuration file is called a load file and has die file extension .lod. Because die configuration file used by SMI will be compiled by a C compiler and loaded from a microprocessor, the standard S-record format configuration file cannot be used. A special configuration file, called a block file, is required. The block file contains die C code describing die SPROC chip load as an initialized array of data, and it has the file extension .blk. The SPROCbuild utility will produce the configuration file as a block file in addition to a load file if die invocation line switch for the MakeLoad module is entered when running die SPROCbuild utility. The symbol file is produced by the Schedule module of the SPROCbuild utility. The standard symbol file has die file extension .sps. It provides access to memory addresses on die SPROC chip using symbolic names instead of direct memory references. Because the symbol file used by SMI must be included in C programs and compiled by a C compiler, the file must be in a different format tiian the standard symbol file. To create mis special version of the symbol file, the symbol translator (SymTran) takes as input the symbol file generated by the SPROCbuild utility and produces C header and code files tiiat create a data structure rnirroring the symbol file and including all necessary variable declarations. The symbol translator produces one header file and one code file for each signal processing design. E.5 Signal Processing Design Considerations In order for a signal processing design created in the SPROClab development system to be usable in a microprocessor application, the microprocessor must have access to the values of variables in the design running on die SPROC chip. Special cells in the SPROCcells function library provide this access by flagging specific nodes in the design for microprocessor visibility. This "micro" keyword triggers die symbol translator to make external C references to the associated symbols available. Only symbols with this micro keyword are available to the microprocessor. E.6 Embedded System Development Considerations The signal processing design must be completed and debugged using the SPROClab development system software. The SPROCdrive interface software is the primary tool for interactively debugging and tuning designs for die SPROC chip. In general, the signal processing design should be completed to a stable interface level before development of die microprocessor application begins. If the signal processor design is modified later, the symbol file and block file generated from it must be updated, and die microprocessor application using die files must also be modified to accommodate die change. It is advisable to use a dependency file and make facility to track inter-related design modifications and ensure consistent creation and use of up-to-date files. E.7 Using the SPROC Configuration File The SPROC configuration file contains die program and data tiiat executes on the SPROC chip. It is produced by the MakeLoad module of the SPROCbuild utility in the SPROClab development system. The configuration file is normally generated in Motorola S-record format for loading from the SPROCdrive interface. It must be generated as an initialized data array for loading from a microprocessor application. A switch setting in the invocation line of MakeLoad determines which format of the configuration file will be produced. The configuration file generated as an initialized array of data is called a block file, and has die file extension .blk. (The base of the file name matches the base of the signal flow diagram from which die configuration was generated.) This file includes die block-formatted data tiiat comprises the load for die SPROC chip, and it declares a C variable that identifies tiiat block of data. This C variable, the block variable, has die following form: mydesign_block where mydesign is die base name of the block file (the same base as the signal flow diagram of die design, and die same base as die symbol file input to die symbol translator). In a microprocessor application, the block file is available as a block of data tiiat can be downloaded to die memory mapped SPROC chip using a C function call and the block variable. The sprocJoad function included in die SPROC C function library will download die block file to the SPROC chip. E.8 Using die Symbol Translator The symbol translator (SymTran) converts the symbol file produced by die SPROCbuild utility in the SPROClab development system into a data stracture tiiat declares C variables for SPROC memory addresses. Output from die symbol translator declares a global static variable tiiat identifies the complete data structure. This data structure occupies 4K by 4 bytes of microprocessor memory. The variable declared to identify die structure is the sproc_id, and die variable name matches the base name of the symbol file. The symbol translator produces the header and code files needed to provide extemal C references for SPROC chip memory addresses. The header file makes the SPROC memory addresses available to die microprocessor for reference as C variables, and the code file locates die C variables at the appropriate places in the SPROC chip memory map. The symbol file generated by the SPROCbuild utility in the development system has the file extension .sps. (The base of the file name matches the base of the signal flow diagram from which the symbol file was generated.) The symbol translator translates the symbol file into a header file (witii extension .h) and a code file (witii extension .c) tiiat use the same base file name as the input symbol file. For example, the SPROCbuild utility uses a signal flow block diagram named mydesign.sch to produce a symbol file named mydesign.sps. The symbol translator uses this symbol file (mydesign.sps) to produce the header file mydesign.h and the code file mydesign.c. Not all of die SPROC memory addresses represented by symbols in die symbol file are available to die microprocessor. Only symbols that include die micro keyword are made visible to the microprocessor. This keyword is set as a characteristic of the specific cells used in the signal flow block diagram of the design. Due to differences in syntax, some of the characters used in symbol names for the SPROC chip environment cannot be used in C. Symbols tiiat use characters that are illegal in C are altered during translation to make them legal. For example, all symbols that contain the % character are converted to contain a capital P character. Symbols of this form typically identify SPROC chip register addresses. The symbol file includes symbolic names for all SPROC memory addresses. The symbol file provides a hierarchical stracture that uniquely identifies nodes and attributes of all cell instances in a signal processing design. Levels of hierarchy in symbol names are separated by a dot (.) character. For example, in the symbol name ampl. gain, ampl is die amplifier cell mat contains the specific attribute (gain) named by die symbol. In addition to deterrnining the hierarchy of nodes and attributes, die SPROCbuild utility also determines the order in which these elements will be processed on die chip, and it assigns chip memory locations (addresses) based on this order. The address for a node or attribute is saved in the symbol file along with its symbol name, so that the symbol file comprises an address map of die symbol names for all nodes and attributes in the design. Some nodes and attributes can be referenced by multiple symbols (or aliases). For example, a wire that connects two cells is both the output of the first cell and the input of die second. In addition, a label may be specified for the wire. All three symbols, for the output of the first cell, the input of the second cell, and die label for the wire, refer to the same node on the design and to die same location in SPROC chip memory. When such aliases are translated, die symbol translator ensures that all aliases for a symbol refer to the same location in SPROC chip memory. Only the SPROCbuild utility can manipulate the order of the nodes and attributes represented by die address stracture. This structure may change any time the utility is invoked to convert a block diagram and generate a configuration file and a symbol file, depending on what changes have been made to the design. If die order of nodes and attributes changes, the address assignments tiiat represent that order change. Therefore, one must always be sure to work witii a current version of die symbol file, and never make assumptions about the addresses assigned to symbols or die order of nodes and attributes relative to each other. E.9 Using the SPROC C Function Library The SPROC C function library (sproclib.c) includes the basic functions necessary to allow the microprocessor to control the SPROC chip. The SPROC C function library includes source modules mat determine the byte ordering supported by SMI, define SPROC data types, provide functions to convert C's data types to and from SPROC data types, and provide functions for the microprocessor to load die SPROC chip and start execution of the signal processing design. All modules are supplied as source and must be compiled and linked in the embedded system development environment. Not all modules are required for every application. The user may select the specific modules needed for a particular application and compile and link only tiiose. If die embedded system design environment supports libraries, one may compile all modules and build diem into a library from which one can reference selected modules for linking in a specific application. Because the data type native to the SPROC chip is incompatible with C's intrinsic floating point data type, SMI defines specific SPROC data types for access from the microprocessor application. It also provides conversion functions to convert to and from die defined SPROC data types. The SPROC data types provided by SMI are: FK24_TYPE, the data type native to the SPROC chip, a fixed-point, 24-bit 2's compliment value in the range -2 < x < 2. FTX16_TYPE, supports applications where precision can be sacrificed for increased speed of data transfer. It is die most significant 16 bits of die FTX24_TYPE data. INT24_TYPE is a 24-bit integer data type. All symbols are declared to be sdata, a union of all SPROC data types. The header file sprocde h defines die SPROC data types and function prototypes. It must be included in each C module tiiat references SPROC data values. SMI supports applications using both Motorola-type (little endian) and Intel-type (big endian) byte ordering. The default byte ordering is Motorola-type. To change the byte ordering, one must edit die file sprocdefh, or use the #define INTEL statement or the define switch on die C compiler. To edit die file sprocdefh, comment out the lines relating to Motorola-type byte ordering, and uncomment the lines tiiat provide support for Intel-type byte ordering. SMI provides three basic functions required for the microprocessor application to load die SPROC chip and start signal processing design execution: sproc_load, sproc_reset, and sproc_start The sprocjoad function downloads the signal processing design onto the target SPROC chip. It writes the chip's code, control, and data space with data from the block file. The sprocjoad function has the form: sprocJoad(sproc_id, block) where sproc_id is the name of die data structure created by die symbol translator (i.e., the base name of the input symbol file), and block is the block variable declared in die SPROC configuration file. The block variable has the form mydesign_block. The sproc_reset function issues a software reset to the target SPROC chip. The sproc_reset function has the form: sproc_reset (sproc_id) where sproc_id is die name of the data structure created by die symbol translator (i.e., the base name of die input symbol file). The sproc_start function initiates execution of the signal processing design loaded on die SPROC chip. The sproc_start function has the form sproc_start (sproc_id) where sproc_id is the name of the data structure created by die symbol translator (i.e., die base name of me input symbol file). E.10 Accessing SPROC Chip Memory Values In die microprocessor application, one can read and write the SPROC chip memory value for any node or parameter whose symbol is visible to die microprocessor. However, there are several issues one must consider when determining how to incorporate access to the available SPROC chip memory values into the application. First, most values in SPROC chip memory locations are driven by the activity of the chip's general signal processors (GSPs), at signal processing speeds. Memory values are modified at speeds much higher than the relatively slow speed of die interface to die values provided by die microprocessor bus. Second, some values are dynamic and change during execution of the particular cell that contains them. For example, the coefficients of adaptive filters are modified by the filter algorithm defined for die cell. Given die issues noted above, reading SPROC chip memory values is less risky than writing values. However, because of the slow microprocessor interface speed, microprocessor reads of SPROC chip data can be problematic. Any SPROC chip memory value read by the microprocessor may be obsolete by the time the microprocessor obtains it due to the relatively slow speed of the microprocessor interface. In addition, consecutive microprocessor reads of SPROC chip memory addresses will obtain values that were computed at different times, but not necessarily consecutively. Other values may have been written by the GSPs between microprocessor read accesses. To ensure obtaining consecutively computed values for use by the microprocessor, a sink cell is used to collect values at the signal processing rate. Writing values from the microprocessor presents specific problems. As noted above, die values of many parameters are modified by die GSPs or by die cells that contain them as die signal processing design executes. Otiier parameters, like the gain of an amplifier, are usually defined on the- signal processing block diagram and their values generally remain constant during design execution. Depending upon the specific signal processing design and SPROC chip memory address, a destination address written by die microprocessor may be overwritten by a GSP during design execution if the microprocessor write is not coordinated witii the signal processing activity in the design. One way to ensure that values written by the microprocessor will not be overwritten before they are used in die signal processing design is to use a source cell witii reset. This cell . _ allows die microprocessor to safely write into die cell's in vector, which cannot be written by any GSP, tiien write to the cell's reset line to pump out the values. Writing a set of new filter coefficient parameters for a filter cell presents a difficult problem. Filter response may become unstable as the values are slowly changed from the old stable set to a new stable set. A workaround solution to allow filter coefficient changing is to instantiate two filters in the signal processing design and use a comparator cell functioning as a multiplexor to direct signal flow through one filter or the otiier. The microprocessor can change die coefficient set in die non-executing filter then switch die signal flow to tiiat filter widiout producing an unstable filter response. This approach, however, results in "over allocation" of GSP resources. Resource requirements are calculated based on die existence of both filters, because the SPROCbuild utility has no information on the actual run-time signal flow. F. Low Frequency Impedance Analyzer Example Turning to Fig. 11, a block diagram is seen of a low frequency impedance analyzer. The analyzer includes several multipliers 2201, 2203, 2205, 2207, 2209, 2211, two sealers, 2214, 2216, two integrators 2220, 2222, two hard limiters 2224, 2226, two full wave rectifiers 2230, 2232, two filters 2234, 2236, two amplifiers 2238, 2240, two summers 2242, 2244, three arrays (sink blocks) 2246, 2248, 2250, an oscillator 2252, a serial input 2253, two serial outputs 2254, 2255 and two microprocessor software interface output cells 2256, 2258, and one microprocessor interface input cell 2260. Each block has a library name (e.g., SCALER, MULT, SUM2, FILTER, etc.), an instance name (e.g., SCALERl, MULT2, etc.), and at least one terminal, and many of the blocks include parameters (e.g., shift =, upper =, spec =, freq =, etc.). The wires between terminals of different blocks carry data sample values (as no virtual wires are shown in Fig. 11). The serial input 2253 receives data from extemal die SPROC at a high frequency sample data rate, and the data is processed in real time in accord witii the block diagram. The SPROC outputs two values extemal to the SPROC and microprocessor (i.e., out the serial ports) as a result of the SPROC processing. Information to be provided to or received from the microprocessor is sent or received via the microprocessor software interface cells 2256, 2258, and 2260. Li particular, when the microprocessor writes to the location of cell 2260, cell 2260 causes die arrays 2246, 2248 to collect data and to provide a signal to microprocessor software interface output cells 2256 and 2258 when filled. Witii the block diagram so provided on an OrCad graphic interface, and in accord witii the above description, after translation by the MakeSDL file, the scheduler/compiler provides a program file (yhpdual.spp) and a data file (yhpduaLspd) for the SPROC, and a symbol file (yhpduaLsps) for the symbol translator and microprocessor and for the SPROCdrive interface. The program, data, and symbol files are attached hereto as Appendices F, G, and H. In addition, the yhpdual.spp and yhpdual.spd files are processed by die MakeLoad program which generates die yhpdualblk file which is attached hereto as Appendix I. In order to completely implement die low frequency impedance analyzer such tiiat it may be accessed by die microprocessor, the microprocessor is provided witii C code. An example of C code (MaintestC) for this purpose is attached hereto as Appendix J. Of course, similar code could be generated in an automatic fashion if an automatic microprocessor code generator were to be utilized. As provided, die C code attached as Appendix J calls yhpdual.c and yhpdual.h which are the translated files generated by die symbol translator from the yhpdual.spp file generated by die SPROC scheduler/compiler. Attached hereto as Appendices K and L are die yhpdual.h and yhpdual.c files. Thus, die MaintestC as well as die yhpduaLh and hypdualc files are provided in a format which can be compiled by die microprocessor compiler. There have been described and illustrated herein architectures and mediods for dividing processing tasks into tasks for a programmable real time signal processor and tasks for a decision- making microprocessor interfacing with the real time signal processor. While particular embodiments of the invention have been described, it is not intended tiiat the invention be limited thereto, as it is intended tiiat die invention be as broad in scope as d e art will allow and that die specification be read likewise. Thus, while particular hardware and software have been described, it will be appreciated tiiat the hardware and software are by way of example and not by way of limitation. In particular, while a 68000 microprocessor and C compiler for the 68000 microprocessor have been described, otiier processors (i.e., not only "microprocessors"), and/or odier types of code (e.g., FORTRAN, PASCAL, etc.) could be utilized. All tiiat is required is tiiat the symbol table code (.sps) generated by die SPROClab development system be in a format for compilation by die processor compiler, and that, where provided, die boot file (.blk) be in a format for compilation by the processor compiler or in a format for storage by the processor. Similarly, while a particular real time signal processor (die SPROC) has been described, it will be appreciated tiiat other similar type signal processors can be utilized provided that the signal processor is directed to signal processing rather than logic processing; i.e., the signal processor should have a non-interrupt structure where data flow is tiirough central memory. Further, while a system which provides die realization of a high level circuit in a silicon chip from simply a sketch on a graphic user interface has been described for at least the real time signal processor, it will be appreciated that die text editor could be used to replace the graphic entry, and tiiat while die system would not be as convenient, the graphic entry is not absolutely required. Similarly, the text editor could be elirninated and die system could work only from die graphic entry interface. Odier readily evident changes include: an expanded or a different cell library; different graphic user interfaces; die provision of a scheduler/compiler for die SPROC which is directly compatible with die graphic user interface (rather than using a translator such as MakeSDL); and die provision of different software packages. It will therefore be appreciated by those skilled in the art that yet other _ modifications could be made to die provided invention without deviating from its spirit and scope as so claimed. APPENDIX SUBSTITUTE SHEET Copyright fc) 1991 Star Semiconductor Corporation. All Rights Reserved. This Material may not be copied or used without prior written permission. * $Id: makesdl.c.v 1 .4 1991/10/01 16:24:10 ivan Exp $ * SLog: makesdl.c.v $ * Revision 1.4 1991/10/01 16:24:10 ivan * Fix wi ld address bug. « * Revision 1.3 1991/09/16 19:06:37 ivan * Changed error Messages to Star format * * Revision 1.2 1991/09/11 15:20:52 ivan * Support "blocklen" parameter on 'filter' blocks to control splitting * of filters longer than a sample period into seperate blocks. * Revision 1.1 1991/09/06 18:47:50 ivan * Initial revision makesdl.c -UTURENET/DISPRO to SOL file conversion. Convert a FUTURENET pinlist format netlist file into an SDL hierarchical file. Build a list of filters in the design and after completing the netlist conversion call the DISPRO to SDL converter successively for each filter. Thus a total of (1+N) ".sdl" iles are created, where N is the number of filters in the design. Also a ".dat" file is created for each fir in the design. A ".spf" file is created containing a list of alt filters successfully converted to sdl in this design, useful for "make". '/ requires 'include "sysfuncs.h" 'include "strfunc.h" 'include <stdio.h> 'include <stdlib.h> 'include <string.h> 'include <ctype.h> ......«.,......„..» / '* " exceptions */ ■..--.„.».„.„„.„..../ .,.....„.....,.... / '* constants */ 'define MAXCOMMAND 82 /* dos command line size A'/ 10? /define MAXNAME 32 /* dos fi lena e name size */ /define MAXEXT 6 /* dos filename extension size */ /define MAXPARAM 10 /* number of command line params */ /define MAXPARMS 8 /* number of cell parameters */ /define MAXLINE 200 /* input fi le line size /define MAXREF 32 /* ORCAD reference designator /define MAXMODEL 32 /* ORCAD part name /define MAXFIELD 32 /* ORCAD part field /define TLEN 32 /define NOW 1000 /" max number of wires per schematic * /define N0I 16 /* max number of inputs per icon * /def ne N0016 /* max number of outputs per icon * /define NOTK 12 /* max number of tokens on line * /define NFILTER 30 /* max number of filters per design * /define NTFUNC 25 /* max number of tran fnc per design * /define ARRAY_WIDTH 32 /* max length of wire name * /define SECTSIZE 30 /* for splitting FIR into blocks */ types /ft******************/ typedef βnum{singleFi Iter, dualFilter, transferFunction}fi IterType; typedef char maxfield[MAXFIELD]; typedef struct int index; char reference[MAXREF] ; char mode I [MAXMODEL] ; maxfie ld parms[MAXPARMS] ; symbo l ; data symbol sptr ; static char makesdl[ ] = "$Revision: 1 .4 $" ; vl locate 2 dimensional character arrays for storage of lists .... * . * ..».»......«...„...»...«..._...._................... / int wlc = 0. i lc = 0, o lc = 0; nt f lc = 0, t ic = 0; :har wi re_list[NOW][ARRAY_WIDTH] ; :har input_list[NOI][ARRAY_WIDTH] ; :har output_list[N00][ARRAY_WIDTH] ; :har token_list[NOTK][ARRAY_WIDTH] ; ihar fi lter_list[NFILTER][ΛRRAY_WIDTH] ; :har struc_list[NFILTER][ARRAY_WIDTH] ; ?' < SUBSTITUTE SHEET int blockLen_ϊ st[NFILTER] ; char tfunc_list[NTFUNC]tARRAY_WIDTH] ; char tfunc_strue_tist[NTFUKC][ARRAY_WIDTH] ; /* macros */ /* functions */ int trans late(FILE * src, FILE * dest, char *design_name) ; int find_next_block(FILE * ifi le, char toc_rec[]); int get_block(FILE * fname) ; int split_tokens(char *p1 , char p2[][ARRAY_WIDTH]) ; void format error(const char "string) ; int pr_array(FILE * dest, char listt][ARRAY_WIDTH]) ; int row_not_sent(char list[][ARRAY_WIDTH] , int index) ; int convert_fi lter_block(fi IterType) ; char *get_str(char *s) ; int makβ_f i lter(char "name, char "struc. int axtaps) ; int not_in_array(char list[][ARRAY_WIDTH], int index, char *str) ; int gettffCchar "name); main program *"—*** « */ void maiπ(int argc, char *argv[]) C FILE "infile, "outfi le, •fltfile; char fname[MAXNAME], ext[MAXEXT]; char inpath[MAXNAME], outpath[MAXNAHE], fltpath[MAXNAMEJ; process command line parameters printf{"\nMakesdl Xs\n", nakesdt); printf("Copyright (C) 1991 by STAR Semiconductor Corporation.\n"); if (argc > 1) { strtolw(argv[1 ]) ; if ((strcmp(argv[T], "-h") = 0) | | (strcmp(argv[1], "/h") = 0)) i printf("Usage: Makesdl f lename[.net]\n")f exit{-1) ; } else strcpy (inpath, βrgv[1]); A- 3 } #ifdef DEBUG else ( /* DEBUG only » / strcpy(inpath, "ftest3"); } #else else { printf("Usage: makesdl fi lename[.net]\n"); exit(-1); } #endif make input and output filenames ......,....................,.. / splitname(inpath. fna e. ext); if (strcmp(ext, ".sdl") -== 0) { printf("ERROR -- makOOl: input file cannot be \»Xs\"\π". ext); exit(-1); } else if (strcmp(ext, ".dat") == 0) { printf("ERROR -- mak002: input file cannot be \"%s\"\n". ext); exit(-1); } else if (strcmp(ext, "") == 0) /* append default extension */ ( strcpy(ext. ".net"); mergenamβ(inpath, fname, ext); }: mergename(outpath. fname, ".sdl"); mergename(fItpath, fname, ".spf"); / ...,,...„„„„..„,.«.„„„„.,, open input and output f les ......... * ... * „„,...„.„... / if (check_open_rf(iinfi le, inpath) != 0) { - printf("ERROR •- mak003: failed to open Xs\n", inpath); exit{-1); }; if ((outfile = fopβn(outpath, "w")) == NULL) { printf("ERROR •- mak004: failed to open %s\n", outpath); exit(-1); }i if ((fltfile » fopen(fItpath, "w")) = NULL) { printf("ERROR -- ιnak005: failed to open Xs\n", fltpath); SUBSTITUTE SHEET }: ,,..«.„.«...«.«*..««..«..««*•«•«* translate the input to output f le .„„«...„.«.« * „».««.«.«« * ». * ..«» / printf("Creating Xs from Xs\n", outpath, inpath) ; if ((βxit_code = translate(infi le. outfile, fname)) != 0) t printf("ERROR — mak006: could not translate Xs\n", inpath); }: close netlist translator f les fc lose (i nfi le) r fclose(outf le) ; Call fi lter translator to generate the hierarchical sdl fi les for all filters in this design. whi le {— flc >= 0) C int err, temp; err - make_fi lter(fi lter_list[f lc], struc_list[f lc], blockLen_list[f lc]) ; if (err < 0) t printf("ERR0R -- mak007: problem with fi lter Xs\π". fi lter_list[f lc]) ; exit_code » -1 ; }: temp = fpriπtf(fltfi le, "Xs.fdf\n". fi lter_list[f lc]) ; .*««....<...«...«.«««.*..,.........«...«..«..«...«.«»«««,«....«.„„.,« Call transfer function translator to generate the hierarchical sdl files for all transfer functions in this design. ...*.»..**«..,«...,.*.............»..««.«.«...«»*..*...,..,,«.,»..,,, while (—tic >» 0) C int err, temp; err « gettff(tfunc_list[tlc]) ; if (err < 0) C printf ("ERROR — makOOβ: problem with transfer function Xs\n", tfuπc_list[tlc]) ; }ϊ temp = fprintf(f ltfi le. "Xs.tff\n", tfunc_list[t lc]) ; }: fclosβ(fltfi le) ; Ul exit(exit_code); } FUNCTION DEFINITION: translate Take the contents of a file in FUTURENET format and convert them into another file in SDL format. Use given name to assign top level design name. Do a basic check to validate the file contents are in pinlist format. */ int translate(FILE * src, FILE * dest, char "name) { int trl_status; FILE "tmpfile; char temp_rec[MAXLINE]; check fi le validity trl_status = 0; fgets(temp_rec, MAXLINE, src); if (strncmp(temp_rec, "PINLIST", 7) != 0) return (-1); tmpfile = fopen("$sdl1.t p", "w"); write header to output file fprintf(dest, "block Xs()\n\n", name); clear wire list int i ; for (i = 0; i < NOW; i++) wire_lιst[i][0] = '\0' }; wlc = 0; process successive blocks copy each block into the structure sptr, and update the lists of inputs, outputs and wires. •/ while ((find_next_block(src, temp_rec)) == 0) { get_block(src); /* fill sptr, input, output, wire lists */ write sdl for this block to a temporary file, since wire list must be at top of output file, but is not yet available A-G SUBSTITUTE SHEET /* ki lt all white space in parameter structure */ strcpress(sptr.mode I) ; strcpress(sρtr. reference) ; C int i r for (i = MAXPARMS - 1 ; i>=0; — i ) strcpress (sptr .parms[ i ] ) ; }; /* Now check if this b lock is a fi lter, extract the reserved parameters "spec=f lename" and "struc=primitive_name" . Add these parameters to the list of fi lters which wi ll be translated when the net list translation, including the modified hierarchical fi lters, is comp lete */ if (strcmp(sptr .model, "fi lter") = 0) /* normal fi lter */ trl status = convert_fi lter_b lock(sing leF Itβr) ; else if (strcmp(sptr. model, "vcfi lter") = 0) /* vcf i Iter */ trl_status = convert_fi lter_block(dualF lter) ; else if (strcmp(sptr .model, "transfnc") = 0) /* transfer function */ tr l status = convert_fi lter_block(transferFunction) ; printf (tmpf i le, "Xs Xs\n u , sptr. odel, sptr. reference) ; fpr ntf (tmpfi te. " £") ; /* write parameter list for this block, skip blank fields */ C const char* dβli = " "; int i; for (i = MAXPARMS - 1; i>=0; —i) C char* ptr = sptr.parmsfi]; strepress(ptr); if (strcmp(ptr, "") != 0) { fprint (tmpfile, "Xs\n XXXs", deliπ, ptr); delim = ",";; }f }; }; fprintf(tmpfile, "\n }\n"); /* write list of inputs and outputs for this block. Initialise the List delimiter first, after first entry is written update the delimiter to a comma. When input list is exhausted move on to output list. */ fprintf(tmpfile, " (\n "); I const char* delim = ""; int j; for (j •= 0; j < HOI; }++) C if (strcmp(input_list[j], "") != 0) C A- 7 fprintf(tmpfi le, "XsXs", delim. input_list[j]) ; delim = ",\n "; }; }i for (j = 0; j < N00; j++) { if (strcmp(output_list[j], "") != 0) { fprintf(tmpfi le, "XsXs", delim, output_list[j]) ; delim = ",\n "; }; }; }i fprintf(tmpfile, "\n );\n\n"); }; all blocks now processed, terminate temporary file fprintf(tmpfi le, "end\n"); write wire list to output file ............................./ fprintf(dest, " wire\n»); pr_array(dest, wire_list); fprintf(dest, »;\n\n"); fprintf(dest, »begin\n"); /• printf("Processed Xi blocksXn", i); ............................... close temporary fi le and return fclose( tmpfi le); now append temporary f i le to output f i le tmpfi le = fopen("$sdl1.tmp", "r"); forever { fgets(temp_rec, MAXLINE, tmpfi le); if (feof(tmpfile) != 0) break; fprintf(dest, "Xs", temp_rec); }i fclose(tmpfi le); unlink("$sdl1.tmp"); return (trl_status); } A-i SUBSTITUTE SHEET 13A FUNCTION DEFINITION: find_nβxt_block Advance to beginning of next block in fi le int find_next_block(FILE * ifi le, char loc_rec[]) f. strcpy( loc_rec, "\n") ; /* f lush record string */ whi le (strncmp( Loc_rec. »(SYM", 4) 1= 0 && feof(ifi le) = 0) fgets( loc_rec, MAXLINE, ifi le) ; return (feof(ifi le)) ; } FUNCTION DEFINITION: get_b locfc Process all lines of a block into a form usab le for generation of SDL Lines may be of the form: DATA,2 - instance info DATA.3 - symbol / parameter / verify info PIN - wire info other - garbage for now ».«......«„...,..«»...... * „.»..»«..«..............»........ / int gβt_block(FILE * fname) f. int i = 0; char tmp_rec[MAXLINE]; reset structure sptr.index = 0; sptr.rβference[0] = Α0'; sptr.model[0] = '\0'; C int i; for (i = MAXPARMS - 1 ; i>= 0; -- ) sptr.parmsri][0] = '\0'; }; / ..»-......................,« clear input List, output list «..,..................„..,. / for (i » 0; i < NOIf i++) input_List[i][0] » '\0 * ; i lc = 0; for (i » 0; i < N00; i++) output_list£i][0] = '\0 * ι olc »= 0; /* fetch sucessive line records from file and extract tokens */ do ft- ? { fgets(tmp_rβc, MAXLINE, fname); sp li t_tokens( tmp_rec , tokeπ_ li st ) ; process DATA lines if (strcmp(token_list[0], "data") == 0) { if (strcmp(token_list[1], "2") == 0) strcpy (sptr. reference, token_list[2]) ; else if (strcmp(token_list[1 ], "3") == 0) { int i ; strcpy (sptr. ode I, token_list[2]); for (i - MAXPARMS - 1; i>= 0; --i) strcpy(sptr.parms[i], token_list[i+3]); } else format_error("ignoring unknown DATA statement"); process PIN lines "*******"*****/ else if (strcmp(token_list[0], "pin") == 0) { /* Replace the *** characters from the wire number generated in futurenet netlist with something readable */ if (strncmp(token_list[2], »* « *", 3) == 0) { token_list[2][0] = * _ * token_list[2][1] = 'w' token_list[2][2] = 'n' }; /* check lists are not full */ if (ilc >= N0I) format_error("too many inputs on block"); if (olc > NOO) format_βrror("too many outputs on block"); if (wlc > NOW) format_error("too many wires in design"); /* add an input to input and wire lists for this block */ if (strcmp(token_list[5], "23") == 0) { strcpy(input_list[i lc++], token_list[2]); if (not_in_array(wirβ_list, wlc, token_list[2]) == 0) strcpy(wire_list[wlc++], token_list[2]); } /* add an output to output and wire lists for this block */ else if (strcmp(token_list[5], "21") == 0) 4-/0 SUBSTITUTE SHEET i strcpy(output_list[olc++] , token_list[2]) ; if (not_in_array(wire_list, wlc, token_list[2]) = 0) strcpy{wire_list[wlc++]» token_list[2]) ; J else format βrror("bad pin statement") ; process other tines else if (strcmp(token_tist[0] , ")") = 0) else printf ("WARNING — mak010: ignoring unknown line: Xs\π", token_list[0]) ; } whi le (strcmp(token_list[0] , ")") 1= 0) ; return (0) ; FUNCTION DEFINITION: split_tokens from a buffer p1 extract tokens to array of strings p2 int split_tokens(char *p1 , char p2r]L"ARRAY_WIDTH]) C int i, ϊ. k; char c; char token[TLEN]; flush token array first for (i =» 0; i < N0TK; i++) p2[i][0] » '\0'ϊ fetch new tokens i = 0, j « 0; forever C k > 0; forever C c = p1[i]: if (c >=« '\0 * |[ c= * .' || c = '\n * ) C /* token com lete, so null terminate, exit if too long */ token[k] = * \0'; i++; if (k++ >= TLEN) { printf("ERROR - token too tong\n"); exit(-1); } break; /* token not complete yet, append another character */ token[k] = (char)tolower(c); i++; k++; } /* move this token to token list */ strcpy(p2[j], token); if (j++ >= NOTK) ( printf("ERROR - too many tokens on line\n"); exit(-1); } /* check for end of line */ if (c == '\0 * || c == '\n') break; } return (j); void format_βrror(const char 'string) £ printf("ERROR - Xs", string); exit(-1); } FUNCTION DEFINITION: pr_array print a comma separated list to a stream, terminates on a null list entry, or the number of wires in a design is exhausted. int pr_array(FILE * dest, char list[][ARRAY_WIDTH]) { int i = 0; char loc_rec[ARRAY_WIDTH]; if (strcmp(list[i], "\0") == 0) /* check first one • / return (i); strcpy(loc_rec, tist[i]); fprintf(dest, " Xs", loc_rec); forever /* check the rest */ { i f (strcmp( list[++i ] , "\0") = 0 | | i > NOW) /* check next one */ break; /* nothi ng left */ else SUBSTITUTE SHEET strcpy( loc_rec, list[i]) ; /* if( row_not_sent( list. i )=0 ) */ fprintf(dest. ",\n Xs", loc_rec); /* always print it */ } } return (i - 1)r FUNCTION DEFINITION: row not sent see if current row (string) in an array exists earlier in the array, return 0 if current entry does not exist earlier. Used to prevent duplication when creating a wire list. */ int row_not_sent(char list[][ARRAY_WIDTH], int index) C int k; strcpy(loc_rec, List[index]); /* ok to corrupt local copy of index */ for (k = index - 1; k >= 0; k--) /* step back one entry in list */ i if (strcmp(loc_rec. list[k]) = 0) return (-1); /* if duplicate found earlier in list */ } return (0); FUNCTION DEFINITION: not_in_array See if a string exists in the array (list of strings), return 0 if current entry does not exist earlier. Used to prevent duplication when creating a wire list. int not_in_array(char List[J[ARRAY_WIDTH], int index, char *str) C int k; for (k = index - 1; k >= 0; k—) /* step back one entry in list t " if (strcmp(str» list[k]) «= 0) return (-1); /* if duplicate found earlier in list */ } return (0)r FUNCTION DEFINITION: convert filter block Convert a f lter block structure to a specific named instance of a hierarchical block, add the specification file name and the required filter structure name to lists for future filter translation. Valid filter structures names: biquad, biqamp, vcf /?-/3 int convert_fi lter_block(fi IterType code) £ int cfb_status; char* specPtr; char* strucPtr; int* blockLenPtr; Set default filter implementation, since the "struc" parameter needs to be optional at the schematic entry time. code=1 , FILTER - use single input filter primitives code=2, VCFILTER - use dual input controlled filter primitives codβ=3, TRANSFNC - use single input filter primitives Valid FILTER struc's are: biquad. biqint, biqamp Valid VCFILTER struc's are: biqvc ft**********************************************..!*.*********/ cfb_status = 0; blockLenPtr = &blockLen_list[f lc]; •blockLenPtr = SECTSIZE; /* default, overridden by blocklen */ switch (code) £ case singleFi Iter: /* FILTER default structure */ strcpy(strucPtr = struc_list[f lc], "biquad"); specPtr = f i lter_list[f lc++]; break; case dualFilter: /* VCFILTER default structure « / strcpy(strucPtr = struc_list[f lc], "biqvc"); specPtr = fi lter_list[f lc++]; break; case transferFunction: strcpy(strucPtr = tfunc_struc_list[f lc], "biquad"); specPtr = tfunc_list[t lc++] ; break; default: cfb_status = -1 ; /* ERROR condition */ break; }: strcpy(specPtr, ""); /* null the spec first */ check filter list is not full if (flc >= NFILTER) £ printf("ERROR -- mak011:Too many filters to handle\n"); cfb_status = -1 ; return (cfb_status); }: if (tic >= NTFUNC) £ printf("ERROR •- mak012: Too many transfer functions to handleW); cfb_status ■ -1 ; return (cfb_status); }; A'/y SUBSTITUTE SHEET get spec and structure names ..„..........«...,...«.... / c int i ; for (i = MAXPARMS-1 ; i >= On " --) £ if (strncmp(sptr.parms[i], "spec=", 5) — 0) C strcpy(specPtr, get_str(sptr.parms[i])) ; sptr.parms[i]£0] = '\0'r /* now delete spec parameter */ } else if (strncmp(sptr.parπs[ij, "struc=", 6) == 0) £ strcpy(strucPtr, get_str(sptr.parms[i])); sptr.parms[i][0] = '\0"; /* now delete struc parameter */ } else if (code 1= transferFunction && strncmp(sptr.parms[i], "blocklen=", 9) = 0) C •blockLenPtr = atoi(get_str(sptr.parms£i ]) ) ; sptr.parms[i][0] = *\0 * ; /* now delete block ten parameter */ > J; Modify the structure to ref lect actua l instance of f lter strcpy(sptr.model, specPtr) ; if (strcmpfsptr .model, "") = 0) i print ("ERROR -- mak013: spec parameter missing, instance Xs\n", sptr.reference); cfb_status = -1; return (cfb_status); } return (cfb_status); 3 F UNCTION DEFINITION: gβt_str Jet rhs of equality statement :har *get_str(char *s) c char temp[ARRAY_WIDTH]; int i « 0. j = 0r wh le (s[i++] !» '='); /* skip through '=' sign */ while (s[i] 1= '\0') /* copy characters */ temp[j++] -e s[i++]; tβmptJ] - '\0'; /* terminate string */ return (temp); ~/r Copyright (c) 1991 Star Semiconductor Corporation. All Rights Reserved. This material may not be copied or used without prior written permission. * $Id: makefil.c.v 1.31991/09/16 19:06:35 ivan Exp $ * SLog: makefi l.c.v $ * Revision 1.3 1991/09/16 19:06:35 ivan * Changed error messages to Star format * « Revision 1.2 1991/09/11 15:20:50 ivan * Support "blocklen' parameter on 'filter' blocks to control splitting * of filters longer than a sample period into seperate blocks. * * Revision 1.1 1991/09/06 18:47:47 ivan * Initial revision makefi l.c Convert DISPRO filter to SDL file. This function is called from a main C program to convert a single filter definition file (.FDF) to (.SDL), returns 0 if filter is successfully translated. « / /* requires */ ^include "sysfuncs.h" ^inc lude <stdio.h> ^inc lude <stdlib.h> ^inc lude <string.h> ^include <math.h> ^inc lude "strfunc.h" ^inc lude "gensd l.h" • *** » ********** »« ** /* exceptions */ /* constants */ ......««........... / define MAXNAME 32 ødefine MAXLINE 100 sdl code formatting info #define MAXSECT 50 /* maximum number of sections for iir */ #define MAXTAPS 512 /* maximum number of taps for fir */ #dβfine IIR 0 /* return code */ #define FIR 1 /* return code */ /- / 7 SUBSTITUTE SHEET iZ2 /* types */ typedef unsigned char uchar; /* data */ / .„..«... * .« * ...«». * / A* macros */ /* functions */ int get_dispro_fir_data(FILE * dis_file. double "coeffvec, char *t, int *iptr); int get_dispro_iir_data(FILE * dis_file, double *coeffvec, char *t, int *iptr, int *oddflag); double f r_coef[MAXTAPS]; double iir_coef[MAXSECT * 5]; char check_rec[MAXLINE]; int err, ret_code; int nuasect. oddflag; Get f lename from invocation strcpy(fname, name); strcpy(mystruc, struc); Mergenane(inpath, fname, ".fdf"); Mergenane(outpath, fname. ".sdl"); old style mergβname(datapath, fname, ".dat"); mergename(auxpath, fname, ".aux"); open input fi le ************"/ if ((infite = fopen(inpath. "r")) == NULL) £ printf("ERROR -- kf001 : Cannot open filter spec file Xs\n", inpath); return (-1); } Read first line of file to check FIR or IIR fgets(check_rec, MAXLINE, infile); check for DISPRO FIR format input file if (strncmp(check_rec, "\"<S>FIR", 7) == 0) £ err = get_dispro_fir_data(infi le, fir_coef, type_str, Snumsect); if (err -= -2) £ printf("ERROR -- mkf002: no coefficients in filter spec file Xs\n", inpath); return (-1); } else if (err != 0) £ printf("ERROR -- mkf003: problem with filter spec file Xs\n", inpath); return (-1); } printf("Creating Xs from Xs, FIR design\n", outpath, inpath); /*** old style no longer used auxfi le = fopen( auxpath, "w" ); datafi le = fopen( datapath, "w" ); write_fir_fi le(auxfi le, fname, type_str, numsect ); writβ_data_fi le(datafi le, fir_coef, numsect ); fclose(auxfi le ); fclose(datafi le); /* new style with split fir */ outfi le = fopen(outpath, "w"); wfir(outfi le, fname, type_str, numsect, maxtaps, fir_coef); fclose(outfi le); ret code = FIR; } ή ' ) ? SUBSTITUTE SHEET check for DISPRO IIR format input fi le else if (strncmp£check_rec, "\"<S>IIR", 7) = 0) £ err = get_dispro_iir_data(infi le, iir_coef. typejstr, &numsect, &oddflag); if (err = -2) £ printf ("ERROR — mkf004: no coefficients in Xs\n", inpath); return (-1); } else if (err != 0) £ printf("ERR0R — mkf005: problem with Xs\n", inpath); return (-1); } printf ("Creating Xs from Xs, IIR designVn", outpath, inpath); outfilβ = fopen(outpath, "w"); write_iir_file(outfile, fname, mystruc, typejstr. iir soef, numsect. oddflag); fclose(outfile); ret code = IIR; handle unrecognised file format else £ printf("ERROR -- mkf006: unrecognised filter file format Xs\n", inpath); ret sodβ = -2; } close files and return fclose(infile); return (ret sode); } /* Copyright (c) 1991 Star Semiconductor Corporation. All Rights Reserved. This material may not be copied or used without prior written permission. * $Id: gettff.c.v 1.4 1991/09/2022:31:43 ivan Exp $ * $Log: gettff.c.v $ * Revision 1.4 1991/09/20 22:31:43 ivan * Output nine digits precision of fitter coeffecients (had been 6) * * Revision 1.3 1991/09/16 19:06:33 ivan * Changed error messages to Star format * • Revision 1.2 1991/09/11 15:20:47 ivan * Support 'blocklen' parameter on 'filter' blocks to control splitting * of ilters longer than a sample period into seperate blocks. * * Revision 1.1 1991/09/06 18:47:45 ivan * Initial revision * */ gettff.c Read and process a *.tff transfer function file */ ..„........«....... /* requires */ / *************** « *** / #include "sysfuncs.h" (/include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <ctype.h> #include <f loat.h> #include "gensdl.h" #include "strfunc.h" /**** « ***** « ***** » **/ /* exceptions */ ,.„...„............ /* constants */ / ....„.......«...«. / #define MAXLINE 100 #define MAXSECT 10 #define PI 3.1415926535 ................... / /* types */ ?- / SUBSTITUTE SHEET «*/ data */ •*/ /* macros */ /* functions */ / ....»,............. char *extract j param j str(char *rec) ; int conv j stoz(int mode, double rate, double fcrit, double coef[], char *name) ; int conv_quad_stoz(double rate, double vect], int index) ; int conv_lin_stoz (double rate, double vec[] , int index) ; double lim2(double var) ; int gettff(char *name) £ FILE *infile. *outfile; char inpath[20], outpath£20]j /* for test only */ char tmp_rec[MAXLINE]; char tempstr[100]; char plane; double samplejrate. crit_freq, pwratβ, temp; double coef[6 * MAXSECT], packvec[5 * MAXSECT]; int nsect, order; int i, j. coef j det, exit sode, index: strcpy(inpath. name); strcp (outpath, name); strcat(inpath, ".tff") ; strcat(outpath. ".sdl") ; if ((infi le * fopβn(inpath, "r")) = NULL) £ printf ("ERROR -- gtfOOI: can't open input fi le XsVn". inpath) ; return (-1); } printf ("Creating Xs.sdl from Xs.tff. transfer function designXn", name, name) ; Initialise filter parameters, before reading fi le exit_code « 0; plane = 'n'; /* default plane */ sa plejrate = (double) 0; crit_freq = (double) 0; nsect = 0; order = 0; Process lines before coefficients coef et = 0; while (feof(infile) = 0) /* rip through the file */ £ fgets(tmp_rec, MAXLINE, infile); strtolw(tmp rec); if (strncmp(tmp_rec, "<c>", 3) == 0) £ coefjdet = 1; /* found coefficients */ break; /* go and process them */ } else £ if (strncmp(tmp_rec, "
", 3) == 0) plane = 's' ; if (strncmp(tmp_rec. "<z>". 3) == 0) plane = 'z' ; if (strncmp(tmp_rec, "sam", 3) == 0) £ strcpy(tempstr, extractjparam str(tmpjrec)) ; samplejrate = atof (tempstr); } if (strncmp(tmp_rec, "cri". 3) == 0) £ strcpy(tempstr, extractjparam str(t pjrec)) ; crit req = atof (tempstr) ; } if (strncmp(tmp_rec, "num", 3) == 0) nsect = atoi(βxtract_paramjstr(tmp_rec)) ; if (strncmp(tmp_rec, "ord", 3) == 0) order « atoi(extract_param_str(tmp_rec)); } } Parameter validation if (plane != 's' && plane != * z') £ printf("ERROR -- gtf002: no s-plane or z-plane specifiedXn"); exitjoode = -1 ; } if (plane == 's' && samplejrate <= (double) 0) £ printf("ERROR -- gtf003: sample rate must be greater than 0\n"); exit code ■ -1 ; r 3 SUBSTITUTE SHEET } if (nsect < 1 || nsect > MAXSECT) C printf("ERROR -- gtf004: number of sections must be between 1 and Xd\n", MAXSECT); exit sode = -1; > if (order < 1 || order >■ 2) £ printf("ERROR -- gtfOOδ: order must be specified as 1 or 2\n"); 3 Process coefficients if (coefjdet = 0) £ printf("ERROR — gtf006: no coefficients foundVn"); exitjsode = -1; 3 check for all parameters and coefficients present before continuing .,...«.,.,....„„...,....,.......„......«....»...,«....«.....„. / if (exit j sode !« 0) return (exit j sode); Read all coefficients if (order = 2) £ for (i = 0; i < nsect; i++) £ fscanf(infile, "Xlf. Xlf, Xlf, Xlf, Xlf", S.coefr.6 * i + 0], Scoef[6 * i +1], &coef[6 * i + 2], &coef[6 * i + 4], &coef[6 * i + 51); coef[6 * i + 3] = (doubte) 1; 3 else if (order = 1) £ for (i = 0; i < nsect; i++) £ fscanf(infilβ, "Xlf, Xlf, Xlf", &coef[6 * i + 1], Scoef[6 * i + 2], &coef[6 * i + 5]); coef[6 * i + 0] = (double) 0; coef[6 * i + 3] = (double) 0 coef[6 * i + 4] « (double) 1 3 3 fclose(infi le); /* DEBUG S A- 2- Ϊ printf("\n"); for (i=0; i<nsect; i++) £ for(j=0; j<6; j++) £ printf("X.9lf, ", coef[6*i+j]); 3 printf("\n"); 3 */ * * Translate s-planβ coefficients to z-plane * /* prewarp s-plane to maintain response at a critical frequency by artificially shifting down the rate, avoid division by zero at fcrit = 0 */ if (plane == 's') £ if (crit freq > (double) 0) £ temp = tan(PI * critjfreq / sample -ate) ; temp = samplej-ate / PI * temp; pwrate = sample 'ate * critjfreq / temp; 3 else £ pwrate = samplejrate; 3 Convert s-plane coefficients in the coefficient vector to z-plane via the bilinear transformation •/ if (order == 2) £ for (i = 0; i < nsect; i++) £ index = 6 * i ; conv_quad stoz(pwrate, coef, index); 3 3 if (order == 1) £ for (i = 0; i < nsect; i++) £ i ndex = 6 * i ; conv_lin_stoz(pwrate, coef, index); 3 3 3 /* End of s-plane conversion to z-plane */ /********** DEBUG Z *«**•«*** printf ("\n"); for (i=0; i<nsect; i++) £ for(j=0; j<6; j++) £ SUBSTITUTE SHEET printf("X.9If, ", coef[6*i+j]); printf("\n"); Coefficients are now in z-plaπe, generate a hierarchical .sdl file /* first pack 6 entry format coefficient vector to 5 entry format, since it is assumed that a0=1.0 always in the generate sdl program and the biquad sdl primitive. Pre-negate the a1, a2 coefficients for the biquad implementation during the packing. input = C bO. b1. b2. aO, a1, a2} ... output = C bO, b1. b2, -a1. -a23 ... */ j =0; for (i = 0; i < nsect * 6;) £ packvec[]++] = lim2(coef[i++]); packvecf ++] = lim2(coef[i++]); packvec[j++] = lim2(coef[i++J); i++; /* skip all aO coefficients */ packvec[j++] = -lim2(coef[i++]); packvec[j++] = -Lim2(coef[i++]); 3 Generate a hierarchical .sdl file if ((outfi lβ = f open (outpath, "w")) = NULL) £ printf ("ERROR -- gtf007: can't open output f le Xs", outpath) ; return (-1) ; 3 if (order = 2) C wπ " te_iir_file(outfi le. name, "biquad", "tranfuπc", packvec, nsect, 0); 3 else if (order = 1) C write_ii r_fι le(outf le, name, "bi linear", "tranfunc", packvec, nsect, 0) ; 3 fclosβ(outfi le) ; return (exitjsode) ; Conversion of S-plane quadratic into 1-plane. A- - G int conv_quad_stoz(double rate, double vec[], int index) £ int exitjsode, i ; double a, b, c, t, norm; exit j sode = 0; t = 1 / rate; a = vec[index + 0] b = vee[index + 1] c = vec[index + 2] vec[index + 0] = 4 a / (t * t) + 2 * b / t + c; vec[index + 1] = 2 c - 8 * a / (t * t); vecfindex + 2] = 4 a / (t * t) - 2 * b / t + c; a = vec[index + 3] b = vec[index + 4] c = vec[index + 5] vec[index + 3] = 4 * a / (t * t) + 2 * b / t + c; vec[index + 4] = 2 * c - 8 * a / (t * t); vec[index + 5] = 4 * a / (t * t) - 2 * b / t + c; /* Normalise array to numerator b0=1.0, denominator to a0=1.0 */ norm = vec[index + 3]; for (i = 0; i <= 2; i++) £ vec[index + i] = vec[index + i] / norm; 3 norm = vecfindex + 3]; for (i = 3; i <= 5; i++) £ vec[index + i] = vecfindex + i] / norm; 3 return (exit j sode); In-place conversion of S-plane linear into Z-plane. int conv_ I in_stoz( double rate, double vec[], int index) £ int exit code. -A7 SUBSTITUTE SHEET i; double b, c, t, norm; exit j sode =• 0; t = 1 / rate; b » vecfindex + 1]; c = vβc[index + 2]; vec[index + 0] = (double) 0; vec£index + 1] = c + 2 * b / t; vec[index + 2] = c - 2 * b / t; b = vec[index + 4]; c = vec[index + 5]; vec[index + 3] = (double) 0; vec[index + 4] = c + 2 * b / t; vec[index + 5] = c - 2 * b / t; /* Normalise array to numerator b0=1.0, denominator to a0=1.0 */ norm = vec[index + 4]; for (i 0; i <= 2; i++) £ vec[index + i] m vec[index + i] / norm; 3 norm m vec[index + 4]; for (i = 3; i <= 5; i++) £ vec[index + i] « vecfindex + i] / norm; 3 return (exitjsode); Return rhs of equality statement ««.......„.,...... * . * ......... / char *extract_param_str(char *rβc) £ int i = 0. j -0; char text[201; char c * "\n * ; /* initialise for test */ while (c !« '«') /* eat Ihs */ £ c » rec[i++]; /* advance pointer */ 3 wh le (c 1= '\0') £ c * rec[i]; if (isspace(c) ■* 0) C A'ΛP text[j ] «= c; /* copy string */ 3 i++; 3 return (text) ; double I im2( doub le var) £ if (var >= 2.0) var = 1 .999999; else i f (var < -2.0) var = -2.0; return (var) ; 3 JUNK make_lin(double vec[], char *name) £ FILE "outfile; char outpath[32]; strcpy(outpath. name); strcat(outpath, ".sdl"); outfi le = fopen( outpath, "w" )i fprintf( outfi le, block Xs £3 (in; out)\n", name ); fprintf{ outfi le, begin\nbi Linear Xs1\n £\n", name ); fprintf( outfile, XXbO=X.9lf,\n», vec[1] ); fprintf( outfile, XXb1=X.9lf.\n", vec[2] ); fprintf( outfi le, XXa1=X.9lf\n", vec[5] ); fprintf( outfile. }\n (in, out);\nend\n" ); fclose(outf le); return(O); */ A' L ? SUBSTITUTE SHEET /* Copyright- (c) 1991 Star SeMieonductor Corporation. All Rights Reserved. This Material May not be copied or used without prior written permission. * Sid: gβnfdf.cv 1.1 1991/09/0618:47:35 ivan Exp $ * $Log: genfdf.c,v $ • Revision 1 .1 1991/09/06 18:47:35 ivan * nitial revision * */ Generate a .fdf file for DISPRO analysis of biquad stages */ /* requires */ /........«...*.«..../ ^include <stdio.h> #includβ <string.h> ................... /* exceptions */ /• constants */ /* types - */ /* data */ /* Macros */ /* functions */ genfdf(double vec[], char •name, double rate, int nsect) £ FILE *outfile; char outpath[32]; strcpy(outpath, name); strcat(outpath, ".fdf"); outfile = fopen(outpath, "w"); fprintf(outfi "\"<S>IIR Filter Specifications\"\n"); fprintf(outfi "\" Type=\".\"LOWPASS\"\n"); fprintf(outfi "\" Order= \",2\n"); fprintf(outfi "\" Sampling frequency=\",Xli\n", (long) rate); fprintf(outfi "\" Passband:\",1000,0\n"); fprintf(outfi "\" Stopband:\",1200,0\n"); fprintf(outfi "\" Passband ripple:\",.5\n"); fprintf(outfi "\" Stopband loss:\".112\n"); fprintf(outfi "\"<OCoefficients (A,D,E,B,C) for wordlength \",24\π"); fprintf(outfi "1,Xlf,Xlf,Xlf,Xlf,Xlf\n", vec[0], vec[1], vec[2], vec[4], vec[5]); fclose(outfi le) return (0); A- 3/ SUBSTITUTE SHEET 136 int dumay=1; A-3 Copyright (c) 1991 Star Semiconductor Corporation. All Rights Reserved. This material may not be copied or used without prior written permission. * $Id: exspf.c.v 1.21991/09/16 19:06:29 ivan Exp $ * SLog: exspf.c.v $ * Revision 1.2 1991/09/16 19:06:29 ivan * Changed error messages to Star format * Revision 1.1 1991/09/06 18:47:33 ivan * Initial revision / exspf.c 3pen a ".spf" f le which is expected to contain a list, one per line, of filenames ".fdf" or ".tff". Depending on the extension call the appropriate translator to make ".sdl" files for the Scompile. For filters a total of (1+N) ".sdl" files are created, where N is the number of filters in the list. Also a ".dat" or a number of ".d?7" files are created for each fir in the design. For Transfer functions M ".sdl" files are made, where M is the number of ".tff" files in the list. •/ /* requires */ /......«...»......../ ^include <stdio.h> Pinclude <stdlib.h> ^include <str ng.h> ^include <ctype.h> ^include "strfunc.h" include "exsdl.h" / „.....„..,.....». / /* exceptions */ /* constants •/ /• types */ static char exspf [] = "SRevision: 1 .2 $"; - 3 3 SUBSTITUTE SHEET /* Macros */ /* functions */ int make_filter( char *name, char "struc ); int gettff( char *name ); jfdefine MAXLINE 80 /** • • • *•* •« * main program * • * •« ** • • • */ void main(int argc, char *argv[]) £ FILE *inf le; char fπame[MAXNAM], ext[MAXEXT]; char inpath[MAXNAM]; char linβ[MAXLINE], tmprec[MAXLINE]; char c; int i. count; .....««........«.......«...... process command line parameters .«.....................«.....,/ printf ("\nExspf Xs\n». exspf) ; printf ("Copyright (C) 1991 by STAR Semiconductor Corporation n") ; if (argc > 1) C strtolw(argv[1 ]); if ({strcmp(argv[1], "-h")=0) | | (strcmp(argv[1 ] , "/h")=0)) £ printf("Usage: exspf filename[.spf]\n"); exit{ -1 ); 3 else strcpy(inpath. argvf.1]); 3 else £ printf("Usage: makesdl filename[.net]\n"); exit( -1 ); 3 make input and output filenames .«...,.......*.*......,......*/ splitname( inpath, fname, ext); if (strcmpfext, ".sdl")«=0) printf("ERROR -- expOOl: input file cannot be \»Xs\"\n".ext); 3 else if (strcmp(βxt, ».dat")==0) £ printf("ERROR -- exp002: input file cannot be \"Xs\"\n".βxt); exit( -1 ); 3 else if(strcmp(βxt, »")«=0) /* append default extension */ £ strcpy(ext, ".spf"); mergename(inpath, fname, ext); 3 Process input f le if ( check _βpβn_rf( Sinfile, inpath ) != 0) exit(-1); while(1) £ fgets( tmprec. MAXLINE. infile ); break; strcpress(t prec); splitname( tmprec, fname, ext); if(strncmp(ext, ".fdf", 4)«=0) £ makejfilter( fname, "biquad"); 3 if(strncmp(ext, ".tff". 4)=0) £ gettff (fname); 3 3 fclose( inf le ); 6X1t( exitjsode ); A-3S- SUBSTITUTE SHEET Copyright (c) 1991 Star Semiconductor Corporation. All Rights Reserved. This material may not be copied or used without prior written permission. * Sid: exsdl.c,v 1.31991/09/1619:06:26 ivan Exp $ * $Log: βxsdl.c.v S • Revision 1.3 1991/09/16 19:06:26 ivan * Changed error messages to Star format * * Revision 1.2 1991/09/11 15:20:36 ivan • Support 'blocklen' parameter on 'filter' blocks to control splitting • of filters longer than a sample period into seperate blocks. * • Revision 1.1 1991/09/06 18:47:27 ivan • Initial revision /******* « ******* « ******** « *** : ******** % * « **' •a-**-*************************** exsdl.c Expand a psuedo sdl file to SDL by substituting the "spec" parameter value for the keyword FILTER or TRANSFNC. Write the list of filters a . nd transfer functions to an SPF file. • / /* requires */ /....«..........««./ #include "sysfuncs.h" #include "βx sarse.h" #include <stdio.h - ^include <stdlib.h> #include <string.h> #include "strfuπc.h" #include "exsdl.h" ................... / /* exceptions •/ /* constants */ /* types */ /* data */ static char βxsdlf] = "SRevision: 1.3 $"; - 3 ζ 1 . /« GLOBAL STORAGE for interfacing to parser and lexical analyser */ char tmprec[MAXRL]; /* holds latest identifier */ char instrec[MAXRL], specrec[MAXRL]; /* current instance, spec */ char typerβc[MAXRL] = {""}; /* current type */ char flist[NOP][ AXNAM]; /• filter list •/ char tlist[NOT][MAXNAM]; /* transfnc list */ int flc = 0, tic = 0; /* counters */ extern FILE *yyin, •yyout; /* macros */ /* functions */ void main(int argc, char *argv[]) £ FILE *listfile; char inpath[MAXNAM], outpath[MAXNAM], listpath[MAXNAM]; char fname[MAXNAM], ext[MAXEXT]; Check command line parameters printf("\nExsdl Xs\n", exsdl); printf("Copyright (C) 1991 by STAR Semiconductor Corporation.\n"); if (argc > 1) £ strto lw(argv[1 ] ) ; if ((strcmp(argv[1 ], "-h") == 0) | | (strcmp(argv[1 ], "/h") == 0)) £ printf ("Usage: exsdl f i lename[ .pd l]\n") ; 3 else strcpy(inpath, argv[1 ] ) ; 3 else £ printf("Usage: exsdl fi lename[.pdl]\n"); exit(-1); 3 make input and output f lenames splitname(inpath, fname, ext); 4- 3 7 S BSTITUTE SHEET 1A2 if (strcmp(ext, "") = 0) /* append default extension « / £ strcpy(ext, ".pdl"); Hergename(inpath, fname. ext); 3 mergename(outpath, fname, ".sdl"); mergename(listpath. fname, ".spf"); open input and output files if ((yyin = fopβn(inpath, "r")) =» NULL) £ printf("ERROR -- exs001: failed to open Xs\π", inpath); 3 if {(yyout = fopen(outρath. "w")) = NULL) £ printf("ERROR -- exs002: failed to open XsVn", outpath); exit(-1); 3 Process input file printfC'Crβatiπg Xs. Xs from Xs\n". outpath, listpath. inpath) yyparse(); fclose(yyin); fclose(yyout); /,..,.....*.*...*« Write list to fi le ........„.......» / if {(listf le = fopen( listpath. "w")) == NULL) C printf ("ERROR — exs003: fai led to open Xs\n", listpath) ; exit(-l) ; 3 whi le {-- flc >= 0) fprintf ( listfi le, "Xs.fdfxn", flist[flc]) ; whi le (—tic >= 0) fprintf (list i le, "Xs.tffXn", tlist[tlc]) ; fclose( listf i le) ; A- 3 /* Copyright (c) 1991 Star Semiconductor Corporation. All Rights Reserved. This material may not be copied or used without prior written permission. • Sid: exnet.c.v 1.41991/09/2004:23:58 ivan Exp $ • $Log: exnet.c.v $ • Revision 1 .4 1991/09/20 04: 23:58 ivan • Minor fixes * • Revision 1.3 1991/09/16 19:06:20 ivan • Changed error messages to Star format * • Revision 1.2 1991/09/11 15:20:33 ivan • Support 'blocklen' parameter on 'filter' blocks to control splitting • of filters longer than a sample period into seperate blocks. * • Revision 1.1 1991/09/06 18:47:21 ivan • Initial revision exnet.c Extracts psuedo sdl by scanning the viewlogic database which is created when a schematic is saved. Actually the schematic must be saved then annotated before this program is run. This is a modifified version of the ViewLogic demonstration program "flatnet.c". The following comment is from there. * Facility: VIEWBASE Demonstration Program * Functional Description: * This program demonstrates how to generate a simple flat * netlist using the VIEWBASE access routines. Almost all * design types are accessed: components, nets, pins, and * attributes. In addition, this program demonstrates how * to evaluate parameterized attributes, how to create a * synonym table, and how to build unique component and * net path names from the original hierarchical description. * * A flat netlist consists of a single MODULE description * for an entire (possibly hierarchical) schematic design. * The basic format of the netlist is as follows: * MODULE module_name(symbol_attr ...) ; INTERFACE * sympin_namβ(sympin_attr ...)=net_name ... ; COMPONENTS * symbol iame comp_name(comp_attr ...) * compinjιame(compin_attr )=net_name ; * NETS * nβt ιame(nβt_attr . . . ) compjiame.compinjia e — ; END MODULE r r 3 ? SUBSTITUTE SHEET The MODULE statement defines the name of this module and contains a optional list of symbol attributes. A semicolon terminates the module statement. The INTERFACE section defines the interface to the module. The format defines the connection between the external view (symbol) of the module and the corresponding nets on the underlying schematic. An optional list of symbol pin attributes may follow the sympin name. The INTERFACE section is terminated by a semicolon. The COMPONENTS section defines a component orientated view of the schematic. Each component statement specifies the component type (symbol name), the component name, and the net connected to each component pin. An optional list of component attributes may follow the component name. The COMPONENTS section is terminated by a semicolon. The NETS section defines a net orientated view of the schematic. Each net statement lists the component pins connected to this net. An optional List of net attributes may follow the net name. The NETS section is terminated by a semicolon. Flattened netlists usually require that the full path name of each component instance is used. This path name is a concatenation of the names of the components passed through while decending the design hierarchy. The full path name uniquely identifies each component in the design's flattened representation. This program demonstrates how to create hierarchical path names. Flattened netlists also require that the top-most netna e be used when refering to nets which transcend the design hierarchy (pass through symbol pins). This insures that nets which are electrically equivalent use the same name when the design is flattened. This program demonstrates how to find the top most net name. This program also demonstrates the use of a synonym table for generating a unique name when the flattened component or net name is unacceptable to the target system. Copyright (c) 1986 by Viewlogic Systems, Inc. rβquires #include "sysfuncs.h" ^include <stdlib.h> ^include malloc.h> ^include <string.h> linelude <stdio.h> /* standard I/O */ #include <ctypβ.h> /• char type macros •/ finclude "viewbase.h" /• data base access routines •/ #include "strfunc.h" /* utility string functions */ exceptions /* constants */ #define VERSION "1.10" /* netlister version number */ #define EXFAILURE 1 /* failure exit code */ #define EXSUCCESS 0 /* successful exit code */ #define EBUFSIZ 400 /* evaluation buffer size */ /• SPROC stuff •/ #define MAXPARAM 12 /* parameters per icon */ #define ARRAY WIDTH 32 /* for SPROC parameters */ /* types */ data static int Attrjsn = 1; /* attribute output flag */ static int Evaljsn = 1; /* attribute evaluation flag */ static int Syn sn = 0; /* synonym creation flag — force off */ /* macros */ /* functions */ /* ============= SYNONYM TABLE DATA STRUCTS AND ROUTINES The synonym table routines generate a unique synonym for each unique input name. The input name can be any char string. The output name, (the synonym) has the general format: <prβfixxinteger value>. for example, S23. The integer portion of the synonym is incremented for each new unique input name. The routines and structures are easily modified to generate a different format if the current one is unexceptable to the target simulator or layout system. #define HASHSIZE 101 /* synonym hash table size •/ #define PREFIX «S" /• synonym prefix •/ typedef struct namerec { /* storage record for one name */ char "name; /* pointer to the original name */ A- Ϋ/ SUBSTITUTE SHEET unsigned int id; /* unique id created for the new name •/ struct namerec *nexthash; /• next record in hash link • / struct namerec *nextid; /* next record in entry order link */ 3 NAMEREC; static HAMEREC « Namelιst[HASHSIZE]; /* hash table of converted names •/ static NAMEREC *Listhβad « NULL; /* first record in order of entry */ hash create hash table index. static int hash(char* s) /* name */ £ unsigned int hashval; for (hashval = 0; *s; s++) hashval = hashval * 10 + *s; return((int)(hashval X HASHSIZE)); 3 / • hash */ /• *-new_πame • if the oldname is not already in the synonym table, • create a new name and record the new and old names in • the table. •/ static char "new_name(char* oldname) C int index; NAMEREC *np; static unsigned int uid = 0; /* id counter • / static NAMEREC "tail * NULL; /* last record in entry order */ static char newname[20]; /* synonym */ if (ISyn sn) return(oldname); /• synonym creation disabled • / index = hash(oldna e); / • get hash table index • / /• see if oldname has already been converted • / for (np ■ Namel st[index]; np != NULL; np = np -> nexthash) if (strcmp(oldname, np -> name) = 0) break; /* found it V if (np =- NULL) £ /* create a new entry */ np = (NAMEREC *) Hal loc(sizeof (NAMEREC)); np -> name » «alloc(str len(oldname) + 1) ; strcpy(np -> name, oldname) ; np -> id » uid++; /* assign a new unique id */ np -> next d « NULL; /* link into the hash table list */ np -> nexthash » Name list [index] ; Name list [index] * np; - *~ /* link into the id order list */ if (Listhead == NULL) £ Listhead = np; 3 else tai I -> nextid = np; tai I = np; /•• return new name */ sprintf(nβwname, "XsXu", PREFIX, np -> id); return(newname); } / • newjiame */ /• * legalna e * test for a legal FLAT name under the following rules: * - first char must be alphabetic. * - second and following chars must be alphanumeric. * - maximum length must be <= 8 chars. * illegal names will be converted to synonyms. */ static char *legalname(char* name) £ int i ; static char nu l lstr[] = "" ; if (name == NULL) £ /* (not necessari ly an error) */ return(nullstr); 3 if (!isalpha(name[0])) £ /* non-a lphabetic fi rst char */ return(new_name(name) ) ; for (i = 1; name[i]; i++) £ if (!isalpha(name[i]) && !isdigit(name[i])) { /* non-alphanumeric embedded char • / return(new_name(name)); 3 if (i >= 8) £ /* name to long */ return(new ιame(name)); 3 return(name); /* return original */ } /* legalname */ #if 0 /• * dump synlist * write out the cross reference list of synonyms together with * the original names to the specified file. •/ static void du p synlist(fp) FILE *fp; A^3 SUBSTITUTE SHEET NAMEREC *np; if (!Syn_on) return; /* synonym creation disabled */ iprintf(fp. « « *\n* « N A M E S U B S T I T U T I O N S\n**\n") ; iprintf(fp, "** New Name Origina n") ; iprintf(fp» "** - \n") ; for (np = Listhead; np != NULL; np = np -> nextid) iρrintf(fp. "•* XsX-12u Xs\n», PREFIX, np -> id, np -> name) ; iprintf(fp, "**\n* End of Netlist\n ,r ) ; 3 #endif /• == CONTEXT ROUTINES • Routines to manage the context data structure. This data structure * consists of a linked List of pointers to COMPONENT structures. This • stack of pointers defines a path from the topmost component down to * the "current" component, i.e. it defines a unique "context". #define MAXNAME 1024 /* max length of hierarchical name •/ static char hiername[MAXNAME] = ""; / • storage for hierarchical name •/ typedef struct ccontext f. struct ccontext "next; /• next component in stack */ COMPONENTS « c; /* current component */ 3 CCONTEXT; static CCONTEXT *cntxt_list = NULL; /* list of component pointers •/ * cntxtjjush • Modify the context by pushing into a component. •/ static void cntxt_push(COMPONENTS* comp) £ CCONTEXT «cp; cp = (CCONTEXT *) malloc(sizeof (CCONTEXT)) ; cp -> c a comp; cp -> next =s cntxt_list; cntxt_list at cp; 3 /* cntxt_push */ cntxt_pop Modify the context by poping out of a component. •/ static void cntxt sopQ £ CCONTEXT *cp; A- y if (cntxt_list != NULL) £ cp = cntxt_list -> next; free(cntxt_list); cntxt_list = cp; 3 3 /* cπtxt pop */ /* * addpath • Build the context hierarchy name. */ static void addpath(char* buf.CCONTEXT* cp) £ if (cp == NULL) return; if (cp -> next != NULL) addpath(buf , cp -> next) ; strcat(buf , igcomnam(cp -> c) ) ; strcat(buf , "\\") ; 3 /* addpath */ /• * cntxt_name * Return the component context hierarchy name. */ static char *cntxt_name(char* name) £ strcpy(hiername, ""); addpath(hiername, cntxt_list); strcat(hiername, name); return(hiername); 3 /* cntxt name */ / • upperjiet • returns a pointer to the net connected on the level above • or NULL if the specified net is not an 10 net or there's no • net on the level above. */ static NETS *upper_net(NETS" netp,CCONTEXT* cp) £ SYMPINS "spnp, *spnp2; NETS 'uppernet; int i; if (cp == NULL) cp = cntxt_list; /* set to top of stack */ if (cp == NULL) return(NULL); /* nothing on stack •/ /* first find out if this net is connected to an interface pin */ spnp = igsymspn(igcomsym(cp •> c)); for (i = 1; spnp !» NULL; spnp = igspnnxt(spnp), i++) SUBSTITUTE SHEET if (igspnnet(spnp) — netp) break; /* match */ if (spnp = NULL) /* not an interface pin */ return(NULL); /* get net connected to this pin on the next highest level */ uppernet = igpinnet(ifpinpin(i, igcompin(cp -> c))); /* see if net is connected to more than one interface pin... */ /* if so. then a unique name for this signal cannot be determined. */ for (spnp2 = igspnnxt(spnp); spnp2 != NULL; spnp2 = igspnnxt(spnp2)) £ if (igspnnet(spnp2) = netp) £ iwmsgout(WARNING, "Warning - Net Xs connects pins Xs and Xs of symbol Xs.\n", ignetnam(netp), igspπnam(spnp), igspnnam(spnp2), iggrpnam(igsymown(igcomsym(cp -> c)))); 3 3 returπ(uppernet); 3 /' r upper iet */ " cntxt_netname * Return the highest level net name. */ static char *cntxt_netπame(NETS* netp) £ NETS "parβntnet; CCONTEXT *cp; for (cp = cntxt_list; cp != NULL; cp = cp -> next) £ if ((parentnet = upper_net(netp, cp)) = NULL) break; /* stop at topmost net */ if (ignettyp(netp) = GLOBAL_NET) { if (ignettyp(parentnet) = LOCAL_NET) £ /* we are ignoring a global net which occurs on */ /* the subcircuit. this may not be what the */ /* user wants so a warning is in order. */ iwmsgout(WARNING, "Warning - Global net Xs on subcircuit Xs is being ignored.\n". ignetnam(netp), iggrpnam(ignetown(netp))); iwmsgout(WARNING | NOINC. " Using signal name from level above.\n"); 3 else if (strcmp(ignetnam(netp), ignetna (parentnet)) 1= 0) £ /* global nets with different names are tied together. */ /* this may be a design error. */ iwmsgoutfWARNING, "Warning - Global net Xs on subcircuit Xs\n", ignetnam(netp). iggrpnam(ignetown(netp))); iwmsgout(WARNING | NOINC. " is tied to global net Xs on schematic Xs above.\π", ignetnam(parentnet). iggrpnam(ignetown(parentnet))); A^ G /* continue search on next highest level */ netp •> parentnet; 3 strcpy(hiername, ""); if (ignettyp(netp) == LOCAL_NET) addpath(hiername, cp); /* global nets do not have a path prefix */ strcat(hiername, ignetnam(netp)); return(hiername); } /* cntxt j iβtname */ /* ================= DESIGN STRUCT PROCESSING ROUTINES ================= */ /* * modelname * returns either the value of the MODEL attribute or the * group name. */ static char "modelname(GROUPS* grpp) £ ATTRIBUTES *attp; if (iggrpsy (grpp) != NULL) ( if ((attp = ifattatt("MODEL",igsymatt(iggrpsym(grpp)))) != NULL) £ return(igattva l(attp) ) ; 3 3 return (iggrpnam(grpp) ) ; } /* mode lname */ ?if 0 / « * refdesname * returns either the value of the REFDES attribute or the * group name. •/ static char *refdesname(grpp) 3R0UPS *grpp; £ ATTRIBUTES *attp; if (iggrρsym(grpp) != NULL) £ if ((attp = ifattatt("REFDES",igsymatt(iggrpsym(grpp)))) != NULL) £ return(igattval(attp)); 3 3 return(iggrpnam(grpp)); 3 /* refdesname */ *endif /* * primitive * component is primitive if its symbol representation is of type * MODULE or has a matching LEVEL attribute. A- 7 SUBSTITUTE SHEET static int primitive(COMPONENTS* comp) £ SYMBOLS "symp; symp s igcomsym(comp); if (igsymtyp(symp) == MODULE_TYPE) rβturn(l); if (iwgetlevel(igsymatt(symp)) != NULL) return(l); return(O); } /* primitive */ * status_line * displays the line "Processing <name> \r". Only enough spaces * after <name> as required to cover the last line are output. */ static void status_Line(const char* name) £ static int las len = 0; static char buf[150] = "Processing "; int len, i; strcpy (Sbuf [11 J .name) ; len = strlen(na e) + 11 ; for (i = len; i < lastlen; in buf[i] = ' * ; buf[i] - -Vr'; buf[i+1] = '\0' ; lastlen = len; fputs(buf,stdout); 3 / • status_line */ * eval sttribute * expand and evaluate and output one attribute, if the g lobal * evaluation f lag Eval sn is FALSE, then the attribute is output as is. • I static void βvat sttributβ(FILE* fp, ATTRIBUTES* attp,int first) £ static char evalbuf[EBUFSIZ] ; int status; if (Evaljsn) £ /* expand and evaluate the attribute value */ status » ipevaluate(evalbuf, igattval(attp), EBUFSIZ) ; 3 else £ /* use unevaluated attribute value */ strncpy(evalbuf. igattval(attp) . EBUFSIZ); evalbuf[EBUFSIZ-1] = '\0' ; 3 iprintf(fp. "XsXs=\"XsV"", (first? "": " ") , igattnam(attp) . evalbuf) ; A- ? if (Eval sn) £ if (status != 0) { /* expansion or evaluation error occured "/ iwmsgout(ERROR, "Error - Xs", ipgetmsg(status)); 3 3 3 /* eval j attribute */ #if 0 / * wr_sproc_attr * expand and evaluate and output one attribute, if the global * evaluation flag Eval j sn is FALSE, then the attribute is output as is. */ static void wr_sproc_attr(fp, attp, fst) FILE "fp; ATTRIBUTES "attp; int fst; £ static char evalbuf [EBUFSIZ] ; strcpy(eva lbuf , igattva l(attp) ) ; eva lbuf[EBUFSIZ-1 ] = * \0' ; iprintf(fp, "XsXs=Xs\n", (fst? "": " ") , strto lw(igattnam(attp) ) , strtolw(evalbuf )) ; #endi f /* * do_attributes * this routi ne is used to output net and interface symbo l pi n * attributes. */ static void do_attributes(FILE* fp,ATTRIBUTES* attp) £ int first = 1 ; if (Attr j sn) £ iprintf(fp, "("); for (; attp != NULL; attp = igattnxt(attp)) £ eval_attribute(fp, attp, first); first = 0; 3 iprintf(fp, ")"); 3 } /* do_attributes */ /* -- * do_comp_attributes " this routine is used to output a component and its symbol * attributes, it uses the igcossat() "Component attributes * Override Symbol attributes" routine to get unique attributes. */ static void do_comp_attributes(FILE* fp,COMPONENTS* comp) £ ATTRIBUTES "attp; char current icon [MAXPARAM] [ARRAY_WIDTH] ; char current_rβfdes [ARRAY_WIDTH] = { "" 3 ; A- ? B TITUTE HEET char current_device [ARRAY_WIDTH] = £ "" 3; char name [ARRAYJHDTH] ; char val [ARRAY_WIDTH]; int i=0, special; char c; /* flush array */ whi le(i < MAXPARAM) £ current_icon[i][0]='\0'; i++; 3 /* for all component and symbol attributes */ attp = NULL; i=0; white {(attp = igcossat(comp, attp)) 1= NULL) £ /* strcpy(evalbuf. igattval(attp)) ; βvalbuf[EBUFSIZ-1] = '\0'; */ special=0; strcpy (name, strto lw(igattnam(attp) ) ) ; strcpy( va I, strto lw(igattva l(attp) ) ) ; if(strcmp(name, "device")=0) £ strcpy (current_device, val) ; special=1 ; 3 if(strcmp(name, "refdes")=0) £ strcpy(current_rβfdes, vat); special=1; 3 if( special < 1 ) £ strcpy( current_icon[i], name ); strcat( current_icon[i], "=" ); strcat( current_icon[i], strtolw(igattval(attp)) ); i++; 3 /* dump sdl thro paramemter list */ iprintf(fp, "\nXs Xs\n£", currentjdevice, current_refdes); i=0; C=' '; while((i < MAXPARAM) && (current_icon[i][0] != '\0')) £ iprintf(fp » "Xc\n XXXs", c, current_icon[i J) ; i++; 3 iprintf(fp, "\n3") : A - /• iprιntf (fp, "Xs=Xs\n", strto lw(igattnam(attp) ) , strto lw(eva lbuf ) ) ; */ 3 /* do_comp_attributes */ #if 0 /* * do_pin_attributes * this routine is used to output component pin and symbol pin * attributes, it uses the igcospat() "Component pin attributes * Override Symbol pin attributes" routine to get unique attributes. */ static void do_pin ittributes(fp, pinp) FILE "fp; PINS "pinp; £ ATTRIBUTES "attp; int first = 1 ; if (Attr sn) £ iprintf(fp, "("); /* for all component pin and symbol pin attributes */ attp » NULL; whi le ((attp = igcospat(pinp, attp)) != NULL) { eva l_attribute(fp, attp, fi rst) ; fi rst = 0; 3 iprintf(fp, ")") ; 3 3 /* do_pin_attributes */ #endi f /* * list_net_pins * list all component pins connected to this net. for composite " components, the net is followed down into the component's * subcircuit. */ static void list_net_pins(FILE* fp.NETS* netp) £ PINS "pinp; COMPONENTS "comp; char buf[30]; for (pinp = ignetpin(netp); pinp != NULL; pinp = igpinnnx(pinp)) { comp = igpinown(pinp); if (primitivβ(comp)) { /* print component and pin names */ sprintf(buf, "Xs.". legalname(cntxt ιame(igcomnam(comp)))); strcat(buf, legalname(igspnnam(igpinsρn(pinp)))); iprintf(fp, " Xs", buf); 3 else £ /* push into composite component */ cntxt_push(comp); list_net pins(fp, igspnnet(igpinspn(pinp))); A-S/ BSTITUTE SHEET cntxtjpop{); 3 3 } /* list_net_pins */ /* * do_nβtlist * This is the main body of the net orientated listing. We first * cycle through each net on this level and for each net that is a * top level net, we list all the component pins connected to that * net (following the nets into all subcircuits). Next, we walk * all components on this level and recursively process any that are * composite. » / static void do_πetlist(FILE* fp.GROUPS* grpp) £ COMPONENTS "comp; NETS "netp; nt stat; char delim[3]; /* list delimiter if only one element */ strcpy(dβlim. "") ; status_line(iggrpnam(grpp)) ; if (Evaljon) £ /* push the variable definition table */ ippushlev(); 3 /* list all top level nets and their component pins */ iprintf(fp, "wire\n"); for (netp * iggrpπet(grpρ); netp 1= NULL; netp = ignetnxt(netp)) £ if (upper_net(netp, NULL) = NULL) £ /* this is a top level net */ write wire list to output fi le if( *legalname(cntxt_netname(netp)) = '$') iprintf(fp, "Xs _Xs". delim, legalname(cntxt_netname(netp))) ; else iprintf(fp, "Xs Xs", delim, legalname(cntxt_netname(netp)) ) ; strcpy(delim, ",\n") ; /* change delim for more elements */ /* NOTE: Only attributes from the top level net are output. */ /* Additional processing wou ld be required to find and */ /* output attributes from a ll of this net's subnets. */ /"•* do_attributes(fp, ignetatt(netp)) ; listjΛβt_pins(fp. netp) ; iprintf(fp, ".\n») ; « **/ A- 15? terminate wi re list iprintf(fp, " ; \n\n") ; /* push into all composite components */ comp =s NULL; while ((comp = iggrpcom(grpp, comp)) != NULL) { if (Iprimitive(comp)) { /* push into composite */ if (Evaljsn) { /* add variable defs for this component to the table. */ /* (in the do somplist() routine, variable definitions */ /* were loaded for both primitive and composite */ /* components... however, since we're only evaluating net */ /* attributes in this case, we only need */ /* to load definitions off composite components.) */ if ((stat = ipaddvardefs(co p)) != 0) { printf("ERROR -- exn001 : Error loading definition: Xs\n". ipgetmsg(stat)}; 3 3 cntxtjpush(comp); do ietlist(fp, igsymown(igcomsym(comp))); cntxt_pop(); if (Evaljsn) £ /* de lete this component's defi nitions */ ipdelvardefsO ; 3 3 if (Eva ljsn) £ /* pop the variable defini tion tab le ippoplev() ; 3 3 /* do_net tist */ /* * list_compjpins * this routine cycles through all the pins on the component and * lists the names of the nets connected to pins, unconnected * pins will produce a warning message. « / static void listjsomp_pins(FILE* fp,COMPONENTS* comp) £ #define MAXIO 16 NETS *netp; PINS *pinp; ATTRIBUTES "attp; int unconnectedjsins = 0; /* arrays for storage of in and out nets */ char innets [MAXIO] [ARRAY_WIDTH]; char outnets [MAXIO] [ARRAY_WIDTH]; char netna e [ARRAY WIDTH]; A'S3 SUB TIT TE SHEET char direction [ARRAYJKIDTH]; char name [ARRAYJKIDTH]; char val [ARRAYJflDTH]; int pinnuαber=0; int i; char delim[10]; /* flush arrays */ i=0; while(i < MAXIO) £ innets [i]£0J = '\0 * ; outnets[i][0] = '\0'; i++; 3 /* for all component pins ... */ for (pinp = igcompin(comp); pinp != NULL; pinp = igpincπx(pinp)) £ /* get pin name iprintf(fp. " Xs", legalname(igspnnam(igpinspn(pinp)))); « / /* output component pin attributes do_pin_attributes(fp, pinp); */ /* get the name of the net attached to the pin. the cntxt_netname() routine returns the topmost netname */ if ((netp = igpinnet(pinp)) !*t NULL) £ strcpy{netname, tegalname(cntxt_netname(netp))); 3 else £ ++unconnected_pins; 3 /* for alt attributes, extract only pinnuπber and direction */ attp a= NULL; whi le ((attp t igcospat(pinp, attp)) != NULL) £ strcpy(name, strtolw(igattnam(attp))); strcpy(val, strtolw(igattval(attp))); if(strcmp(name, "#")==0) pinnumber = atoi(val); if(strcmp(name, "pintype")=0) strcp (dirβction, vaI); /* We have direction, pinnumber and net name here, update arrays */ if ( strcmp(direction, "in") = 0) strcpy( innβts[pinnumber], netname); else strcpy( outnets[pinnumber], netname); /* all pins */ A-sy /* Print input array */ strcpy(delim, ""); iprintf(fp. "\n(\n "); i = 0; whi le(i < MAXIO) £ if ( innets[i][0] != '\0') /* skip empty fields */ £ if (innets[i][0] == '$') iprintf(fp, "Xs_Xs", delim, innets[i]); else iprintf(fp, "XsXs", delim, innets[i]); strcpy(delim,",\n "); 3 i++; 3 /* Print output array */ i=0; while(i < MAXIO) £ if ( outnets[i][0J != '\0') /* skip empty fields */ £ if(outnets[i][0] == '$') iprintf(fp, "Xs_Xs", delim, outnets[i]); else iprintf(fp, "XsXs", delim, outnetsfi ]) ; strcpy(delim,",\n "); /* in case there were no input */ 3 i++; iprintfffp, "\n);\n"); if (unconnectedjpins) £ iwmsgout(WARNING. "Warning - Component Xs has Xd unconnected pin(s).", legalname(cntxt_name(igcomna (comp))), unconnected j sins); 3 iρriπtf(fp, "\n"); 3 /* list somp sins */ / « * dojso pl st * This is the main body of the component orientated listing. This * routine recursively decends each branch of the design hierarchy * and outputs a statement for each component instance. Each statement * contains the full path name of the component and its pin-net * connections. The top most net name is used for each pin-net connection. •/ static void do_complist(FILE* fp,GROUPS* grpp) £ COMPONENTS "comp; int stat; status_line(iggrpnam(grpp)); A-ss SUBSTITUTE SHEET if (Evaljsn) ζ 160 /* push the variable definition table */ ippush lev() ; 3 comp a NULL; whi te {(comp = iggrpcom(grpp. comp)) != NULL) £ if (Evaljsn) f, /* add variable definitions for this component to the table */ if {(stat = ipaddvardefs(comp)) 1= 0) £ printf ("ERROR -- exn002: Error Loading definition: Xs\n", ipgetmsg(stat)) ; 3 3 if (primitive(comp)) £ /* print component statement iprintf(fp. " Xs". legalnamβ(iggrpπam{igsymown(igcomsym(comp))))) ; iprintf(fp, « Xs". lβgalname(refdesname(igsymown(igcomsym(comp))))) ; "/ /* iprintf(fp, " Xs". legalname(cntxt_name(igcomnam(comp)))) ; */ do somp_attributes(fp, comp) ; list_comp_pins(fp. comp) ; 3 else ( /* push into composite component */ cntxt j sush(comp); do sompList(fp. igsymown(igcomsym(comp))); cntxt_pop(); 3 if (Evaljsn) £ /* delete this component's definitions */ ipdelvardβfsO ; 3 3 if (Evaljsn) £ /* pop the variable definition table */ ippoplev(); 3 3 /* do somplist */ #if 0 /« * do_interfacβ " the first part of the nodule description defines the interface * to the outside world. */ static void do_interface(fp, grpp) FILE *fp; GROUPS "grpp; £ SYMPINS *spnp; A-S iprintf(fp, "INTERFACE^"); /• list the SYMBOL_PIN=INTERNAL_NET connection list */ for (spnp=igsymspn(iggrpsym(grpp)); spnp != NULL; spnp=igspnnxt(spnp)) £ /* add pinname */ iprintf(fp, " Xs", igspnnam(spnp)); do_attributes(fp, igspnatt(spnp)) ; iprintf{fp, "="); if (igspnnet(sρnp) == NULL) { iwmsgout (WARNING, "Warning - Symbol pin Xs is not used in underlying schematic", igspππam(spnp)); 3 else { /* add internal netname */ iprintf(fp, "Xs", ignetnam(igspnnet(spnp))); 3 3 iprintf(fp, " ;\n"); } /" do_interface */ fendif /* * dojnodule * output the module statement and symbol attributes. */ static void dojnodule (FILE* fp, GROUPS* grpp) £ iprintf(fp, "block Xs", strtolw( legalname(modelname(grpp)))) ; do_attributes(fp, igsymatt(iggrpsym(grpp))) ; iprintf(fp. "\n\n"); } /* dojnodule */ /* * loadf i le * Load variable definitions from the specified file (if it * exists). « / static void loadf i le(const char* fname) c int status; if ((status = ipincfilβ(fname)) == IP_DUPVAR) £ printf ("WARNING -- exn003: Duplicate variable(s) in Xs.VAR\n", fname); 3 else if (status == IP_SUCCESS) { printf ("Definitions loaded from Xs.VAR\n", fname); 3 ) /* loadf ile */ /* * usage * display usage info. • / static void usage () £ printf("Usage: FLATNET [flags] design [level ...]\n"); printf{» flags\n"); -S7 SUBSTITUTE SHEET - disable attribute output.\n"); • enable bus expansion.\n"); - disable attribute evaluation.\n"); - disable NETS section.\n"); - disable warning messages.\n"}; - disable synonym creation.Vn"); - top level schematic name.Vn"); - level string(s).\n"); /* — » main * process command line, open output file, load data structs, * process design. '/ /oid main(int argc, char* argv[]) FILE *outfp; /* output fi le pointer */ char "fi lename; /* output f i le name */ char *design_name ; /* top leve l schematic name GROUPS *top_group; /* pointer to top group */ int netlist = 1 ; /* net listing f lag */ int warnings = 1 ; /* warning f lag */ int i , j , flag, stat; printf ("VIEWBASE to SDL extractor. Version Xs\n". VERSION) ; printf ("Copyright (C) STAR Semiconductor Inc. 1991 \n") ; if (argc < 2) £ /* no args */ usage O ; exit(EXFAILURE) ; 3 iwinitO ; /* initialize wir fi le reader */ /* process command line, f lags and leve l arguments are optional. */ /* f lags may be grouped together and nay occur before or after */ /* the design name. */ design_namβ = NULL; for (i = 1 ; i < argc; i++) £ if (argv[i]rθ] = '-') f /* command line switch */ for (j t 1 ; argv[i][] ' 3; J++) £ flag = isupper(argv[i][j])? tolower(argv[i]π]) : argv[i][j]; switch (f lag) £ case 'a' : /* disable attribute output */ Attrjon = 0; Evaljsn « 0; break; case 'b' : /* enab le bus expansion */ iwexpbusO ; break; case 'e' : Evaljsn = 0; break; case 'n' : /* disab le net orientated listing */ netlist « 0; break; case 'w' ; /* disable warning messages */ warnings = 0; break; case 's': /* disable synonym creation */ Synjsn = 0; break; 3 /* switch */ 3 /* for j ... */ 3 else { if (design j iame == NULL) £ /* save design name */ designjiame = argv[i]; 3 else £ /* save level string (more than one level may be specified) */ iwset leve l(argv[ i ] ) ; 3 3 3 /* for i ... */ if (designjiame == NULL) { printf("ERR0R -- βxn003: you must specify a design name.\n"); usage(); exit(EXFAILURE); 3 strtolw(desigπ ιame); /* lower-case design name */ /* open output netlist file */ filename = ma Hoc (str len (designjiame) + 5); sprintf (fi lename, "Xs.pdl", designjiame); if ((outfp = fopen(fi lename, "w")) == NULL) £ fprintf (stderr, "Error: can't open Xs.\n", filename); exit(EXFAILURE); 3 printf ("Netlisting to Xs.\n", filename); /* set up error reporting routines */ iwmsgcloseO; /* clear default settings */ iwmsgsetup(ERROR, outfp, "\nXs"); /* errors to file and */ iwmsgsetup(ERROR, stdout, "Xs"); /* console */ iwmsgsetup(INFO, outfp, "\π*« Xs"); /* infos to file */ if (warnings) iwmsgsetup,(WARNING, outfp, "\n** Xs"); / « warnings to file */ /* load design into data structures */ top_group = iwgroup(design ιame); if (top_group «= NULL) £ fprintf(stderr, "Error loading Xs. \n", designjiame); fclose(outfp); exit(EXFAILURE); 3 printf("\n"); /* free temporary memory used by the reader */ iwcleanupO; /* notify user of errors or warnings found during loading */ if (iwmsgcount(ERROR I WARNING) > 0) £ ^ ^ C / 9 SUBSTITUTE SHEET printf("Xd error(s). Xd warning(s) encountered during load n", iwmsgcount(ERROR). iwmsgcount(WARNING)); 3 /* initialize output formatting routines */ iprintfinit{78, " ", »\n "); if (Evaljsn) £ /* initialize parameterized attribute routines and load variable */ /* definitions from the top level symbol */ if {(stat = ipinit(topjjroup)) != 0) £ pr ntfP'ERROR — exn004: PA initialization error: Xs\n", ipgetmsg(stat) ) ; 3 /* load variables from the variable definition text fi les */ loadf i le(design_name) ; loadfi leC'FLATNET") ; 3 /* iprintf(outfp, "* « FLAT Netlister - VXs\n", VERSION); iprint (outfp. "** Created: Xs, Xs Xs\n\n", iday{), idate(), itime()); */ /•***•* • ** Block name **** « ****/ do_modu le(outfp, topjgroup) ; /* output module header */ /*do_interfacβ(outfp. topjgroup) ;*/ /* output module interface nets */ /**"* « **** Wire List **** «« *•*/ do_netlist(outfp. topjjroup) ; /* output net section */ / « *"• « * « *** « -* Component List ***"*****•***/ iprintf (outfp, "begin\n") ; do somp list (outfp. topjgroup) ; /* output component section */ iprintf (outfp. "end\n") ; /* terminate module section */ /* du pjsynlist(outfp) ;*/ /* list synonyms */ printf("Xd error(s), Xd warning(s) encountered.\n", iw sgcount(ERROR), iwmsgcount(WARNING)); fclose(outfp); exit(EXSUCCESS); /* main */ A- Q O Copyright (c) 1991 Star Semiconductor Corporation. All Rights Reserved. This material may not be copied or used without prior written permission. * Sid: exnode.c.v 1.31991/09/2004:24:01 ivan Exp $ * Slog: exnode.c.v S * Revision 1.3 1991/09/20 04:24:01 ivan * Minor fixes * Revision 1.2 1991/09/16 19:06:24 ivan * Changed error messages to Star format « * Revision 1.1 1991/09/06 18:47:25 ivan * Initial revision * */ exnode.c Bui ld an sdi . C D fi le to probe a se lected node . */ ^* *** * ** . **** * ****** / /* requi res */ /*******************/ finclude <stdio.h> #include <stdlib.h> #inc lude <string.h> #iπclude "sysfuncs.h" #inc lude "strfunc.h" #include "exsdl.h" #inc lude " lex.h" / ..... * ...........« */ /* exceptions */ /****************»**/ /* constants */ types /* data */ / ....„»,......,.... / static char exnode[] = "SRevision: 1.3 $"; /* GLOBAL STORAGE for interfacing to parser and lexical analyser char tmprec[MAXRL]; /* holds latest identifier */ A- a SUBSTITUTE SHEET extern FILE "yyin. •yyout; /* macros */ /* functions */ void main(int argc, char *argv[]) £ char inpath[MAXNAM]; char outpath[MAXNAM] = t"dp.cmd"3; char fname[MAXNAM], ext[MAXEXT]; Check command line parameters printf("VnExnodβ Xs\n", exnode); printf("Copyright (C) 1991 by STAR Semiconductor Corporation.\n"); if (argc > 1) £ strtolw(argv[1]) ; if {{strcmp(argv[1], »-h") = 0) | [ (strcmp(argv[1 ], »/h") = 0) ) £ printf ("Usage: exsdl fi lename[ .nod]\n") ; exit(-l ) ; 3 else strcpy(inpath, argv£1 ]) ; 3 else £ printf ("Usage: exsdl fi lename[.nod]\n") ; exit{-1) ; 3 Check input fi le extension splitname(inpath, fname, ext) ; if (strcmp(ext, "") = 0) /* append default extension */ i strcpy(ext, ,r .nod"); Mergename(inpath. fname, ext); 3 open input and output files if {{yyin a. fopβn(inpath, "r")) = NULL) A" Q£L printf ("ERROR - - βxo001 : fai led to open Xs\n", inpath) ; exit(-1 ) ; 3 if ( (yyout = fopen(outpath, "w")) == NULL) £ printf("ERROR -- exo002: failed to open Xs\π", outpath); exit(-1); 3 /.... * .««,.««..... Process input fi le ***** * ********** * i printf("Creating Xs from Xs\n". outpath, inpath); yylex(); fprintf(yyout, "lo symbols\n"); fprintf(yyout, "pr Xs\n", tmprec); fprintf(yyout, "exit y\n"); fclose(yyin); fclose(yyout); A- 63 SUBSTIT TE SHEET Copyright (c) 1991 Star Semiconductor corporation. All Rights Reserved. This material may not be copied or used without prior written permission. 1991/10/01 16:24:07 ivan Exp $ * Revision 1.4 1991/10/01 16:24:07 ivan » Fix wild address bug. » Revision 1.3 1991/09/16 19:06:31 ivan * Changed error messages to Star format * • Revision 1.2 1991/09/11 15:20:44 ivan * Support 'blocklen' parameter on 'fi lter' blocks to contro l splitting * of fi lters longer than a sample period into seperate blocks. * * Revision 1.1 1991/09/06 18:47:42 ivan * Initial revision / .... * .. * .......«......«. * «....«....... * . * ... getdis.c Functions for extracting FIR and IIR data from a '.fdf fi le •/ /* requires */ ..,................ / ♦include "sysfuncs.h" ^include "strfunc.h" ♦include <stdio.h> ♦include <string.h> ♦include <stdlib.h> . * «.........., * .... / /* exceptions */ /* constants */ /* dispro fi le information */ ♦define MAXLINE 80 ♦define TYPEREC 2 ♦define LENGREC 3 ♦define MAXTAPS 500 ♦define MAXSECT 50 /• types /•••••••••••• A- GV ,...,....... * ....... /* data */ /* macros */ , f / ** * *********** *** ** / /* functions */ /******************* / shar *extraotjsaram2(char *str); extern double lim2(double var); Process DISPRO FIR f i les int get_dispro_firjiata(FILE * dis_fi le, double "coeffvec, char *t, int "iptr) £ char tmp_rec[MAXLINE]; char fi lter_type[12]; int i, numsect, hnumsect, coef det ; double cvalue; /*•***•••••*••* get f i Iter type **************/ fgets(tmp_rec, MAXLINE, dis_file); strcpy(fi lter_type, extract_param2(tmpj^ec)) ; strcpy(t, fi Iter type); /* for calling routine */ /*****•********** get fi Iter length ................/ fgets(tmp_rec, MAXLINE, dis_file); numsect ■ atoi(extract_param2(tmp -ec)); if (numsect < 2 || numsect > MAXTAPS) £ printf("ERROR -- gtdOOI : invalid number of taps\n\n"); return (-1); 3 hnumsect = numsect » 1 ; •iptr * numsect; /• for calling routine */ A-£s SUBSTITUTE SHEET skip to beginning of coefficients coef_det « 0; while (feof(dis_file) == 0) £ fgβts(tmp_rec. MAXLINE. dis_file); if (strncmp(tmp_rec, "\"<C>", 4) «= 0) £ coefjdet = 1; /* found coefficients » / break; /* go and process them */ if (coefjdet «= 0) £ return (-2); 3 FIR coefficient record may be very long, so fetch it one value at a time. First decide if coefficient symmetry is for even or odd number of samples. if ({numsect & 0x0001) == 0) £ for (i = 0; i < hnumsect; i++) £ fscanf (dis_f i le. " Xlf", Scvalue) ; coeffvec[i] t cvalue; coeffvec[nunsect - 1 - i] » cvalue; 3 3 else £ for {i at 0; i <= hnumsect; i++) £ fscanf(dis_fi le, " Xlf", Scvalue) ; coeffvec[i] = cvalue; coeffvec[numsect - 1 - i ] = cvalue; 3 3 return (0); Process DISPRO IIR fi les. Passed down parameters are actually owned by salting routine. lis_f i tβ open f i le for read fdf IIR format joeffvec vector of coefficients, 5 per section t f i Iter type: lowpass, bandpass, highpass, tranfunc iptr number of sections int gβt iispro_ι ir data(FILE • dis_fi le, double *coeffvec, char *t. int "iptr, int "odd lag) r A-G& char tmp_rβc[MAXLINE]; 171 char filter_typβ[12]; int i, j. order , numsect , coefjdet ; double a, b. c, * ' d, e; I ************** get f i Iter type **************/ fgets(tmp_rec, MAXLINE, dis_f i le) ; strcpy(fi lter_type, βxtractjsaram2(tmp -ec) ) ; strcpy(t , fi lter_type) ; /* for ca l li ng routine */ / ...... * ......... get fi Iter order ..,............. / fgets(tmp_rec, MAXLINE, dis_file); order = atoi(extract_param2(tmp "ec)); i = 0; /* for even order filters */ if ((order & 0x0001) != 0) /* test for odd order filter */ £ /* make order the next highest even number, set the flag */ ordβr++; i = 1; /* for odd order fi Iters */ 3 numsect = order » 1; /* for recursive filter structure */ •iptr = numsect; /* for calling routine */ •oddflag = i; /* for calling routine •/ if (numsect < 1 | | numsect > MAXSECT) £ printf("ERROR --gtd002: invalid number of IIR sections\n\n"); return (-1); 3 skip to beginning of coefficients ...............................*/ coefjdet = 0; while (feof(dis_file) == 0) £ fgβts(tmp_rec, MAXLINE, dis_file); if (strncmp(tmp_rec, "\"<C>«, 4) == 0) £ coefjdet « 1; /* found coefficients */ * break; /• go and process them •/ 3 3 A- £7 SUBSΠTUTE SHEET if (coefjdet -= 0) C return (-2); 3 Fetch coefficients from fiLe. Second and first order coefficients are modified the same way. See the DISPRO manual. Figure 3.1a for details. j = 0; for (i = 0; i < numsect; i++) C fscanf(dis_file. " X*i, Xlf. Xlf, Xlf, Xlf, Xlf", Sa. &d, &e. &b, &c); coeffvec[j++] = lim2(a);/* bO */ coeffvectj++] = Lim2(a * d); /* bl */ coβffvec[j++] = Lim2(a * e); /* b2 */ coeffvec[j++] = Lim2(-b); /* a1 */ coeffvec[j++] = Lim2(-c); /* a2 */ 3 return (0); shar *extract_param2(char *rec) int i «t 0, j «0; static char tβxt£12]; /•!!!!!!!! Ul! ! !! " ! ! I! 1 HI! !!!! 1! !!! I! !*/ char c = '\n'; /* initialise for test */ while (c != '.') /* eat first parameter */ C c = rec£i++]; /* advance pointer */ 3 while (c != * \0') f. c = rec£i]; if (c = ' ' I = 'U' || • \n' || c «= ■ '"') /* eat white */ else £ text[j] t c; /* copy string */ ι++; strtoIw(text); /* for type checking */ return (text); A-G& μ Copyright (c) 1991 Star Semiconductor Corporation. All Rights Reserved. This material may not be copied or used without prior written permission. * Sid: strfunc.c.v 1.31991/09/16 19:06:40 ivan Exp $ * SLog: strfunc.c.v $ * Revision 1.3 1991/09/16 19:06:40 ivan * Changed error messages to Star format * Revision 1.2 1991/09/11 15:20:55 ivan * Support 'blocklen' parameter on 'filter' blocks to control splitting * of filters longer than a sample period into seperate blocks. • * Revision 1 .1 1991 /09/06 18:47 :56 ivan * Ini ti a l revision * */ .,.......«...,.........«....., * ................«..««..................... strfunc. c */ /* requi res */ / ................... #i nclude "sysfuncs.h" finc lude <stdio.h> #inc lude <stdlib.h> #include <string.h> ^inc lude <ctype.h> #include "strfunc.h" /* exceptions * /* constants */ / .........„........ /• types */ /* data */ /* macros */ A- €? SUBSTΓΓLΠΈ SHEET /* functions */ /* convert an int value to character representation in a specified radix stored in a string */ /* recursive itoa with limit on number of chars */ void itoa_timit(int value, char ** stringjstr, int radix, int njshars) £ int next_value; int digit; /* see if limit has been reached */ njshars++; if (njshars > ITOAJ.IMIT) return; /* compute the right digit of the value */ digit β value - (next_value = value/radix)*radix; value = next_value; /* recursive ly call us for remaining digits */ if (value) itoa_limit(value. stringjstr, radix, njchars) ; /* output our digit at end, converting to ASCII */ *(*string_ptr)++ = (char)fdigit + '0') ; /* add terminator, which can be overwritten by successive digits */ " • stringjstr = '\0'; /* here is the real itoa */ char* itoa(int value, char* string, int radix) £ char* string start; int njshars; njshars = 1 ; stringjstart t string; /* if negative value, output a minus sign and work with positive number •/ if (value < 0) £ •string++ = '-' ; value E -value; n_chars++; 3 itoa_Limit(valuβ, Sstring, radix, n j shars) ; return (stringjstart) ; 3 /• splitname - separate filename into name and extension strings, cname points to the combined filename string p1 points to the name string p2 points to the extension string all strings are null terminated 175 returns 0 int splitname(char "cna e, char *p1 , char *p2) £ int i = 0, j - 0; char c; forever £ c = cname[i]; if (c == * . * || c == * \0 * ) £ p1[i] = '\0'; i++; break; 3 p1[i] = c; i++; if (c == '\0') p2[j] = '\0'; else £ p2[j] = c; while (c != '\0') £ c = cname[i]; p2[j] m c; i++; j++: 3 3 return (0); /* mergename - combine name and extension strings into filename string. cname points to the combined filename string p1 points to the name string p2 points to the extension string all strings are null terminated returns 0 */ int mergename(char "cname, char *p1, const char *p2) £ cname[0] : '\0' ; strcat(cname, pi); strcat(cname, p2); return (0); /* strtoup - convert a string to uppercase. string points to the null terminated string to be converted returns a pointer to string - 7/ SUBSTITUTE SHEET shar *strtoup(char "string) /* convert string to uppercase */ £ int i « 0; white (string[i] != '\0') £ string[i] = (char) toupper((int) stringri]); i++; 3 " return (string); > /• strtotw - convert a string to lowercase. string points to the null terminated string to be converted returns a pointer to string •/ shar *strtolw(char "string) /* convert string to lowercase */ £ int i at 0; while (string[i] != '\0') £ string[i] = (char) tolower((int) string[i]); return (string); char *strcprβss(char *string) /* remove white space */ £ int i = 0, j « 0; whi le (string[i] 1= '\0') £ if (isspace(string[i]) «= 0) £ stringr ] = string[i]; 3 i++; 3 stringf ] = *\0'; /* terminate compressed string */ return (string); 3 /* check_opβn_rf - check and open a read file, exit on fai lure rfile points to the file structure inpath is the filename returns 0 if successful returns 1 if failed */ int check spen_rf(FILE •* rfitβ, char *rpath) £ if {("rfile » fopen(rpath, "r")) = NULL) £ A{- 7^ printf("ERROR -- strOOl : cannot open Xs\n", rpath); return (1); 3 else return (0); i-'f SUBSTITUTE SHEET 178 APPENDIX . β- Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/dsink.sdl,v 1.2 1991/10/01 * $Revision: 1.2 $ * $Id: dsink.sdl,v 1.2 1991/10/01 21:24:22 chet Exp $ * $Log: dsink.sdl,v $ # Revision 1.2 1991/10/01 21:24:22 chet # Added Revision Keyword # # Revision 1.1 1991/09/05 14:28:15 allsop # Initial revision # */ /★♦★★A******************************************************************** dsink.sdl ************************************************************************** Function: Dual sink block. Store two inputs into vectors until full, then cease. Arguments: ina inb Parameters: length Algorithm: Manage two sink vectors. Store input values into output vectors until full. */ /*******************/ /* inline code */ /*******************/ asmblock dsink { %subr=default, %length=128 } ( ina , inb ; ) verify ( %length>0 && %length<=256 ), 'Specify length in range 1 to 256.'; variable integer ptr = outvectorl; micro variable outvectorl[%length] ; micro variable outvector2[%length] ; duration 10; begin Ida ptr cmp #outvectorl+%length-l B - l SUBSTITUTE SHEET // store the inputs in vectors // save ptr for next invocation /*******************/ /* subroutine call */ /*******************/ callblock dsink { %subr=default, %length=128 } ( ina , inb ; ) verify ( %length>0 && %length<=256 ), 'Specify length in range 1 to 256. ' variable hex return=postamble; variable integer length=%length; variable integer ptr=outvectorl; micro variable outvectorl[%length]; micro variable outvector2[%length] ; /*******************/ /* subroutine body */ /*******************/ subrblock dsink { } Q symbol return=0 r length=l, ptr=2, outvectorl=3; duration 0; begin // save ptr for next invocation DONE: jm [B+return] B- end -3 SUBSTITUTE SHEET /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/dsinkrd.sdl,v 1.51991/10/ * $Revision: 1.5 $ * $Id: dsinkrd.sdl,v 1.5 1991/10/0121:24:27 chet Exp $ * $Log: dsinkrd.sdl r v $ # Revision 1.5 1991/10/01 21:24:27 chet # Added Revision Keyword # # Revision 1.4 1991/09/19 13:04:55 allsop # Changed done output to 0.0 or 1.0. # # Revision 1.3 1991/09/16 15:12:05 allsop # Remove micro definitions from reset and done. # # Revision 1.2 1991/09/11 14:45:05 chet # Revise reset threshold for reset >= 0.5; include total lines of code comments. # # Revision 1.1 1991/09/05 17:25:23 allsop # Initial revision # */ dsinkrd.sdl ************************************************************************** }?unction: double sink block with reset input and done flag output Arguments: ina inb reset done Parameters: length Algorithm: Manage two sink vectors. Store input value into output vector until full. When reset input becomes >= 0.5, reset output buffer pointer to start; also clear DONE output (set to 0.0) . When output vector is full r signal by setting DONE output (set to 1.0). Note: done flag is written every sample, even if unchanged. Note: Reset input is ignored while vector is being assembled. If reset is held high (>== 0.5) the DONE flag is always zero. V &H *******************/ 183 /* inline code */ /*******************/ asmblock dsinkrd { %subr=default, %length=128 } ( ina, inb, reset ; done ) verify ( %length>0 && %length<=256 ), 'Specify length in range 1 to 256.'; variable integer ptr == outvectorl; micro variable outvectorl[%length] ; micro variable outvector2[%length] ; // total lines of code: 20 // use A register for full check ιgth-1 // use Base register for storage // X is a scratch register here // reset threshold // jump if not reset // set pointer to start of vector // clear done flag; vector being assembled // set done flag; vector is full /*******************/ /* subroutine call */ /*******************/ callblock dsinkrd { %subr=default , %length=128 ) ( ina, inb, reset done ) verify ( %length>0 && %length<=256 ) , 'Specify length in range 1 to 256. variable hex returnaapostamble; variable integer creset; // copy of reset variable integer length=%length; variable integer ptr==outvectorl; micro variable outvectorl[%length] ; micro variable outvector2[%length] ; duration 6+16; // total lines of code: 6 + 23 begin SUBSTITUTE SHEET /*******************/ /* subroutine body */ /*******************/ subrblock dsinkrd { } () symbol return=0, creset=l, length=2, ptr=3, outvectorl= ; duration 0; temp register: address of outvectorl[0] test reset input reset threshold jump if not reset set pointer to outvectorl[0] set done flag; vector is full exit routine from one place only use F register for storage clear done flag; vector being assembled Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/ext_in.sdl,v 1.4 1991/10/0 * $Revision: 1.4 $ * $id: ext_in.sdl,v 1.4 1991/10/01 21:24:32 chet Exp $ * $Log: ext_in.sdl,v $ # Revision 1.4 1991/10/01 21:24:32 chet j Added Revision Keyword 1 If Revision 1.3 1991/09/19 13:06:00 allsop i Changed subr=off to subr=default. * If Revision 1.2 1991/09/04 21:24:09 allsop U Removed code and moved micro declaration to argument list. If f Revision 1.1 1991/08/13 13:44:52 allsop If Initial revision # */ /************************************************************************* ext_in.sdl ************************************************************************** Function: external input (from microprocessor) arguments: out Parameters: zone; trigger; rate; Algorithm: SPROC input (microprocessor output) visibility tag. V /*******************/ /* inline code */ /*******************/ asmblock ext_in { %subr==default, %zone="", %rate=0, %trigger=no_cl } ( ; micro o timezone %zone = %rate; computeline %trigger; duration 0; SUBSTITUTE SHEET 5-r /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. » This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/ext_out.sdl,v 1.4 1991/10/ * $Revision: 1.4 $ * $Id: ext_out.sdl,v 1.4 1991/10/01 21:24:36 chet Exp $ i 'f * $Log: ext_out.sdl,v $ # Revision 1.4 1991/10/01 21:24:36 chet # Added Revision Keyword # # Revision 1.3 1991/09/19 13:06:45 allsop # Changed subr=off to subr==default. # # Revision 1.2 1991/09/04 20:42:28 allsop # Removed code and moved micro declaration to argument list. # # Revision 1.1 1991/08/13 13:46:09 allsop # Initial revision # */ ************************************************************************* ext_out.sdl ************************************************************************** Function: external output (to microprocessor) Arguments: in Parameters: Algorithm: SPROC output (Microprocessor input) visibility tag. */ /*******************/ /* inline code */ /*******************/ asmblock ext_out { %subr=default } ( micro in ; ) duration 0; begin end 5 ~ SUBSTITUTE SHEET /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/sink.sdl,v 1.6 1991/10/01 * $Revision: 1.6 $ * $Id: sink.sdl,v 1.61991/10/0121:27:10 chet Exp $ * $Log: sink.sdl, $ # Revision 1.6 1991/10/01 21:27:10 chet # Added Revision Keyword # # Revision 1.5 1991/08/28 19:28:45 chet # Replaced with msink.sdl (only difference is 'micro' declaration). # # Revision 1.1 1991/08/13 13:54:21 allsop # Initial revision # */ /************************************************************************* sink.sdl ************************************************************************** Function: This cell captures consecutive data samples to a block of data RAM. The block of RAM is specified as 'micro*► Arguments: fixed in -2.0 <= in < 2.0 // current input sample Parameters: integer length 0 < length <=512 // length of data RAM block Algorithm: while ptr is not greater than the last address to be stored store input indirect with ptr to current address increment pointer Note that the subroutine version is slightly more complicated but operates on the same principle. */ /*******************/ /* inline code */ /*******************/ asmblock sink { %subr=default, %length=l28 } ( in ; ) verify ( %length>0 && %length<=512 ) , 'Specif length in range 1 to 512. '; variable integer ptr = outvector; micro variable outvector[%length]; 189 /*******************/ /* subroutine call */ /*******************/ callblock sink { %subr=default, %length=128 } ( in ; ) verify ( %length>0 && %length<=512 ), 'Specify length in range 1 to 512.' variable hex return=postamble; variable integer length=%length; variable integer ptr=outvector; micro variable outvector[%length] ; /*******************/ /* subroutine body */ /******************* subrblock sink { ) () symbol return=o, length=l, ptr=2, outvector=3; duration 0; be in SUBSTITUTE SHEET Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Reader; /home/solus/users4/release/CVS/cells/code/sinkrd.sdl,v 1.7 1991/10/ * $Revision: 1.7 $ * $Id: sinkrd.sdl,v 1.7 1991/10/0121:27:15 chet Exp $ * $Log: sinkrd.sdl,v $ # Revision 1.7 1991/10/01 21:27:15 chet # Added Revision Keyword # # Revision 1.6 1991/09/26 20:47:07 allsop # Remove bogus characters after end statement. # # Revision 1.5 1991/09/19 13:03:08 allsop # Changed done output to 0.0 or 1.0. # # Revision 1.4 1991/09/19 12:56:03 allsop # Changed done output to 0.0 or 1.0. # # Revision 1.3 1991/09/16 15:17:28 allsop # Remove micro definitions from reset and done. # # Revision 1.2 1991/09/11 14:32:15 chet # Revise for reset condition >= 0.5; correct duration statement for subroutine. # # Revision 1.1 1991/09/05 14:26:54 allsop # Initial revision # */ /************************************************************************* sinkrd.sdl ************************************************************************** Function: sink block with reset input and done flag output Arguments: in reset done Parameters: length Algorithm: Manage one sink vector. Store input value into output vector until full. When reset input becomes >= 0.5, reset output buffer pointer to start; also clear DONE output (set to 0.0). When output vector is full, signal by setting DONE output (set to 1.0) . Note: done flag is written every sample, even if unchanged. Note: Reset input is ignored while vector is being assembled. If reset is held high (>= 0.5) the DONE flag is always zero. V /*******************/ /* inline code */ ^ / *******************/ asmblock sinkrd { %subr=default, %length=128 } ( in , reset ; done ) verify ( %length>0 && %length<=512 ), 'Specify length in range 1 to 512.'; variable integer ptr = outvector; micro variable outvector[%length] ; // total lines of code: 18 // use A register for full check jth-1 // use Base register for storage // X is a scratch register here // reset threshold // jump if not reset // set pointer to start of vector // clear done flag; vector being assembled // set done flag; vector is full /*******************/ /* subroutine call */ /*******************/ callblock sinkrd { %subr=default , %length=128 } ( in , reset ; done ) verify ( %length>0 && %length<=512 ), 'Specify length in range 1 to 512.' variable hex return=postamble; variable integer length=%length; variable integer ptr=outvector; micro variable outvector[%length] ; duration 5+13; // total lines of code: 5+20 begin 3-3 SUBSTITUTE SHEET / *******************/ /* subroutine body */ / *******************/ subrblock sinkrd { } () symbol return=0, length=l, ptr=2, outvector=3; duration Or oeg Ida B add #outvector-return ldf A // temp register add [B+length] cmp [B+ptr] gt DO_STORE Ida Y // review reset input value cmp #0.5 // reset threshold jit SETJ30NE // jump if not reset stf [B+ptr] // set pointer to start of vector jmp CERJDONE 3ET_D0NE: Ida #1.0 // set done flag; vector is full jmp EXITJ3UB // exit routine from one place only DO_STORE: ldf [B+ptr] // use F register for storage stx [F] Ida [B+ptr] add #1 sta [B+ptr] C RJDONE: Ida #0.0 // clear done flag; vector being assembled EXIT_SUB: jmp [B+return]- end B-'i /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/source.sdl,v 1.4 1991/10/0 * $Revision: 1.4 $ * $Id: source.sdl,v 1.4 1991/10/01 21:27:19 chet Exp $ * $Log: source.sdl,v $ # Revision 1.4 1991/10/01 21:27:19 chet # Added Revision Keyword # # Revision 1.3 1991/08/28 19:32:27 chet # Replaced with msink.sdl (only difference is 'micro' declaration). # # Revision 1.1 1991/08/13 13:56:24 allsop # Initial revision # */ /************************************************************************* source.sdl ************************************************************************** Function: This routine reads consecutive inputs from a file (array) of specified length, and outputs them, one at a time. The array is specified as 'micro'. Arguments: fixed out -2.0 <= out < 2.0 // current output sample Parameters: file "name.dat" // specify data file integer trigger integer rate integer length 0 < length <=512 // length of data RAM block Algorithm: read input indirect with ptr to current address store input to out increment pointer; wrap address to beginning if necessary Note that the subroutine version is slightly more complication but performs the same function. V /*******************/ /* inline code */ /*******************/ asmblock source { %subr=default, %trigger=no_cl, %zone="", %rate=0, %file="", % verify ( %length>0 && %length<=512 ), 'Specify length in range 1 to 512.*; 15 - SUBSTITUTE SHEET 19^ verify ( %file != "" ), 'Specify data source filename'; timezone %zone = %rate; computeline %trigger; variable integer ptr = invector; micro variable invector[%length] = %file; /*******************/ /* subroutine call */ /*******************/ callblock source { %subr=default, %trigger=no_cl, %zone="", %rate=0, %file=" verify ( %length>0 && %length<=512 ), 'Specify length in range 1 to 512.'; verify ( %file != "" ), 'Specify data source filename'; timezone %zone = %rate; computeline %trigger; variable hex return=postamble; variable integer length=%length; variable integer ptr=invector; micro variable invector[%length] = %file; /*******************/ /* subroutine body */ /*******************/ subrbloσk source { } () symbol return=0, length=l, ptr=2, invector=3; duration 0; begin £-/ // temporary register SUBSTITUTE SHEET APPENDIX C /* $Log: symutil.c.v $ l/i » Revision 1.3 1991/08/08 14:09:47 krassow * *** empty log message *** * Revision 1.2 1991/08/08 13:21:09 krassow » »«* m ty log message *** * */ /* Utilities supporting symtran.c */ ^include <stdio.h> #include <string.h> #include <stdlib.h> #include <gf.h> #include <ibmkeys.h> #include <standard.h> #include "sdi_defs.h" #include "sdijimds.h" #include "sy tran.h" #include "sym_ext.li" char symutiiπ = "$Id: symutil.c.v 1.3 1991/08/08 14:09:47 krassow Exp $" ; /* */ /* interface declarations */ / */ char * generatejιame(void); void add >utput_line(void); void * e alloc(sizβ_t size); void free_list(node_type *list); void fi ll_in_size(void); void clean J5xit(int code); BOOLEAN check_for_ESC(void); char * symrec2name(char * symbol OC); void show_list(node_type "list); ' void closejstructs(int level. BOOLEAN published); /* error handling file interface to display module */ extern FILE *efopen(char * path, char * type); extern int efclose(FILE *file jtr, char * f i le iame) ; /" interface to sps ti I module */ extern unsigned int symrec2addr( unsigned char * symbol -ec); /* item « pointer to item to be inserted */ /* globals Work and Prev are updated •/ void insert (nodejtype "item, nodejtype "head) { nodejtype "work; /* start at beginning of list */ if (*head) else { •head = item; return; } /* insert item at end of list */ e-/ SUBSTITUTE SHEET whi le (work->next) X 198 work « work->next; i work->next = item; item->prev - work; } /* end of insert */ char * symrec2name(char *symbol_rec) C char *ptr, *name_str; int len; if ((ptr = strchr(symbol_rec. ' * )) != NULL) f len = ptr - symbotjrec; name j str = emalloc(len + 1) ; strncpy{name_str. symbol_rec, len) ; name jstr[ len] - '\0' ; } else printf("\nBad (no space) symbol."); rβturn(namβ j str)t } /* end of symrβc2name */ void add_to_list(char *symbol_rec. char *name) { name_list_item_type * new_item; /* create new item from symbol record */ new itera * emalloc(sizeof(name_list_item_type)) ; new_item->πext = NULL; nβw_item->addr = symrβc2addr(symbol_rec); if (name) πew ftem->πame = name; else new_item->name = symrec2πame(symbol_rec) ; if (List = NULL) £ List - new item; List_end = new item; 1 else X /* append new item to list */ List_end->next = newjitem; /* update end of list */ List end — new item; } / « end of add_to_list */ void showjprogress(/int *dot_cπt) i (*dotj;nt)++; if (!Quiet_mode && *dot_cnt >= 8) printf ("."); *dot_cπt « 0; } } /* end of show_progress */ c- S void push_name(char "name) C Namβjstack[Namβj5taok ix] ■= emalloc(str len(name)+1) ; strcpy(Namejstack[Namej5tack ix] , name) ; . Name ϊtack ix++; } char * pop ιame() C v * , . Namβjstackjix-- ; return(Namejtack[Namej5tack ix]); } /* modify Prev_hdl to insertion point */ /* return TRUE if match; traverse by sibling */ char *make_name(char "start, char *end) C int len; char "name; len = end - start; name = emalloc((size_t)( len+1)); strncpy(name, start, len); name[len] = '\0'; return(name); } /* end of make iame */ void addjdot(char "text, char ""endjiame) C if (text != "endjiame) { strcpy(*end ιame, "."); *end ιame++; } else "endjiame = '\0' ; } /* end of add_dot */ void close_structs(int level. BOOLEAN published) C int indent; shar indent_str[100]; shar "name; while (Namejstack ix > level) { /* create string containing spaces per indent level */ strcpy(indent_str. INDENT_CHARS); • s for (indent=1; indent < Namβ j stack j ix; indent++) strcat(indent_str. INDENT_CHARS); /* retrieve the current structure's name from the name stack */ t name = pop_name(); /* don't use real name unless one or more items are published */ if (!published) name ■ generate_name(); e-3 SUBSTITLΠΈ SHEET sprιntf(Out_line. "\n*s} %s;". indentjstr. name) ; if ([published) free(name) ; add j jutput_line(); > /" declare all top level names in asm format too */ } /* end of ctosβ structs */ void fill_in_size() C nodejtype "this • This_list; nodejtype " last - Last_list; / » go to end of both lines */ whi le (this && this->next) this = this->πextf whi le ( last && last->next) last = last->next; / » always fi ll in size */ last->info->size = this->info->addr - last->info->addr; } /* fi ll in size «/ BOOLEAN check_for_ESC() C if (gfkbhitO) if (getkβyO «= ESC) return(TRUE) ; return (FALSE); 1 #ifdef old void free_node(node_type "item) C f ree(item->info) ; f ree(item->name_str) ; } /* end of free_node */ lendif void free_list(node_tyρe *list) C nodejtype "work. *temp; work * list; /* traverse list freeing as we go. .. */ whi le (work) f temp « work->πext; if (work->name_str) f reβ(work->name_str) ; if (work->info) c- y ,freβ,(wor„k->ι•n,fo),; 201 free(work); work = temp; } } /* end of free_list */ void frββ 3ym_list(name_list item_type "list) { name_list_item_type "work, "temp; work = list; /* traverse list freeing as we go... */ whi le (work) { temp = work->next; if (work->name) free(work->name); work = temp; } } /• end of free_sym_list */ void * emalloc(size_t size) £ void "ptr; if ((ptr = malloc(size)) == NULL) { printf ("\nOut of memory..."); clean_exit{-1); } else retum(ptr); } /* end of emalloc */ /* add the contents of Out_line to both files, handling "extern" appropriately */ void addjjutput_line{) £ char "ptr; do { /* place passed line in the header file, always */ fprintf(Header_file, "Xs", Out_line); /* also add real declarations (of static variable) to source file */ /* skip over #defines, they go only in header file */ if (strstr(Out_line, "#define") != NULL) break; /" don't use "extern" in source file */ if ({ptr = strstr(Out_line. "extern ")) != NULL) strcpyfptr, ptr+7); fprintf (Sourcejfi le, "Xs". Out_line); } while (FALSE); c-s SUBSTITUTE SHEET } /* end of add_output_linβ */ char * generate iame(void) C char * generated_name; /* allocate space for this new name */ generated iame = ■ emalloc(sizeof("_reserved_xxxx")); /* check for fatal error of running out of numbers "/ if (Gβnβrate ix >= 9999) £ printf("ERROR -- UTL001: Too many reserved names."); exit(-1); ) /* procude the name */ sprintf(generated j iame, "_reserved_X04d", Generate_ix++); return(generated iam-); } /* end of generate name » / c- ς / ' /* $Log: ' symjsxt.c.v $ 203 * Revision~1τ3" 1991/08/08 14:09:37 krassow * •** empty log message *** * * Revision 1.2 1991/08/08 13:21:00 krassow * *** empty log massage *** * */ /* */ /* global variables */ /« ---. */ #include <stdio.h> #include <stdlib.h> ^include <standard.h> #include »sdi_defs.h" ^include "sdi_cmds.h" #include "symtran.h" #include "sym_ext.h" char symextπ = "$Id: symjsxt.c.v 1.3 1991/08/08 14:09:37 krassow Exp $"; unsigned int Line - 0; name list item type * List; na e list item type * Listjsnd; char *Namejstack[50]; int Namejstack ix; FILE "Source_fi le, *Symbol_f i le, *Header_fi le; char Symbol_fi le_name[MAX_PATH_LEN]; char Sourcβ_f i lβ_name[MAX_PATH_LEN] char Header_fi le_name[MAX_PATH_LEN] char Sourcβ_f i le_base[MAX_PATH_LEN] BOOLEAN Quiet node; BOOLEAN All_symbols; char Version[100]; char User_include[MAX_PATH_LEN); char *Out_buf; char 0ut_line[100]; char "Out; unsigned int Geπerate ix; nodejtype *Last_list, *This_list; BOOLEAN Published; C-7 SUBSTITUTE SHEET 20 if- /* SLog: syn_ext.h.v $ • Revision 1.3 1991/08/08 14:09:39 krassow * "" empty log message *" - Revision 1.2 1991/08/08 13:21 :02 krassow * *" empty log nessage "" » * •/ /* Sid: sym_ext.h,v 1 .3 1991/08/08 14:09:39 krassow Exp $ */ /* / « global variables */ /• */ extern unsigned int Line; extern name_list_item_type * List; extern name_list_item_type * List and; extern char *Name_stacfc[50]; extern int Namejstack ix; extern FILE *Source_file, "Symbol_fi le, *Header_fi le; extern char Syπbol_file_naπe[HAX_PATH_LEN]; extern char Source_fi le_name[HAX_PATH_LEN]; extern char Hβader_fi lβ_namβ[HAX_PATH_LEH]; extern char Source_filβ_base[HAX_PATH_LEN]; extern BOOLEAN Quietjnode; extern BOOLEAN ALl symbolε; extern char Version[]; extern char User_include[MAX_PATH_LEN]; extern char *0ut_buf; extern char 0ut_lιne[100] f extern char "Out; extern unsigned int Generate Tx; extern node_type *Last_list, *This_lιst; extern BOOLEAN Published; C- f /« JεHeader: /homβ/solus/users4/rβlease/CVS/ link1/symtran/symtran.c,v 1.5 1991/09/15 21:08:47 krassow Exp $ */ /* $Log: symtran.c.v $ « Revision 1.5 1991/09/15 21:08:47 krassow * *** empty log message *** * * Revision 1.4 1991/08/08 14:09:41 krassow * "* empty log message *** * * Revision 1.3 1991/08/08 13:21:04 krassow * **• empty log message *** * Revision 1.2 1991/07/31 23:37:40 krassow * *** empty log message **' * Revision 1.1 1991/07/16 13:43:09 krassow * Initial revision /" Converts SCompi le Symbol table to files design. c and design, h /* The only symbols translated are tagged as "micro" symbols, /* unless the "all" switch is used (for debugging). /" Each symbol gets a variable (of type sprocjiatum) mapped into a /* structure so that heirarchial names (with dots) can be used. /* It is assumed that the .c file can be located at the SPROCs address /* by a linker/ locater, so no assembly file need be generated. ♦include <stdio.h> #include <string.h> ♦include <ctype.h> ♦include <stdlib.h> ♦include <staπdard.h> ♦include <fields.h> ♦include <sys\ types. h> ♦include <sys\stat.h> ♦include "sdijiefs.h" ^include "sdi_cmds.h" ^include "symtran.h" ♦include "symjjxt.h" shar symtran[] = "$Id: symtran.c.v 1.5 1991/09/15 21:08:47 krassow Exp $"; /* / /* interface declarations */ /* */ /* interface to Terry's command line module */ sxtern int cmdline(int argc, char *arcv[], int n_sw, char sw[], int(* swjun[])(), char "badjsw ); sxtern void getji lenames(int argc, char" argv[], int max_fi les, int* njfiles_ptr, char* files[]); sxtern int do_switches(int argc, char *arcv[], int n_sw, char sw[], int (*sw fun[])(), char "badjsw ); /oid frβe_list(nodβ_type "list); /oid fi ll in size(void); /oid cleanjixit(int code); .xtern BOOLEAN check_for_ESC(void) ; int add_datajsym(unsigned int symjjddr, char "symbol); int add_patternjsym(sprocj.atum pattern, char "symbol); jnsigned char aschex2char( unsigned char * high_byte); /oid * emalloc(size_t size); /oid symrec_to_struct_entry(char * symbolj^ec); /oid symrβcjto_dβfinβ(char * symboljrβc); /oid write_out_buf(void); C- ? SUBSTITUTE SHEET extern void add j .utput_liπβ(void); char interface2char(B00LEAN interface); /* interface to sym it l module */ extern char * generatβ ιamβ(voιd); extern void show_progress(int *cnt); extern char * ake_name(char "start, char *end); extern void insert(node_type "item, node_type * "head); extern void push ιame(char *name); extern char * pop ιamβ(void); extern void atfd_to_list(char *symbol_rec, char ■ name); extern void freβ_sym_list(πamβ_list_item_type "list); /* interface to AndyLib extern void build_str(char *str, char c, int cnt)r /* sps jtil interface */ extern BOOLEAN symrec2interface(unsigned char * symbolj-ec); extern unsigned int symrec2addr(unsigned char * symbol_rec); extern sproc jatum symrec2flag(unsigned char * symboljrec); extern unsigned int symrec2cnt(unsigned char * symboljrec); extern unsigned int symrec2zone(unsigned char * symboljrec); extern int symrec2fm (unsigned char * symboljrec); extern unsigned long syπrec2pattern( unsigned char * symbol_rec); unsigned long chars2lαng(char 'field); void show_list(nodβ_type *list); extern void close structs(int level, BOOLEAN published); /" error handling file interface to display module */ extern FILE *βfopen(char * path, char * type); extern int βfclose(FILE *file_ptr. char * f lejname) ; void display_banner(char 'version); int sβt_aII symboIs(void); int set_quiet(void); int show jsage_and_exit(void); int set_user_include(char *new_ext); int process records(void) ; char Sw_str[] = "ahqU" ; int maιn{int argc. char" argv[]) C #definβ NUMJ3WITCHES (sizeof(Sw j str)-l) int (*fune[NUM_SWITCHES]) {) ; char sw_status; char * filβs[21; char cmd_line_filβ_namβ£HAX_PATH_LEN]; int n_files « 2; /* #definβ loopTest 1 •/ #ifdef loopTest int test; #endif ♦ifdβf loopTest for (test=0; test<1000; test++) £ ♦endif c- /o »emset(Namβ j stack, '\0', sizeof(Namejstack)); strcpy(Vβrsion, "SRevision: 1.5 $"); /* identify version */ display_bannβr(Version); /* note that order in function array must match switch string below */ func[0] = set_all_symbols; func[1] ι show_usagβ_and_exit; func[2] = set j quiet; funo[3] ' » set jser include; /* pay attention to command line switches, if present */ if (do switches(argc, argv, NUMJ3WITCHES, Swjstr, func, Ssw status)) { printf ("\nERR0R -- SYM004: Unknown switch Xc". swjstatus); show_usagβ_and_βxi t ( ) ; } /* get file names, but just check for one */ /* must allow for 2 filenames to trap missing "-" on switches */ f i les[0] = files[1] = cmd_line fi lejiame; get_fi lenames(argc, argv, 2, &n_fi les, files); /* force zero or one filenames on command line */ switch (n_fi les) { case 0 : printf("\nERR0R -- SYM001 : File name must be specified on command line."); show_usage_and_exit(); break; case 1 : /* enforce proper base name syntax */ /* disallow embedded dots, non-alpha lead chars */ if ( (strchr(files[0], * . * )) || (strlen(files[0]) > 8) || ( (!isalpha(files[0][0]) && strchr("_$", files[0][0]) != NULL) ) ) { printf ("\nERR0R -- SYH002: Invalid file base name parameter 'Xs'.", files[0]); show_usage_andjsxi t ( ) ; } else { /* base name is OK, use it */ strcpy(Source_fi le_base, fi les[0]); } break; default: printf("\nERR0R -- SYM003: Unknown parameter >Xs< (use * -' to precede switch).". files[1]); show_usagejsnd_βxit(); break; /* pay attention to command line switches, if present */ if (do_switchβs(argc, argv, NUMjSWITCHES, Sw j str, func, asw status)) { printf("\nERR0R -- SYM004: Unknown switch Xc", swjstatus); show_usage_and_exit(); } /* create output fi le names */ SUBSTITUTE SHEET /* use this base name */ strcpy (Syabo l_f i lβ_name , Source_f i lβ_base) ; strcpy(Source_f l lejiame, Source_f lβ_base) ; strcpy(Hβader_fi lejiame, Source_f i le_base) ; /* apply extensions *Y strcat(Symbol_fi le_name, ".sps") ; strcat(Source_fi lejiame, ".e") ; strcat(Header_f lejiame, ".h") ; if {(Symbol fi le » βf open (Symbol_fi Lejiame, "r")) 0) clβan_exit{-1) ; /* open these for write */ if ({Source F le = efopβn(Source_fi lejiame, "w")) = 0) clβanjβxιt(-l); if ((Hβader_fi le = efopen(Header_fι * lejiame. "w")) = 0) clean_exit(-1 ) ; /* log the creation process */ strcpy(Out_line. "/* Generated by symtran.exe SRevision: 1.5 $ */\n") ; add jutput_line(); /* make reference to our header fi le *λ strcpy(0ut_liπβ. "#include \"sprocdef .h\"\n") ; add_output_lιne{) ; /* make reference to user's include fi le, if specified */ if (strlβn(User_inctude)) £ strcpy(0ut_line. "^include \"") ; strcat(Out_line, User Tnclude) ; strcat(Out_line. »\»\n") ; add_output_lϊne() ; /* */ /* Emit the code and control declarations */ /* Then emit the data space structure */ /* wrap the whole thing in a structure declaration to force ordering */ /* first, the code and control declares */ sprocjsode_space_type Xsjsode;", INDENT_CHARS, Source_f i le_base) ; add j 3Utput_linβ() ; sprocjiontro I spacejtypβ Xsjεontrol;", INDENT_CHARS, Source_f i lβ_base) ; add jutput_lιnβ() ; /* now do the data space */ strcpy(Out_line, "\nextern before /olati le struct £") ; add_output_line{) ; /* process the records in the symbol fi le */ process records() ; efclose(Symbol_file, Symboljfi lejiame); efclose(Sourcβ le, Source T i lejiame) ; efclose(Header_f i le. Header fi lejiame) ; printf ("VnFinished creating 'Xs' and 'Xs' .\n", Sourcβj i lejiame, Hβader_fi lejiame) ; - /Λ. clean_βxit(0) ; #ifdef loopTest } /* end of test */ lend f return(O); } /* end of main */ /* */ /* Read the storage section to bu ld structure tree */ /* Use the the micro tag to determine which items to make public */ /* */ int processj-ecords() £ /* Give usefu l names to sections of the .SPS fi le. */ /* These sections are separated by a b lank line. */ typedef enum { STORAGE _SECTI0N. I0_SECTI0N, LABELSJ3ECTI0N. ORDINARY 3ECTI0N. TIMEZONE_SECTI0N } section type; char symbol_rec[MAX_SYM_REC_SIZE] ; int dot_cnt = 0, datajsym_cnt = 0, pattern_sym_cnt = 0; section_type section = ST0RAGEJ3ECTI0N; BOOLEAN done iojance = FALSE; unsigned int addr ; BOOLEAN done_with_fi le - FALSE; This_list = Last_list - NULL; /* process unti l end of symbol fi le */ whi le ( !done_wi th_fi lβ) { /* let user bai I out */ if (check_for_ESC()) { printf ("\nWARNING -- SYM005 : Terminating symbol conversion per user request . . . ") ; break; if ((fgets(symbo l -ec, si zeof (symbolj-ec) , Symbo l_fi le)) == NULL) £ if (fβof(Symbol_fi le)) break; else { printf("\nERROR -- SYM006: Problem reading input file, line Xd.", Line); break; } } if (section = LABELSJ3ECTI0N) =5 donβ_io_once = FALSE; /* empty lines (consecutive If's) indicate section change */ ■ > if (strcmp(symbol -ec, "\n") == 0) £ /* move on to next section "/ /* section ++; The form below removes the implicit conversion. "/ /* section » (section_type) (((int)(section))++); */ section ■ (section_type) (((int)(section)) + 1); C v. SUBSTITUTE SHEET continue; J /* not in our section yet, keep looking */ switch (section) £ /* case LABELS SECTION : */ case ST0RAGEJ3ECTI0N : λ* only bother with data space symbols */ addr = symrec2addr(symbol_rβc); /» if (IS_DATA_ADDR(addr) |[ IS_C0NTR0L_ADDR(addr)) */ if (IS_DATA_ADDR(addr)) symrec_to j struct_βntry(symbol_rec); show_progress(&dot snt); break; case IO SECTION : if (!done_io_once) { /* close any pending structures */ close structs(0. Published) ; /* close top level structure */ sprintf(Out_line, "\n} after_volati le Xs;\n\n"» Sourcejfi Le jase) ; addjautput_line() ; done_io_once = TRUE; } break; case ORDINARYJSECTION : /* convert these symbols into ^defines */ /* skip the ones beginning with _ */ if (symboljrecfO] != '_') [ symrec_to_define(symbol_rec); } show_progress(Sdot_cnt); break; case TIHEZONEJ3ECTI0N : done_with_file » TRUE; break; default : /* other sections have no special significance for us */ break; } return(O) ; } /* end of -. " -ocβss records *A /* modify Prev idl to insertion point */ /* return TRUE if Batch; traverse by sibling */ void ■ake_valid_c ιame(char "name, char sub_list[]) d-/y £ char "swapjihar; size t i; /* substutite source char with dest char for every pair in the sub_list */ for (i = 0; i < str len(sub_list) ; i+=2) while {(swap_char = strchr(name, sub_list[i])) != NULL) *swap_char ■ sub_list[i+1] ; } /* end of make_valid_c jiame */ /* parse name into series of dot-delimited names, handle each name in turn */ /• All but the last name are nodes */ void parsβ_a_line(char * symbol -ec) £ char "start jtr, *end_ptr, "name; nodejtype *item; This_list « NULL; /* remove non-C chars from name */ makβ /alid_cjιame(symbol 'ec, "XP&A") ; /* start off with both pointers at beginning */ startjstr = end_ptr = symbolj-ec; /* process the whole line */ whi le (start_ptr != NULL) £ /* find next dot, if any */ if ((end_ptr = strchr(start_ptr, '. * )) != NULL) { /* construct name */ name * makβjιame(startjJtr, endjtr); /* point past this dot for next item */ start_ptr = end_ptr + 1; /* create and fill in new node structure */ /* item = createjιode(na e); */ item « emalloc(sizeof (node_type)) ; item->namejstr = name; item->info ■= NULL; item->next « NULL; item->prev - NULL; insert(item, aYThis_list); } else £ /* no more dots, space signifies end of this name (leaf) */ end_ptr ■= strchr(startjtr, ' '); /* construct name */ name - makβ ιame(start ptr, end_ptr); /* fill in node structure */ /* item ^tr = createjιode(name); */ item » emalloc(sizeof(node type)); item->namejstr » name; item->next « NULL; C-/Sr SUBSTITUTE SHEET iteι»->prev = NULL; /* fill in other leaf data here */ itera->info = emalloc(sizβof(leaf_type)); item->info->addr = symrec2addr(symbol_rec); item->info->zone = symrec2zone(symboIj-ec); item->info->interface = symrec2interfacβ(symbol_rec); insert(item, SThis_list); break; A* all done with this record */ J /* end of parsing the line */ } /* end of parse_a_line */ char intβrface2char(BOOLEAN interface) £ return( (char)((interface) ? 'm' : ' ') ) ; } /* end of interface2char */ /* create a ^define for the symbol passed */ void symrec_to_dβfinβ(char * symbol_rec) i char define_name[50]; int len; enu £ NO_SPACE. TOO .ONG, ALL_0K > status = ALL_0K; char * ptr; char spaces[51]; unsigned long value; BOOLEAN once = FALSE; do £ if ( (ptr = strchr(symbol_rec, ' ')) != NULL) £ len « ptr - symbo l_rec; if (len < sizeof(define_name)) £ strncpy(definβ ιame, symbol_rec. len) ; defiπejιame[len] = '\0' 3 else £ status = TO0J.ONG; break; } } else £ status « NOJSPΛCE; break; } /* don't allow i llegal chars in define id */ ■ake_va lidjs_name(def ine iame, "XP8A.D") ; /* grab the value for the define */ value = symrec2pattern(symbol rec) ; /* convert f le base name to all upper case to compose define name */ strcpy(base_name, Source_f i le_base) ; strupr(base name) ; /* align value at column 50 */ len * 50 - 8 - strlen(definejιame) ; bui ldj3tr( spaces, ' ', ten); sprintf(Out_tine, "#define Xs_XsXs0xX06lX\π", base iamβ, dβfinejiamβ, spaces, value); add jutput_linβ(); } whi le (once) ; } /* end of symrec_tojiefine */ void symrec_to 5tructjsntry(char * symbol -ec) £ nodejtype "this; node_type *last; int level = 0; char indent str[100]; BOOLEAN leaf; BOOLEAN diff struct char temp it ring [100]; int space_count; char "generatedjiame; /* establish initial indentation */ strcpy(indentjstr, INDENT_CHARS); parsβ_a_line(symbol -ec); /* bail here for first line */ if (Last_list »■ NULL) { Last_list = This_list; return; } fi l njsize(); for (this = This_list, last = Last_list; /* initialization */ last != NULL: /* iteration test */ last = last->next, level++. /* adjustment */ strcat(indent_str. INDENT_CHARS)) { /* this flag is TRUE when a structure change is required */ diffjstruct = (strcmp(Name_stack[ level], last->name_str) = 0) ? FALSE : TRUE; /* item is a leaf iff it is the end of the chain */ leaf = (last->next == NULL) ? TRUE : FALSE; /* if next item exists and new (different) structure */ /* add a structure declaration */ if (I leaf && diffjstruct) £ /* different name must bubble up structure terminator */ close structs(level. Published); /* begin new structure, so assume not published */ Published = FALSE; CV7 SUBSTITUTE SHEET £". indent str) ; addjoutput_linβ{) ; /* All components of a name are treated as public */ /* so that if one or more is, the name exists */ push jiame ( last->name_str) ; continue; 1 /* if leaf node, emit structure element */ if (leaf) £ /* always start with 60 spaces */ spacejsount = 60; λ* output front part of declaration */ strcpy(Out_line, "\n") ; addjjutput_line() ; space_count -= strlβn(Out_line) ; /* Publish the real name if : */ /« the publishjΛll switch is set */ /* a top level non-system signal (wire) */ /* the symbol is tagged as micro */ if ( (All synibols) | | (last->info->i nterf ace) j j ( (level = 0) && (last->name_str[0] != '_ * ) ) ) £ spacejsount -= sprintf (0ut_lιne, "Xssdata Xs". indentjstr. last->πame_str) ; add_to_li st (symbo l_rec, NULL) ; Published = TRUE; } /* otherwise, use a fi ller in the structure (placeholder) */ else £ generatedjiame = generate_name() ; spacejsount -= ■ sprintf(Out_line, "Xssdata Xs", indentjstr, generatedjiame) ; add_to_lιst(symbol_rec, generatedjiame) ; 1 addj3utput_line() ; /* declare arrays as such */ if ( last->iπfo->size > 1 ) spacejsount -= sprintf(Out_line, "[Xu]", last->info->sizβ) ; else strcp (Out_line, ""); addj3utput_line() ; /* bui ld a spacing line to line up address comment */ nemset(temp string, * ' , spacejsount) ; tempjstring[spacejsount] = '\0' ; sprintf(Out_line, »;Xs /* X04x Xc */», temp stri ng . last ->i nf o->addr, i nterf ace2char( last->i nf o->i nterf ace) ) ; add_output_line() ; 3 } /* end whi le not end of list */ /• latch line for next iteration */ free list (Last list); Last_list « This_list; This_list = NULL; return; } /• end of symrec_to struct 5ntry */ int show ιsage_and_exit() £ /* HELP message */ printf ("\nUsage: SymTran ile [-A] [-Q] [-Ufi lename]") ; printf ("\n"); printf ("\n -A specifies translate All symbols (for debugging only)"); printf ("\n"); printf ("\n -Q indicates Quiet mode (limited screen output)"); printf ("\n"); printf ("\n -U specifies an #includβ directive filename"); printf ("\n"); printf ("\nTwo output files are created named 'basefile.c' and 'basefi le.h'."); printf (»\n»); clβan_exit(-5); return(O); } /* end of showjjsage_and_exit */ void display_banner(char "version) £ /* identify self */ printf("\nSymTran - SPROC Symbol Translator"); printf(" Xs", version); printf ("\nCopyright (C) 1991 by STAR Semiconductor Corporation."); printf(" all rights reserved. \n"); 3 int set_all_symbols(void) £ Alljsymbols = TRUE; rβturn(O); } /* end of set_a 11 jsymbo Is */ int set_user_include(char *str) £ if (strlen(str) < sizeof (User includβ)+1) £ strcpy(User include, str); 3 else £ printf("\nERROR -- SYM007: Bad user include f le name."); 3 rβturn(ret_val); 3 /* end of set_user_include */ int set ^uiet() £ Quiet jaode « TRUE; rβturn(O); SUBSTITUTE SHEET void cleaπ_exit(iπt code) £ int i; /* free the tree and exit */ free_list(This_list); Thiε_list = NULL; freβ_ll'st(Last_list)r Last_list = NULL; for (ι=0; i<(sizeof(Name stack) / sizeof (Name_stack[0])); i++) if (Name stack[i]) frβe(Name stack[i]) ; else break; 3 f ree(Out_bu ) ; f ree_syπ_list(Lιst) ; List = NULL; Listjsnd = NULL; ♦ifndef loopTest exit (code); ♦endif } /* end of clean exit */ - o ♦include <stdio.h> 21 ♦include <string.h> ♦include <ctype.h> ♦include <stdlib.h> ♦include <standard.h> #include "sdijdefs.h" ♦include "sdijsmds.h" ♦include "symtran.h" char sps_util[] = "Sid: sps itil.c.v 1.31991/08/0814:09:34 krassow Exp $"; * .- unsigned long chars2long(char "field); int chars2int(char "field); unsigned char aschβx2char(uchar_ptr highjsyte); void copy 3long_to_sdata (sproc_datum "dest, unsigned long *src); /* fields of signal records */ ♦define SIGNAL_SYM_C0L 0 #define ADDR_SYM_COL 51 #define PATTERN_SYM_C0L 51 ♦define Z0NE_SYM_C0L 57 ♦define FORMAT_SYM_COL 63 #define I TERFACE_SYM_COL 66 /* fields of zone records */ fdefine Z0NE_ID_SYH_C0L 0 ♦define Z0NE_NAME_SYM_C0L 6 #define DECIM_CNT_SYM_COL 59 #define WAIT_FLAG_SYM_COL 65 #define BUF_LEN_SYM_C0L 73 BOOLEAN isjddress_rec( unsigned char * symbol -ec) £ unsigned char temp str[7+2]; BOOLEAN address_flag = FALSE; int i; /* pick out 7 chars from record */ strncpy(tempjstr, 8;symbolj-ec[ADDR_SYM_C0L], 7); /* null terminate this string */ temp_str[8] = * \0'; do £ /* if a space or line feed is encountered, it is an address record */ for (i=0; i<5; i++) if ( (temp_str[i] == ' ') || (temp_str[i] == * \n') jj (temp_str[i] == '\r') ) £ addressjlag = TRUE; break; 3 if (addressjflag) break; /* also an address if 6 char field flagged with 'h' */ ♦ifdef oldjsode /* if h supplied, must convert to address as last 4 digits of 6 char field */ /* Not done, since any hex variable may not be an address. */ SUBSTITUTE SHEET if (symrec2f«t(syabol_rec) = HEX βode) addresε_flag = TRUE; ♦endif } while (FALSE); rβturn(address_flag); } /* end of is_address_rec */ unsigned long symrec2cnt( unsigned char * symbol_rec) £ unsigned long rβt_val; rβt_val * chars2long(&symbol_rec[0ECIH_CNTjSYM_C0L]) ; rβturn(ret_val); } /* end of symrec2cnt */ unsigned int symrec2zαne( unsigned char * symbol_rec) £ /* special case of spaces for zone field means can't probe signal */ if (strncmp(&syπbol_rec[ZONE_SYM_COL], " "» 4) = 0) ret_val * CANT_PR0BE_Z0NE; else ret al = chars2int(Ssymbol_rec[Z0NE_SYM_C0L]); return(ret_val); } /* end of symrec2zone */ BOOLEAN symrec2interface( unsigned char * symboljrec) £ BOOLEAN rβtj al; /* special case of spaces for zone field means can't probe signal */ if (symbo l_rec[INTERFACE_SYM_COL] != ' * ) else ret_val = FALSE; rβturn(ret_val) ; 3 /* end of synrec2interface */ sprocjjatum synrec2flag( unsigned char * symbol -ec) £ sprocjjatum temp sdata; unsigned long temp_long; tβmp_long = chars2long(&symbol_rec£WAIT_FLAG_SYH_C0L]) ; copy 3long_tojsdata(&temp sdata, &temp_long) ; return(temp sdata) ; } /* end of symrec∑f lag */ long syarec2pattern{ unsigned char * symbo l_rec) sprocjiatua temp sdata; C-«?Λ- unsigned long temp_long; temp_long = chars2long(asymbot_rec[PATTERN_SYM_C0L]); return (temp_ long); } /* end of symrβc2pattern */ int symrec2fmt(unsigned char * symbol -ec) £ /* pick out char */ rβt_val « symbo l_rβc[F0RMATJ3YM_C0L] ; /* accept i or f, default to u for undefined */ switch (retj/al) { case 'i' : retjal = INTjnode; break; case 'f : ret al = FPjnode; break; case 'h' : rβt /al = HEXjnode; break; default : ret_val = UNjiiode; break; 3 rβturn(ret al); 3 /* end of symrec2fmt */ unsigned int symrec2addr( unsigned char * symboljrec) £ unsigned int rβt_val; rβtjal « chars2int(&symbol -βc[ADDR_SYM_C0L]); return(rβt_val); 3 /* end of symrec2addr */ unsigned long chars2loπg(char *field) £ unsigned long ret_val; char tempj5tr[7]; int i; unsigned char byte[3]; /* pick out chars of field */ strncpy(tβmp str, field. 6); /* make null terminated string for conversion */ temp_str[6] = '\0'; /* convert to value */ for (i=0; i<3; i++) byte[i] «= aschex2char(&tempjstr[i*2]); /* convert to value */ ret_val = (((unsigned long)byte[0]) « 16) + (((unsigned long)byte[1]) « 8) + (byte[2]); return(rβt_val); /* end of chars2long */ ε-<23 SUBSTITUTE SHEET int chars2int(char "field) £ int ret_val; char temp_str[5]; int i; unsigned char byte[2]; /* pick out chars of fiβLd */ strnepy(temp str, field, 4); /* make null terminated string for conversion */ temp_str[4] = '\0'; /* convert to value *7 for (i=0; i<2; i++) byte[i] aschex2char(&temp_str[i « 2]); /* convert to value */ /* must cast to unsigned int to stop sign propagation *7 rβt_val = (((unsigned int)bytβ[0]) « 8) + (((unsigned int)byte[TJ) ); rβturn(ret_val); } /* end of chars2int */ unsigned char aschex2char(uchar_ptr high_byte) £ int i; unsigned char c, val = (unsigned char) 0; /* convert 2 successive ascii bytes into a hex value */ for (1=1; i<=2; i++) £ val = (unsigned char) (val « (unsigned char) 4); /* allow for space led fields */ if (*high_byte = * ') C = * 0'; else c = (unsigned char) toupper(*high_byte); if (c < 'A') val += c - '0'; else val += c - 'A' + 10; 3 return(val); 3 /* end of aschex2char */ void copy_3long to sdata (sproc j iatum * dest, unsigned long * src) £ dβst->hi « (unsigned char) ({*src & OxOOFFOOOO) » 16); dest- aid « (unsigned char) ((*src & OxOOOOFFOO) » 8); dest->lo « (unsigned char) (*src S OxOOOOOOFF) ; /* end of copy_3long_to_sdata */ /* SLog: symtran.h.v $ * Revision 1 .4 1991/08/08 14:09:45 krassow * *** empty log message *** * * Revision 1 .3 1991 /08/08 13: 21 :07 krassow * *** empty log message *** * « Revision 1 .2 1991 /07/31 23:37:42 krassow * *** empty log message "* * */ /« Sid: symtran.h.v 1.41991/08/0814:09:45 krassow Exp $ */ ♦define MAX_PATH_LEN 250 ♦define MAX_SYM_LEN 50 ♦define MAX_SYM_SIZE 51 ♦define MAX_SYM_REC_SIZE 100 ♦define INDENTJJHARS " " typedef struct leaf_type struct £ unsigned int addr; /* wire's (parameter's) address */ unsigned int zone; /* timezone parameter */ BOOLEAN interface; /* TRUE = interface wire */ unsigned int size; /* default = 1 sproc datum */ } leaf typβ; typedef struct nodβ_type struct { char * name_str; struct nodβ typejstruct * next ; struct node_type struct * prev; struct leaf_typβjstruct * info; } nodejtype; typedef struct namβ_item_struct £ struct name i temjstruct * next ; char * name; unsigned int addr ; } name list item_type; C -A. c- SUBSTITUTE SHEET SLog: βfprintf.c,v S C. .C. Revision 1.1 1991/07/10 00:05:33 krassow Initial revision •A nclude <stdio.h> nclude <stdlib.h> nclude <stdarg.h> ar efprintf_id[] = "Sid: efprintf .cv 1 .1 1991/07/10 00:05:33 krassow Exp $"; t βfprintf( FILE "stream, char "format. ... ) _list args; /* initialize the variable list pointer to point to first element *A va_start(args, format) ; ret_val » vf rintf (stream, format, args); fprintf (stderr, "\nERR0R -- EFP001 : Fi le output error - do you have any disk space left?") ; exit(-l) ; 3 va_end(args) ; rβturn(rβt_val) ; APPENDIX SUBSTITUTE SHEET '* SLog: makeload.c.v S ' Revision 1.15 1991/09/15 20:27:05 krassow * Finally changed Id to Revision for generated comment. * Revision 1.14 1991/05/15 20:25:15 krassow * Changed Header to Id for generated comment. * Revision 1.13 1991/09/15 20:23:46 krassow * Added bβforβ j sonst. after sonst and generation comment. * * Revision 1.12 1991/09A12 20:42:09 krassow * Changed from _load to _block. * Revision 1.11 1991/07731 23:32:56 krassow * Fixed SHI file Ox, bug * * Revision 1.10 1991A07A19 19:15:45 krassow * *** empty log message « ** * * Revision 1.9 1991/07718 20:18:24 krassow * makef le now installs to inhouse * makeload uses all uppercase in output f les * Revision 1.8 1991A07A18 18:51:04 krassow * correct scheme for master sproc boot blocks. /* 05/21A9T ajk 1.12 Don't use bold characters in help message. "7 '* Use all uppercase hex chars for generated output. */ '* (Note that spp files contain lowercase! */ '* 02A21/91 ajk 1.10 Don't write to trigger addresses in data ram (800-813) */ '* Converts SCo pile output to LOAD FILE (Motorola S1) format */ '* converts to Master SPROC Pro* format (-P) *7 • * creates to SPROC boot format (-S) for SMI */ '* creates CODE, CONTROL and DATA files if asked (-E) */ '* surpresses records of all zero data if asked (-Z) */ '* surpresses status display (-Q) *7 'include <stdio.h> 'include <string.h> 'include <stdlι'b.h> 'include "ctype.h" 'include "standard. h" 'include "■akeload.h" :har aakeload[] - "Sid: makeload.c.v 1.151991/09/1520:27:05 krassow Exp $" ; '* */ '* interface declarations */ ' « « / ixtern int do_switches(int argc. char *arcv[], int njsw, char sw[], int (*sw_fun[]){). char *bad_sw ) ; ixtern void get_fi lenames(int argc, char* argvf], int max_fi les, int* n_f i lβs_ptr, char* fi lβs[]) ; •oid aake_blk str(char *buf» int size, int addr) ; :har * readjfi le(char ' in_buf, int bytes_to_read, FILE "fi le, int" len) ; •oid initjsutputjsuf fers(void) ; ■ oid advance_to_next(char ** work_ptr) r ■ oid aake_roa_header(char *buf» int size, int addr, BOOLEAN lastjflag); • oid write_bufs_to_fi lβ(void); • oid show_progress(void) ; ■ oid creatβ_output_βxtension(char *ext str) ; P- l /oid create_checksum(char "cptr, char *buf); int crβate_hβader(char *hptr); shar *emalloc(int size); int βfread(char "ptr, unsigned size, unsigned count, FILE *data_file); int eread(int data_file, char "ptr, unsigned size); int ofprintf( FILE "stream, char "format, ... ); /oid display_banner(char "version); 100LEAN «ιak6j)j-ecord(char **in_buf_ptr. char * endjstr); 300LEAN make -ecords(char *in_buf, int in suf_len); /oid apply_default_extensioπ(char "fname, char *ext); shar checkjfi les(void); ixtern FILE *efopen(char *path, char *type); ixtern int efclose(FILE *file_ptr, char *fi lejiame); int set fi lβ ιames(char *str); int setjsxtra fi lβs(char *str); int set_quiet(char *str); int show_usage_and_exit(void); int set_Boot_ROM_mode(char *str); int makβ 3MI_f i le(char *str); int set jero_surpression(char *str); /oid add i I l_byte (char "record); /oid byte2ascii (unsigned char "str, unsigned char data syte); /oid correct_b locking info (int len, int buf -ow, int startjsddress) ; '* */ '« global variables */ i* . .................. »/ snum £ B00T_R0M. S1_FILE 3 Mode = S1_FILE; '* starting locations with respect to this program */ 'define CODE_START_ADDRESS 0x0 'define CONTROL_BASE_ADDRESS 0x400 'define CONTROL_START_ADDRESS 0x410 'define DATΛ_BASE_ADDRESS 0x800 'define DATA_START_ADDRESS 0x814 'define C0NTR0LJ.ENGTH OxFO 'define R0W_SIZE ( (SPR0C_T0TALJ3DATA / SDATA_PERJ3REC) + 2 ) '* allow for start and end records * */ 'define COL_SIZE_SMI ((SDATA_PER_SREC*(2 +4 + CHARS_IN_SDATA)) + 2 ) • fill byte | | | */ '* comma, space. Ox separator + | */ '* newline plus null + */ 'define C0L_SIZE_S1 ( (SDATA_PER_SREC * (CHARS_IN_SDATA + 2)) + SREC_0H +2) ' « fill byte | « / :har Out_buf_S1[R0W_SIZE][C0L_SIZE_S1] = { '\0'} ; :har 0ut_buf_SMI[R0W_SIZE][C0L_SIZE_SMI] = £ '\0'3 ; nt Row_S1 « 0, Row_SMI 0; insigned int Sproc_address; msigned int PROMjddress; 100LEAN Make_SMI_fi le - FALSE; : ILE *0ut_f i lβ 31. *0ut_f i lβ_SMI ; r ILE *Datajsut i le, *Code_out fi le, "Control sutjfi le; I00LEAN Makβ_extra_f i les - FALSE; I00LEAN Zero surpress = FALSE; :har Code_fi lβ_naae[FILE_NAME_LENGTH]; :har Data_fi le_naaβ[FILE_NAME_LENGTH]; :har Design_naae[FILE_NAME_LENGTH]; :har Out file S1 name[FILE NAME LENGTH]; £>- SUBSTITUTE SHEET shar 0ut_fileJSHI_naae[FILE_NAHE_LENGTH]: 300LEAN Quietjiodβ * FALSE; shar Version[] « C "SRevision: 1.15 $" 3 ; fdefinβ START_RECORD "S0030000FC\n» / */ /* code section *A /* *A shar cmd sw_str[] » "ehPqSz"; int main(int argc, char* argv[]) r : ILE « codβ_file. *data_file; shar out sode_f i le_name[FILE_NAME_LENGTH] ; shar out sontrol_fi lβ_namβ[FILE_NAME_LENGTH] ; shar out_data_f i le_name[FILE_NAMEJLENGTH] ; int recs; shar ext_str[5] ; int bytes_to_rβad; int codβ_info_row_S1. control_info row_Sl . data_info_row_S1 ; int codβ_info_row_SHI, control info_row_SMI. data_info_row_SHI; int last sode ddr. last sontroljaddr, last_data_addr ; /* coaaand line overhead 'A fdβfinβ NUMJSWITCHES (s zβof(cmd sw str) - 1) int (*func[NUM_SWITCHES)) () ; shar status; shar * fi lβs[2]; A* allow for error handling of multiple fi le entry *A shar cmd_tine_fi lβ_name[FILE_NAME_LENGTH]; int n Ti les; shar *work_ptr; shar *ϊn_buf ; int in_buf_len; shar record[100]; A* always tell who we are */ display_banner(Vβrsion) ; /* initialize output buffers */ init_output_buffers() ; /* set up functions activated by coa and line switches */ fuπc[0] « sβt βxtra fi les; fuπc[1] ■ show jsagβ andjsxit; func[2] m 3βt_Boot_R0M_aodβ; func[3] m setjquiet; fuπc[4] ■ aakβJSHI_fi lβ; A* for SMI support *7 func[5] ■ sβt_zero surpression; /* pay attention to coaaand Line argueαents, if present *A if (do_switches(argc. argv. NUMJSWITCHES, cmd sw str, func, Sstatus)) { printf ("ERROR -- LOD001 : Unknown switch Xc". status) ; show_usage_and_exi t() ; J A* get fi le naaes, but just check for one *A fi les[0] m cad_linβ_filβ_naaβ; b-3 gβt_f i lenames(argc, argv, 2, &n_fi les, files); 22/ switch (n_filβs) £ case 0 : /* no file specified, don't use defaults */ printf ("\nERR0R -- LOD010: Missing input file name."); show_usage_and_βxit(); break; case 1 : sβt_fi le ιames(fi les[0]); break; default : J>5f printf ("\nERR0R -- LOD002: Unknown parameter >Xs< (use '-' to precede switch).", filesp]); show_usagβ_and_βxi t ( ) ; brea ; /* with switches all applied, produce full file names */ apply_default_βxtension(Codβ_fi lejiame, "spp"); apply default_extension(Data fi lejiame, "spd"); createj3utput_βxtβnsion(extjstr); apply_dβfault_extension(Out fi lβ_S1 jiame, ext str) ; apply_dβfault_βxtension(Out Fi le SMIjiame, "blk"); /* open needed input files */ /* don't open output files here, do later to avoid hammering good file */ code T i le = efopen(Code_fi lejiame, "r"); datajf i le « efopen(Data_fi lejiame, "r"); /* tell user what's happening */ if (IQuietjuode) £ printf ("\nWorking on "Xs * ", Out _f i lβ ?1 jiame) ; if (MakβJ3MI_f i le) printf ('• and 'Xs'", 0ut_f i le_SHIjιame) ; if (Makβ sxtra i les) printf (" and extra files"); printf(".\n"); 3 /* put appropriate start record into file */ Strcpy(0ut_buf _S1 [R0W_S1++ J . START_REC0RD) ; /* put start lines into SMI file */ strcpy(record. "/* Generated by makeload.exe SRevision: 1.15 $ */\n"); strcpy(Out_buf_SMI [Row_SMI++] , record) ; strcpy(record, "#i nclude \"sprocdef .h\"\n\n"); strcpy(Out_buf_SMI[Row_SMI++] , record) ; sprintf (record, "bβforβjsonst fix24 typβ aftβrjsonst Xs_block[] = { \n", Designjiame); strcpy(Out_buf_SMI[Row_SMI++] . record) ; /* handle extra files, if needed */ if (Make_extra_f i les) { /* use these fixed names */ strcpy(out_code fi lejiame, "code") ; strcpy(out sontrol_fi lejiame, "control"); strcpy(out_data_fi lejiame, "data"); D-Y SUBSTΓΓLΠΈ SHEET /* and these fi le naae extensions */ ap ly iβfau lt_βxtβnsion{out_codβ_fi lejiame, β xt str) ; ap ly def au It sxteπsi on (out jsontro L_f i lejiame , ext _str) ; ap lyjiβfau lt_extensιon(out_data_fi lejiame, extjstr); /* attempt to open these fi les, terminate if fai lure */ Codej-ut_f i le » βf open (out sode_fi lβ_name, "w") ; Control_put_fi le « efopen(outjsontrol_fi lejiame, "w") ; Data_out_f i le « βfopβn(out_data_fi lejiame, "w") ; /* put start record into these fi les */ efprintf (Codβ_out_fi le, START.REC0RD) ; efprintf(Controljsut_f le, START_REC0RD) ; βf ri ntf (Data_out_f i le . START_REC0RD ) ; 3 /* *A A* begin code records *A A* *A A* Instruction RAH starts at zero *A PROM_address « 0; Sproc_address * C0DE_START_ADDRESS; if (Hake_SMI_fi le) £ codβ_info_row_SMr » RowjSMI; Row_SMI++; A* leave space for block size and start address */ 3 A* reaeaber where to put block size and start address *A code_info_row_S1 « Row_S1 ; A* compute number of bytes to read from fi le */ bytes_to_read « SPR0C_C0DE_SDATA * CHARS_IN_LINE; /* read the program f i le into the buffer *A injbuf « read_fi lβ(in_buf. bytes_to_rβad, code_fi lβ. &in_buf_len) ; /* aake sure fi le is big enough here (at least 6 values) */ if (in_buf_len < 6 * CHARS_IN_LINE) £ printf ("\nERR0R — L00004: Program fi le (Xs) too small!", Code_fi lejiame) ; exit(-l ) ; 3 /* build output S-Rβcords from this input buffer */ aake_records(in_buf , in_buf_lβn) ; lastjsodejiddr = Sproc_addrβss; /* - « / A* begin spd fi le handling *A /* A /* */ A* begin control records */ /* V /* Control register memory aap starts here, but... see below */ /* Sproc_address « 0x400; */ /* */ /* The strategy here is to read the entire 1K of control space. */ /* However, 400h thru 40fh are address activated registers and */ /* must NOT be part of a load. Only 41Oh thru 4ffh are really */ /* used. We read the entire 1k to move the input file pointer, */ /* but we only use the fOh sdata items which are decoded by SPROC. */ /* */ bytes_to_read = SPROC_CONTROL_SDATA * CHARS_IN_LINE; /* read the file into the buffer */ in_buf = read fi le(in_buf, bytes_toj-βad, data_fi le. &in_buf_len) ; /" make sure file is big enough here */ if (in_buf_len < bytes toj-ead) { printf("\nERROR -- LOD005: Data file (Xs) too small!", Data_fi lejiame); exit(-1); 3 /* start with in_buf, but keep to use with free() */ work str = injsuf; /* We must just ignore the next 2 * 8 lines */ /* since we don't want to hit these addresses in the download */ for (recs = 1; recs <= C0NTR0L_START_ADDRESS - C0NTR0L_BASE_ADDRESS; recs++) { advance tojiext(Sworkjstr); } /* end of recs loop */ /* Control register memory map that is used by download starts here */ Sproc_address = CONTROL_START_ADDRESS; control info OW SMI = Row 3MI ; Row 3MI++; /* leave space for block size and start address */ 3 /* remember where to put block size and start address */ controMnfoj-ow_S1 = Row_S1 ; /* Process the 410 - 4ff as data records */ /* 500h - 410h = F0 */ make_records(work_ptr, (CONTROL .ENGTH + 2) * CHARS_IN_LINE) ; last_control_addr = Sproc_address; 'ifdef old_way if (make_records(work_ptr, C0NTR0LJ.ENGTH « CHARS_IN_LINE)) { printf("\nERROR -- LODOOB: Out of data in .spd file!\n\a"); exit(-3); 3 'endif free(in_buf) ; / / /* begin data space handling */ /* */ bytes_to_read = SPROC_DATA_SDATA « CHARS_IN_LINE; D' £ SUBSTITUTE SHEET /* read the fi le into the buffer */ in_buf = read_fi le(iπ_buf. bytes_to_read, data_f i le. 8.in_buf_len) ; /* make sure f i le is big enough here */ if (in_buf_lβn < 1 * CHARS_IN_LINE) { printf ("\nERROR — LOD007: Data fi le (Xs) too small!", Data_fi lejiame) ; exit(-T) ; 3 /* start with in_buf, but keep to use with free() */ workjstr =■ in_buf; /* We must just ignore the next 20 values */ /* since we don't want to hit these trigger addresses in the download */ for (recs «= 1; recs <= 20; rβcs++) £ advance_to_next(&work_ptr); } /* end of recs loop */ /* remove skipped records from buffer length */ in_buf_len -= 20 « CHARS_IN_LINE; /* Data RAM starts here «/ /* -A Sproc_addresε •= DATA_START_ADDRESS; data_info_row_SMI >- Row_SMI; Row_SMI++; /* leave space for block size and start address 3 /* remember where to put block size and start address */ data_info_row_s1 = Row Sl ; /* go and aake the data portion */ make_records(work_ptr, in_buf_len) ; lastjdatajsddr •. Sproc_address; free(ιn_buf) ; 7* all input files processed; /* do final cleanup */ /* fi ll in size and address info for SMI fi le */ Bakβjroa_headβr(Out_buf_SHI[code_info_row_SMI], last sodejaddr - CODE_START_ADDRESS, CODE_START_ADDRESS, FALSE) ; aake_roB_header(Out_buf_jSMI[contro t_ι nfo_row_SMI] , lastjsontrol_addr - C0NTR0L_START_ADDRESS, CONTR0L_START_ADDRESS. FALSE); make_rom_header (Out_buf_SMI[data_i nf ojrowjSHI] . last_data_addr - DATA_START_ΛDDRESS. DATΛ_STΛRT_ΛDDRESS, FALSE) ; /* also aake an assemb ly format end record */ aakβ_roa_header(record, 0, 0. TRUE) ; J?-7 strcat(Out_buf_SMI[Row_SMI++], record); 3 if (Mode == B00T_R0M) { /* */ /* place blocking info for boot mode into output buffer */ / */ correct_blocking info(lastj3θde_addr - C0DE_START \DDRESS - 2, code_info_row_S1, C0DE_START_ADDRESS); correct_blocking info( lastjsontrol ddr - C0NTR0L_START_ADDRESS - 2, contro l_i nfo_row_S1. C0NTR0L_START_ADDRESS) ; correctJ3locking info( lastjdatajsddr - DATAj3TART \DDRESS - 2, data i nf o_row_S1 , DATA_START_ADDRESS) ; / */ /• place ending block in output buffer */ /* */ /* Create record indicating zero size (no address needed) */ /" The record length (07) is known; use zz as placeholder for chksum */ sprintf(record, "S107X04Xxxxxxxxxyyyyyyyyzz\n", PROMjiddress); /* sprintf(record, "S1071234xxxxxxxxyyyyyyyyzz\n", PROMjiddress); */ /* char counting» 0123456789abcdef */ street(0ut_buf T>1[Row ϋl], record); /* use 0 as length and 0 as address so as not to confuse checksum */ correct_blocking_info(0. RowjSI, 0); /* remove the extra address - final block is just len */ /* copy the cksum and null and newline */ strncpy(&0ut_buf_S1[Row_S1][16], &Out_buf_S1[Row_S1][24], 4); Row_S1++; /* for completeness */ } /* end of Boot_R0M */ /* place end record in output buffer, leave for Extra files too "/ strcpy(record, "S9030000FC\n"); strcat(Out_buf_S1[Row ?1++], record); /* copy output buffer to output f i le */ wri te_buf s_to f i le( ) ; /* no need to display this information */ /* >» printf ("\nCode size « Xd, Data size = Xd", last_code_addr, last_data_addr - DATA_START_ADDRESS) ; <« */ /* close fi les */ efclose(Out_f i le_S1 , Outjf i te_S1 jiame) ; βfclosβ(Out fi lβ_SMI, Out fi le_SMIjιamβ) ; efclose(code_f i le, Code_f i lejiame) ; efclose(datajfi le, Data_f i lejiame) ; if (Makβjsxtra fi les) £ SUBSTITUTE SHEET /* add eof record (depends on S1 βof set up previously) */ βfprintf (Codβjsut_f le, record) ; βfprintf (ControljDUt_fi le. record) ; βfprintf (Datajsut_fi le, record) ; βf c lose(Codej-ut_f i le, outjsode_f i lejiame) ; efclosβ(Controljaut_fi le. outjsontrol_fi lejiame) ; βfc los6(Data_out_f i le, outjdata_f i lejiame) ; /* tell user */ if (IQuiet aode) £ printf(»\nFιnished with 'Xs'", 0ut_file_S1 jiame) ; printf (" and "Xs'", Out_f i le_SHI_name) ; if (Hake_extra_f i les) printf (" and extra fi les") ; printf (".") ; return(O) ; } /* end of main */ void correct_blocking_info (int len, int buf_row, int start_address) £ Hβfinβ CKSUH_BYTES (2 + 4 + (8 * 8)) /* length A A * * */ /* address A A A « /* values per line * * */ '* characters per value A *7 int cksum_bytes; shar tβmp_str[100], cksumjstr[3J; /* add back the two "va lues" which are the len and addr blocking info */ cksum_bytes = (len >= 8 - 2) ? CKSUM_BYTES : 2 + 4 + ((len + 2) * 8) ; A* create the blocking information *A Bake_blkj5tr(tenp str, len, start_addrβss) ; /* overlay padded values with the blocking information *A strncpy(S0ut_buf_S1 [buf_row][8], temp str, strlen(temp str)) ; /* create temporary string containing everything but checksum */ strncpy(teap_str . SOutJbuf _S1 [buf_row] [2] . cksum_bytes) ; temp str[cksua_bytes] * * \0'; /* compute checksua on this string and insert into buffer */ create shecksua(cksua_str, tempjstr) ; strncpy(&0ut_buf_Sl[buf_row][2+cksum_bytes], cksum str, 2) ; } A* end of corrβct_blocking_info *A '* convert lower nibble of passed character to hex char jnsigned char nibble2hexchar(unsigned char data_byte) jnsigned char ret ch; D-? if (data_byte > 9) rβt_ch » (unsigned char) {'A' + datajsytβ - 10); else rβt j sh = (unsigned char) ('0' + data_byte); return (rβtjsh); ) /* end of nibble2hexchar */ '* convert byte into 2 ascii hex digits */ /oid byte∑ascii(unsigned char *str, unsigned char data_byte) insigned char tmpjsh; t pjsh = (unsigned char)((data_byte & OxFO) » 4); *str = nibble2hexchar(tmpjsh); str++; tmpjsh = (unsigned char)(data_byte & OxOF) ; *str = nibble2hexchar( tmpjsh) ; } /* end of byte2asci i */ 'ifdβf padjsode /oid bui ld_jmp(char *pad_data, int address, unsigned char offset) jnsigned long instruct, mode; jnsigned char "str = pad_data; instruct = JMP_OP; instruct = instruct « 0P_SHIFT; mode = IMMED_R_MODE ; mode « mode « MODE_SHIFT ; instruct * instruct + mode + address + offset; /* convert to ascii */ byte2ascii(str, (unsigned char) ((instruct & OxOOFFOOOO) » 16) ); str += 2; byte2ascii(str, (unsigned char) ((instruct & OxOOOOFFOO) » 8) ); str += 2; byte2asci i (str , (unsigned char) (instruct & OxOOOOOOFF) ) ; > /* end of bui Id jmp */ 'βndif •oid correct_length(char * line_S1 , int num_va lues) ihar lenjstr[3] ; insigned char len; /* point to length byte of record */ line_S1 += 2; /* compute corrected length */ len = (unsigned char) (1 + 2 + (numj alues * 4) ) ; /* | i " i */ /* I I +--- data bytes */ /* | + address bytes */ /* + length byte » / /* stuff the chars representing actua l length into this S-record */ byte2ascii ( lenjstr, len) ; strncpy( line_S1 , lenjstr, 2) ; f>/ SUBSTITUTE SHEET 23^ } /* end of corrβct_lβngth */ A* convert string to upper case *7 void str2upr(char *str) C shar *p * str; whi le (*p != '\0') £ if (is lower (*p)) *p = (char) toupper(*p) ; p++; 3 ) /* end of str∑upr *A '* return TRUE if out of data (also set Sproc address to last value read) */ 300LEAN aakβ_a_record(char **ιn_buf_ptr, char * βndjstr) shar li nβ_S1 [COL_SIZE_S1 ] ; shar linβ_SMr[COL_SIZE_SMI] ; int sdata sount; char chβeksum_str[4] ; shar record[7], tβmp_record[12J; shar pad_data[7]; 300LEAN eπd_of_fi le = FALSE; 300LEAN all_zero alues « TRUE; 300LEAN first -r TRUE; /* initialize locals */ strcpy(pad_data, "000000") ; strcpy(lϊπβ_SMI, ""); /* fi ll in header info for this Line *7 crβatβ_hβader( li ne_S1 ) ; /* create a line *A for (sdatajsount = 1; sdata j sount <= SDATA_PER_SREC; sdata_count++) £ A* pad line out with zeros if past end of file */ /* must catch = condition to not put junk into records *A if (*in_buf_ptr >=- βndjptr) £ eπd_of_file = TRUE; A* do no padding for boot roms or SMI fi le */ if (Mode •» B00T_R0H 1 1 Makβ_SHI_f i le) £ A* fixup length for this record */ correct_lβngth(line_Sl. sdatajsount - 1); break; 3 strcpy (record, padjdata); 3 else { A* read in one 24 bit word per line as 6 ASCII chars *A βeacpy(record. *in_buf_ptr, CHARS_INJSDATA) ; rβcord[CHARS_IN_SDATAJ = '\0' ; str2upr(record) ; if (strcmp(record, "000000") 1= 0) // all ∑ero alues = FALSE; advance tojιext(in_buf_ptr); /* append to current record */ street ( line 31 , record); /* if needed, follow each sproc word (24 bits) with fill byte for splitting */ if (Mode == B00T_R0M) add_f i I l_byte( line_S1 ) ; /* place commas between values except for last */ if (first) £ sprintf(tempj-ecord, "OxXs", record); first = FALSE; 3 else sprintf(tempj-βcord, ", OxXs", record); /* first put in the value */ strcat(line_SMI, tβmpj-ecord); /* pad this 24 bit value */ add_fi Il_byte(linβ_SMI); 3 3 /* end of constructing line */ /* one value per item for count-1 items */ Sproc_address += sdatajsount - 1 ; /* increment Sprocjddress for next record */ if (Mode = B00T_R0M) { /* four bytes per item for count-1 items */ PROM sddress += 4 * (sdata j sount - 1); 3 /* don't output this line if all zeros and zero surpression on */ if ( (Zβrojsurpress && lall ∑ero /alues) || (IZero surpress) ) { /* add checksum to record */ creatβjshecksum(checksumjstr, line_S1+2) ; strcat(line_S1, checksum jstr); /* line complete, terminate and place in output buffer, bump Row */ strcat(line_S1. "\n"); strcpy(Out_buf 31[Row 31++], linβ_S1); /* also write to appropriate extra output file, if needed */ if (MekejMCtra_f i les) { if (Sproc_addrβss < 0x400) efprintf(Codejsut_file, "Xs", line_S1); else if (Sproc_address < 0x800) efprintf(Control_out_file, "Xs", line_S1); else 0-1^ SUBSTITUTE SHEET efprintf(Data_out_fi lβ, "Xs". linβ_S1) ; } A* end of not all_zβro_values *A /* do the same for SMI buffer, if needed *A /* need comma at end of line of values */ strcat( linβ_SMI, ",\n") ; strcpy(Out_buf_SMI[Row_SMI++] . linβJSMI) ; 3 return(βndjjf_f i le) ; 1 /* end of nakej- record */ ** return TRUE if out of data (also set Sproe_address to last value read) */ lOOLEAN aake_records(char *in_buf_ptr. int in_buf_len) :har "βnd str; lOOLEAN end_of_fi le = TRUE; βndjstr = ϊn_buf_ptr + iπ_buf_len; /* process entire fi le */ whi le (in_buf_ptr < endjstr) £ βnd_of_ff lβ « makβ_a record(S.in_buf_ptr, endj tr) ; /* always run the SPROC address value to calculate block size */ /* the following is Now done in make_a_record */ /* Sproc_address += SDATA_PER_SREC; *A A* let user know things are progressing *7 show_progress() ; } /* end of whi le */ return(endjsf_file)j • /* end of aake_records */ oid applyj_efault_extension(char "fname. char *ext) /* don't overwrite existing extension, if any */ if (strchrffname. * .') «» NULL) £ strcat(fname, »."); strcat(fname, ext); 3 - /* end of apply_defau lt_extension */ •har chβck_fi les{) :har answer; A* stay in this loop uπti I proper answer */ do £ printf ("\nUsing "Xs'". Code_fi lejiame) ; printf (" & *Xs' ". Data_f lejiame) ; prι * ntf("to produce ' s' [Y/N] ? [Y] >'. P-/3 /* answer « (char) getchβ();*/ answer = (char) getchar(); if (answer == '\r') answer = 'Y' ; else answer = (char) toupper(answer); 3 while (answer != 'Y' && answer != 'N'); return(answer); } /* end of check_fi les */ int show_usage_and_exit() £ /* HELP message */ printf ("\nConverts Schedule output files (.spp and .spd) to a load file (for SDI)."); printf ("\n Can also produce boot PROM ile or SMI file."); printf ("\n"); printf ("\n Usage: MakeLoad fi lebase [-E] [-H] [-Q] [-S] [-Z] where"); printf ("\n fi Lebase is the design name"); printf ("\n E ■ produce Extra files = off"); printf ("\n p = produce Prom file (.pro instead of .lod)"); printf ("\n Q = Quiet mode = off"); printf ("\n S = produce SMI file (.blk in addition to .lod)"); printf ("\n Z » surpress records of all zeros"); printf ("\n"); printf ("\n Default extensions are:"); printf ("\n .spp = SPROC program file "); printf (" .spd = SPROC data file "); printf (»\n .lod = load file output (for SDI) "); printf (" .blk « SMI file output "); printf ("\n .pro = boot PROM file output "); printf ("\n"); printf ("\n When the 'E' switch is used, three additional files are produced."); printf ("\n These file basβnames are 'code', 'control' and 'data' n"); exit(-5); return(O); } /* end of show_usage_and_exit */ void display_banner(char "version) £ / « identify se lf */ printf ("Load fi le bui lder, Xs", version) ; printf("\n Copyright (C) 1991 by STAR Semiconductor Corporation, a l l rights reserved. ") ; 3 int set_extra fi les(char *str) £ char ignore » "str; Make_βxtra_fi les β TRUE; return(O); Z - / SUBSTITUTE SHEET int set juiβt(char *str) E shar ignore = *str; Quiet gode = TRUE; rβturn(O) ; } int set_ le_names(char *str) :har ignore = *str; /* establish input fi le names */ /- *7 strcpy(Code_f lejiame, str) ; strcpy (Data_fi lejiame. str) ; strcpy(Dβsign_name, str) ; /* establish output fi le base names */ strcpy(0ut_fi le_S1_name. str) ; strcpy(0ut_f i le_SMI_name, str) ; rβturn(O) ; /* to satisfy do switches "7 r A* end of set_f i le iames *A πt set_Boot_ROM_aodβ(char *str) :har ignore = "str; if (Makβ_SMI_file [| Zero surpress) £ printf("\nERR0R — LOD008: PROU not allowed with SHI or zero surpression."); exit(-1); 3 Mode = B0OT_R0H; return(O); A* end of set_Boot_R0HjBode */ nt make_SHI_file(char *str) har ignore = *str; if (Mode «= B00T_R0M) £ printf("\nERR0R — LOD009: SMI switch not allowed with PROM switch."); exit(-l); 3 return(O); /* end of aake_SMI_file *A nt set_zero surpression(char *str) har ignore » *str; A* disallow option f Baking proms */ if (Mode «= BOOTJUJM) £ printf("\nERR0R -- LODOIO: Zero surpression not allowed with PROM.") ; exit(-l ) ; 3 /* change to surpressing records of all zeros */ Zerojsurpress « TRUE; return(O); /" to satisfy dojswitches */ } /* end of set_filejiames */ ff char *emalloc(int size) £ char *ptr; * * if ((ptr = malloc(size)) == NULL) return(ptr); } /* end of e alloc */ int βfread(char *ptr. unsigned size, unsigned count, FILE "data ile) £ int status; status = fread(ptr, size, count, data_file); if (status < 0) return(status); } /* end of efread */ int create_header(char *hptr) £ /* write preamble = type, length and address */ switch (Mode) { case B00T_R0M : /* a l low for 8 fi l l bytes */ retj a l = (int)sprintf(hptr , "S123X04X", PROM_address) ; break; case S1_FILE : defau lt /* length is always 1B (not 18) , includes cksum and addr bytes */ ret_val = (int)sprintf (hptr , "S11BX04X", Sproc_address) ; break; 3 return(ret zal) ; 3 /* end of create ieader */ unsigned char aschex2char(char * highjsyte) £ int i ; unsigned char c, val = (unsigned char) 0; /* convert 2 successive ascii bytes into a hex value */ " for (i=1; i<=2; i++) { val = (unsigned char) (((unsigned int)val) « 4) ; c = (unsigned char) toupper(*high_byte); ^ if (c < 'A') val += c - '0'; else val += c - 'A' + 10; />/ SUBSTITUTE SHEET 2^0 returπ(val); } /* end of aschex2char *A /oid createjshecksum(char *eptr, char *buf) r shar *p; jnsigned int checksua = 0; A* add chars to checksum as unsigned int */ for (p=buf; *p != '\0'; p += 2) £ checksum += (unsigned int) aschex2char(p); 3 /* checksum is 1's compliment of actual sum "A checksum = (unsigned char) (OxFF - checksum); A* " fill in return string *A sprintf(cptr, "X02X", checksum); \ A* end of create j shecksu */ /oid show_progress(void) :har workingjshar; if {Quiet_aode) return; /* let user know what's happening *A switch (Mode) £. case B00T_R0M : workingjshar = 'p*; break; default : workingjshar = '+'; break; 3 printf ("Xc". workingjshar) ; A* end of showjsrogress *A oid ιnit_output_buffers() nt i; for (1=0; ι < R0W_SIZE; f++) £ aemset(Out_bufjST[i]. '\0', C0L_SIZE_S1); Bβaset(Out_bufJSMiril. '\0'. COL_SIZE_SMI); 3 A* end of init_output_buffβrs *A oid writβ_bufs_to_filβ() nt i; /* open these output fi les now. since we're gonna put data in 'em */ 0ut_fi lβ_S1 « βfopen(Out_fi le_Sljιame, "w") ; if (Make_SMI_file) Out_fi lβ 3HI « βf open (Out_fi lβ_SMr jiame. "w") ; if (IQuietj ode) pri ntf ("\nWri ting output ..."); ' ϊ 7 for (i=0; i<Row_S1; i++) £ efprintf(0ut_file 3l, "Xs", 0ut_buf_S1[i]); 3 /* if needed, write SMI data to file */ ;.* if (Make_SMI_f i le) ( for (i=0; i<Row_SMI; i++) £ βfprintf (Out_file_SMI, "Xs", Outjsuf 3MI[i ]) ; 3 λt 3 3 /* end of writβ_bufs_to ?i le */ /* move on to next value in buffer */ /* allow for space padding from scompile (normally 4 spaces) */ /* shouldn't have to skip CR since CR-LF pair translated to just LF by MSC */ void advance tojιext(char ** workjstr) £ •workjstr += CHARS_IN_SDATA; while ("workjstr == ' ' || "workjjtr == '\n' || "workjstr == '\r') (*work_ptr)++; 3 /* end of advancβ_to_next */ /* format a boot block description as text "/ void makβ_blkjstr(char "buf, int size, int addr) £ long long size, longjddr; long sizβ = (( long)(size)) « 8; longjiddr = (( long) (addr)) « 8; if (Mode == B00T_R0M) /* note that "LX" as a format is buggy! (gives 0 as result) */ /* Use IX for long capital hex values "/ sprintf(buf, "X08IXX08IX", long j size, long j iddr); else sprintf(buf, "OxXOβlX, OxXOβlX", longjsize, longjiddr); 3 /• end if make_blk_str */ void make_romjieader(char "buf, int size, int addr, BOOLEAN last_f lag) £ char last_line[80]; make_blk_str(buf , size, addr); /* append trailing comma to all but last record */ if (last_flag) { sprintf (last_line. " } ;\nfix24 type bβforβjsonst Xs_blockjιnd afterjsonst = { OxOOBADBAD } ;", Designjiame); strcat(buf. last line); 3 else strcat(buf, ","); * strcat(buf, "\n"); show_progress(); ) /* end of make -om ieader */ D-/<? SUBSTITUTE SHEET /oid add_fi ll_bytβ (char "record) £ strcat(rβcord, "00"); ) A* end of add_fitI j sytβ *A /oid crβatβ_output_extensϊon(char "βxtjstr) r switch (Mode) £ case B0OT_R0H : strcpy(ext_str. "pro"); break; default : strcpy(ext j str. "lod"); break; 3 } A* end of createjsutputjixtension *A shar * read_fi le(char * in_buf , int byteε_to_read, FILE *f i le, int * len) r shar * temp_in_buf ; shar place_holder[] = "000000 \n000000 \n"; A* aake the buffer 2 values larger for PROM format */ if (Mode m B0OTJR0M) £ /« get a buffer and fi ll it with data */ injsuf » emalloc(bytes_to_rβad + sizeof(p lace_holder) ) ; /* Bake these records look like "normal" records */ strncpy(ιn_buf, place-ho lder, sizeof(p lace_holder) - 1 ) ; /* aake it appear that these "records" came from f i le */ temp_in_buf = injsuf; injsuf += sizeof (placeholder) - 1 ; •len « efrβad(in_buf. 1 , bytes tojrβad. fi le) ; injsuf temp_in_buf ; *len += sizeof(place ioLder) - 1 ; 3 else C /* get a buffer and fi LI it with data */ injsuf -r emal loc(bytes_to_read+1 ) ; •len = efread(fnjsuf, 1. bytes_to_read, fi le) ; 3 return(in juf ) ; ) /* end of rβad ? i le */ b-/9 /* SLog: efopencl.cv $ « Revision 1.1 1991/07/10 00:05:32 krassow * Initial revision * */ #i nclude <stdio.h> #i nclude <stdlib.h> char efopencl[] = "Sid: efopencl.cv 1.1 1991/07/10 00:05:32 krassow Exp $"; /* fatal error file open */ FILE *efopen(char "path, char *type) £ if ((ret_file = fopen(path, type)) == NULL) £ fprintf(stderr, "\nERR0R -- EF0001: Can't open file 'Xs'.", path); exit(-2); 3 rβturn(ret i le); } /* end of efopen */ /* fatal error file close */ int efclose(FILE *filejstr, char *fi lejiame) £ /* if file pointer is null, don't bother closing */ if (file_ptr != NULL) { if {(ret_val = fclose(fi le_ptr)) != 0) { fprintf(stderr, "\nERR0R -- EF0002: Problem closing file 'Xs'.", fi lejiame); exit(-3); 3 3 else ret_val = 0; return(retjzal); /* end of ef close */ D AO SUBSTITUTE SHEET A* Local definitions *7 /* */ /* 3(#)sdl2load.h 1.11 -/ /* generic defines *A iCdβfine CHARS_IN_SDATΛ B A* define input fi le characteristics *A #defιne CHARS_IN_LINE (CHARSjINJSDATA + 4 + 1) A* include spaces and line feed */ A* define SPROC memory characteristics */ #definβ SPROC_CODE_S0ATA 1024 #define SPR0C_C0NTR0L_SDATA 1024 A* absolute worst case! "A #definβ SPROC_DATA_SDATA 1024 #definβ SPR0C_TOTAL_SDATA (SPROCjSODEjSDATA + SPROCJCONTROLJSDATA +SPR0C_DATAj3DATA) /* define byte counts */ fdefinβ SPR0C_CODE_CHARS (SPR0C_C0DE_SDATA * CHARS_INj3DATA) #define SPROC_CONTR0L_CHARS (SPR0C_C0NTR0L_SDATA * CHARS_IKjSDATA) #defιne SPROC_DATA_CHARS (SPROC 3ATAJ3DATA * CHARS_IN_SDATA) #definβ SPROC OTALJCHARS (SPROC_TOTAL_SDATA * CHARS_IN_SDATA) #define SREC_0H (2+2+4+2) /* A A A A */ /* si + I f I *A A* len + j j *A A* address + j *A A* checksum + "A #definβ SDATAj>ER_SREC 8 #dβfine FILE NAME LENGTH 60 #define ESC 0x1b char B0LDstr[5] = £ (char) ESC. '['. '1', 'm', '\0 * J char N0RHstr[5] = { (char) ESC, '[', '0', 'm', '\0* APPENDIX SUBSTITUTE SHEET /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/brea]ram.sdl,v 1.7 1991/10 * $Revision: 1.7 $ * $Id: brea ram.sdl,v 1.7 1991/10/0121:23:54 chet Exp $ * $Log: breakram.sdl, $ # Revision 1.7 1991/10/01 21:23:54 chet # Added Revision Keyword # # Revision 1.6 1991/08/30 16:40:30 krassow # Changed from A register to L register to preserve flags on recovery # # Revision 1.5 1991/08/29 19:51:39 krassow # Use indirect addressing mode for Ida (no #) . # # Revision 1.4 1991/08/28 19:09:38 krassow # Changed a NOP to restore A reg from ram copy. # Note that ram copy must be hard-coded since its creation is not symbolic. # Changed duration from 100 to 6 as more correct. # # Revision 1.3 1991/08/08 15:54:25 krassow # Changed labels in breakram to lower case, # # Revision 1.2 1991/07/30 14:18:54 chet # New template submission # # */ /************************************************************************* breakram.sdl ************************************************************************** Function: This code supports idling of GSPs for a break function, and provides a place for patch code executed after the WAIT_FLAG becomes non-zero. Arguments: none Parameters: none Algorithm: V /*******************/ /* inline code */ /*******************/ -/ #define WAIT_FLAG OBFFh #define NU _REGS Oeh fdefine _REG_1 Obcah Ifdefine L_REG_2 (L_REG_1 + NUM_REGS) jfdefine L_REG_3 (L_REG_2 + NUM_REGS) ffdefine L_REG_4 (L_REG_3 + NUM_REGS) asmblock breakram() iuration 6; phantom; init; oegin // four identical fragments, 1 for each gsp // // // GSPls fragment // _%patch_ram_gspl: ldl WAIT_FLAG // wait here until SDI fixes Vectors jlf _%patch_ram_gspl ldf L_REG_1 // restore ram copy of A register nop nop nop // just jump to beginning, will be patched jmp _%patch_ram_gspl // with original instruction // // GSP2's fragment // %patch_ram_gsp2: ldl AIT_FLAG // wait here until SDI fixes Vectors jlf _%patch_ram_gsp2 ldl L_REG_2 // restore ram copy of A register nop nop nop jmp _%patch_ram_gsp2 // // GSP3 's fragment // _%patch_ram_gsp3: ldl WAIT_FLAG // wait here until SDI fixes Vectors jlf _%patch_ram_gsp3 ldl L_REG_3 // restore ram copy of A register nop nop nop jmp _%patch_ram_gsp3 // // GSP4 's fragment // _%patch_ram_gsp4: ldl AIT_FLAG // wait here until SDI fixes Vectors jlf _%patch_ram_gsp4 ldl L_REG_4 // restore ram copy of A register nop nop jmp _%patch_ram_gsp4 SUBSTITUTE SHEET 2J+8 and £-3 /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/vectors.sdl,v 1.5 1991/10/ * $Revision: 1.5 $ * $Id: vectors.sdl,v 1.5 1991/10/02 12:56:16 krassow Exp $ * $Log: vectors.sdl,v $ ¥ Revision 1.5 1991/10/02 12:56:16 krassow Added Revision tag. * ϊ Revision 1.4 1991/09/03 14:40:42 krassow I from TM checked in by AJK * ϊ Revision 1.3 1991/07/31 14:42:58 chet New template submission ¥ If 1.51 7/24/91 V // still under Terry's source code control // % % %G% /************************************************************************* vectors.sdl ************************************************************************** Function: This block contains SPROC restart vectors. It is incorporated into every system build. arguments: N/A Parameters: N/A algorithm: N/A V /*******************/ /* inline code */ /*******************/ asmblock _vectors() phantom; init; begin jmp "top,_$start_gspl" jmp "top._$start_gsp2" jmp "top._$start_gsp3" jmp "top._$start_gsp4" £- 9 SUBSTITUTE SHEET 250 end £~ /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/io.sdf,v 1.6 1991/10/02 12 * $Revision: 1.6 $ * $Id: io.sdf,v 1.6 1991/10/02 12:56:09 krassow Exp $ * $Log: io.sdf,v $ If Revision 1.6 1991/10/02 12:56:09 krassow If Added Revision tag. If Revision 1.5 1991/09/19 21:52:41 krassow New port dest names. Removed generic init.sdl file. * Revision 1.4 1991/09/03 14:40:34 krassow j from TM checked in by AJK If If Revision 1.3 1991/07/31 14:40:50 chet fj New template submission, with function description ff H 1.51 7/24/91 V // still under Terry's source code control // % % %G% /************************************************************************* io.sdf ************************************************************************** Function: This file provides definitions for input and output, and is included during a system build. It is instantiated first as a mapping of wires onto the entire control space, and establishes symbolic references for all accesses. Control space and data space are viewed by the scheduler as one block of data RAM. This scheme thereby decouples system architectural features from the user so that the architecture may evolve with minimal impact upon the software structure. arguments: N/A Parameters: N/A algorithm: N/A V /*******************/ /* inline code */ /*******************/ ε-€ SUBSTITUTE SHEET // port definitions symbol clO = 20, ell = 21, cl2 = 22, cl3 = 23; symbol no_cl = -1, no_trigger = -1; // old style port definitions symbol portO = 0, portl = 1, port2 = 2, port3 = 3; // New (improved) port definitions symbol siportO = 0, siportl = 1, soportO = 2, soportl = 3; symbol pportO = 0, aportO = 0, probeO = 0; symbol genO = 4, genl = 5, gen2 = 6, gen3 = 7; symbol gen4 = 8, gen5 = 9, gen6 = 10, gen7 = 11; symbol gen8 = 12, gen9 = 13, genlO = 14, genii = 15; symbol genl2 = 16, genl3 = 17, genl4 = 18, genlδ = 19; // port configuration symbols symbol w24 = 0, wl6 = 1, wl2 = 2, w8 = 3; symbol lsb = 0, msb = 1; symbol short = 1, long = 0; symbol on = 1, off = 0, default = -1; symbol intern = 1, extern = 0; // masks for port and compute line triggers symbol port_0_mask =lh, port_l_mask =2h, port_2_mask =4h, port_3_mask = 8 symbol gen_0_mask =10h, gen_l_mask =2Oh, gen_2_mask =40h, gen_3_mask = 80 symbol gen_4_mask=100h, gen_5_mask=200h, gen_6_mask=400h, gen_7_mask =800 symbol gen_8_mask=1000h, gen_9_mask= 2000h symbol gen_10_mask=4000h,gen_ll_mask = 8000h; symbol gen_12_mask=10000h, gen_13_mask= 20000h; symbol gen_14_mask=40000h, gen_15_mask = 80000h; symbol compute_0_mask=100000h, compute_l_mask= 200000h; symbol compute_2_mask=400000h, compute_3_mask = 800000h; // values to be set for port clock registers symbol _%in_clk_val_0 = OFFh, _%in_clk_yal_l = OFFh, _%out_clk_val_0 = OFFh, _%out_clk_val_l = OFFh; // probe port configuration symbol _%probe_out_port_config_0 = 65h; // bit position for gpio output field (bit for gpio_0) in gpio_register symbol _%gpio_output__field = 16; // gpio and rts configuration symbols symbol gpio_0 = 0, gpio_l = 1, gpio_2 = 2, gpio_3 = 3; symbol rts_0 = 0, rts_l = 1, rts_2 = 2, rts_3 = 3; // I/O registers wire hex _%ram_configuration; // 0x400 wire _%reserved_l[5] ; aicro wire hex _%sproc_halt; // 0X406 micro wire hex _%sproc_exit_break; // 0x407 wire _%reserved_2[8] ; // 0X410 wire hex _%serial__in_port_int_clk_0; // 0x410 wire hex _%serial_in_port_int_clk_l; wire hex _%serial_out_port_int_clk_0; wire hex _%serial_out_port_int_clk_l; // 0x413 wire _%reserved_3[44] ; // 0x440 wire integer _%serial_in_port_buf_len_0; wire integer _%serial_in_port_fifo_ix_len_0 ΕL 7 wire hex _%serial_in_port_fifo_start_0; wire hex _%serial_in_port_config_0; wire hex _%serial_in_port_reserved_0[4] ; wire integer _%serial_in_port_buf_len_l; wire integer _%serial_in_port_fifo_ix_len_l; wire hex _%serial_in_port_fifo_start_l; wire hex _%serial_in_port_config_l; wire _%serial_in_port_reserved_l[4] ; // 0x4fb // 0x4fc // 0x4fd // 0x4fe (non-readable) // 0x4ff (non-readable) E'g SUBSTITUTE SHEET £-? /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/userdecl.sdl,v 1.4 1991/10 * $Revision: 1.4 $ * $Id: userdecl.sdl,v 1.4 1991/10/02 12:58:46 krassow Exp $ * $Log: userdecl.sdl,v $ # Revision 1.4 1991/10/02 12:58:46 krassow # Closed Log block comment. # # Revision 1.3 1991/10/02 12:56:14 krassow # Added Revision tag. # */ // // This file may contain user-supplied declarations which apply to all // blocks in a design. // // To use it, add any desired symbol declarations below, of the form: // symbol <symbol_name> = <symbol_value>; // // or add variable storage which is global to the design: // variable <variable_name>[<size>] ; // «< ' £. / O SUBSTITUTE SHEET /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/initcl6.sdl,v 1.2 1991/10/ * $Revision: 1.2 $ * $Id: initcl6.sdl,v 1.2 1991/10/02 12:56:04 krassow Exp $ * $Log: initcl6.sdl,v $ # Revision 1.2 1991/10/02 12:56:04 krassow # Added Revision tag. # # Revision 1.1 1991/09/19 21:42:01 krassow # Initial revision # # Revision 1.4 1991/09/03 14:40:29 krassow # from TM checked in by AJK # # Revision 1.3 1991/07/31 14:42:24 chet # New template submission, with function description # # 1.51 7/24/91 */ // still under Terry's source code control // %W% %G% /************************************************************************* initcl6.sdl ************************************************************************** Function: This code constitutes a true top level block. It defines initial parameters and a framework into which a user's design is instantiated. I/O definitions, SPROC restart vectors, core support functions and a break facility are established via include files. Arguments: N/A Parameters: N/A Algorithm: N/A */ /*******************/ /* inline code */ /*******************/ segblock _top() £'// // SPROC configuration symbols symbol _%sproc_model = "CHIP 1400-1C"; symbol _%n_gsps = 4, _%flag_locs = 24; symbol _%code_space_start = 0; symbol _%io_space_start = 1024, _%data_space_start 2048; symbol _%io_space_size = 1024; symbol _%patch_ram_size = 59; 1. ( symbol _%code_space_size = 1024 symbol _%data_space_size = 1024 _%patch_ram_size - _%flag_locs; symbol _%first_serial_port = 0, %last_serial_port = 3; symbol _%first_in_port = 0, _%n_in_ports = 2; symbol _%first_out__port = 2, _%n_out_ports = 2; symbol _%first_compute_line = 20, _%last_compute_line = 23; // master clock setup #define MC_FREQ 16 symbol _%mc_freq_max = 16; symbol _%mc_freg = MC_FREQ; verify ( MC_FREQ > 0 && MC_FREQ <= _%mc_freg_max) , 'MC FREQ must be > 0 and <= 16 MHz. ! ; symbol _%chip_gsp_rate = (MC_FREQ * 1000000) / 5; symbol _%init_version = "$Id: initcl6.sdl,v 1.2 1991/10/02 12:56:04 kra symbol _%abs_addr_fudge = 0; symbol pi = 3.141592653; #include "io.sdf" #include "userdecl.sdl" begin _vectors _restart() ; _user_top top() ; _user_end user_end() ; breakram break() ; end // mask out bit 23 #define IMMED_MASK 3fffh #include "vectors.sdl" #include "phantoms.sdl" £ Λ- SUBSTITUTE SHEET 253 /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/initd20.sdl, 1.2 1991/10/ * $Revision: 1.2 $ * $Id: initd20.sdl,v 1.2 1991/10/02 12:56:07 krassow Exp $ * $Log: initd20.εdl,v $ # Revision 1.2 1991/10/02 12:56:07 krassow # Added Revision tag. # # Revision 1.1 1991/09/19 21:42:04 krassow # Initial revision # # Revision 1.4 1991/09/03 14:40:29 krassow # from TM checked in by AJK # # Revision 1.3 1991/07/31 14:42:24 chet # New template submission, with function description Λ ιr # 1.51 7/24/91 V // still under Terry's source code control // %W% %G% /************************************************************************* initd20.sdl ************************************************************************** Function: This code constitutes a true top level block. It defines initial parameters and a framework into which a user's design is instantiated. I/O definitions, SPROC restart vectors, core support functions and a break facility are established via include files. Arguments: N/A Parameters: N/A Algorithm: N/A */ /*******************/ /* inline code */ /*******************/ segblock _top() phantom; > /3 // SPROC configuration symbols symbol _%sproc_model = "CHIP 1400-2D"; symbol _%n_gsps = 4, _%flag_locs = 24; symbol _%code_space_start = 0; symbol _%io_space_start = 1024, _%data_space_start = 2048; symbol _%io_space_size = 1024; symbol _%patch_ram_size = 59; t ♦ symbol _%code_space_size = 1024; symbol _%data_space_size = 1024 - _%P a tch_ram_size _ _%fiag_locs; symbol _%first_serial_port = 0, _%last_serial_port = 3; symbol _%first_in_port = 0, _%n_in_ports = 2; symbol _%first_out_port = 2, _%n_out_ports = 2; symbol _%first_compute_line = 20, _%last_compute_line = 23; // master clock setup #define MC_FREQ 20 symbol _%mc_freg_max = 20; symbol _%mc_freq = MC_FREQ; verify ( MC_FREQ > 0 && MC_FREQ <= _%mc_freg_max) , 'MC FREQ must be > 0 and <= 20 MHz. ' ; symbol _%chip_gsp_rate = (MC_FREQ * 1000000) / 5; symbol _%init_version = "$Id: initd20.sdl,v 1.2 1991/10/02 12:56:07 kra symbol _%abs_addr_fudge = 0; symbol pi = 3.141592653; #include "io.sdf" #include "userdecl.sdl" begin _vectors _restart() ; _user_top top() ; _user_end user_end() breakram break() ; end // mask out bit 23 #define IMMED MASK 3fffh #include "vectors.sdl" #include "phantoms.sdl" -/ SUBSTITUTE SHEET /* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/cells/code/phantoms.sdl,v 1.51991/10 * $Revision: 1.5 $ * $Id: phantoms.sdl, 1.5 1991/10/02 12:56:11 krassow Exp $ * $Log: phantoms.sdl,v $ # Revision 1.5 1991/10/02 12:56:11 krassow # Added Revision tag. # # Revision 1.4 1991/09/03 14:40:37 krassow # from TM checked in by AJK f # Revision 1.3 1991/07/31 14:43:36 chet # New template submission, with function description # # 1.51 7/24/91 */ // still under Terry's source code control // %W% %G% /************************************************************************* phantoms.sdl ************************************************************************** Function: This file supplies all of the blocks not specified in a user's design, but required to make the design work. The blocks implement temporal scheduling and operating system features. Arguments: N/A Parameters: N/A Algorithm: N/A */ /*******************/ /* inline code */ /*******************/ //////////////////////////////////////////////////////////////////////////////// // // _user_top // // Null block which gets replaced by real user top block. // //////////////////////////////////////////////////////////////////////////////// asmblock _user_top() phantom ; begin end //////////////////////////////////////////////////////////////////////////////// // // _turnstile // // This phantom block prevents two GSPs in a temporal partitioning scheme // from running into each other. It regulates access to a code segment // via a semaphore location. If that location is non-zero, it indicates // that the segment is in use, and that this GSP must wait. '/ //////////////////////////////////////////////////////////////////////////////// asmblock _turnstile( ;semaphore) phantom; duration 5; begin $1: LDA semaphore // wait until next segme JGT $1 LDA #1 STA semaphore // set next segm end V////////////////////////////////////////////////////////////////////////////// // // _wait_seg_flag // // Wait untol segment flag reached the desired value. '/ //////////////////////////////////////////////////////////////////////////////// asmblock _wait_seg_flag{value) (semaphore;) phantom; duration 5; begin $1: LDA semaphore // wait until next segme CMP ffvalue JGT $1 end //////////////////////////////////////////////////////////////////////////////// // // _free_seg // // This phantom block frees the segment that we just left. // The location for the current segment's semaphore is passed so that SUBSTITUTE SHEET '/ we can decrement it. We do a decrement f / rather than a clear to guarantee that the first segment of a '/ timezone will be run through by all GSPs before the first GSP which loops y back reenters it. '/ '////////////////////////////////////////////////////////////////////////////// ismblock _free_seg(semaphore;) phantom; begin LDA semaphore // decrement usage coun JEQ $1 SUB #1 STA semaphore 51: end '////////////////////////////////////////////////////////////////////////////// V '/ _wait_for_flags V Load the wait flags register with the given mask, then wait for wait flags V to be cleared. V i vsm//b/l/o/c/k/ _/w//a/i/t_//f/ o/r_//f/ l/a/g/s/ {w//a/i/t_/m//a/s/k/}/ (/)/////////////////////////////////////////// phantom; begin LDWS #wait_mask ?1: JWF $1 end '/////////////////////////////////////////////////////////////////////////////// V '/ _set_wait__mask V V Just load the wait flags register with the given mask. V V////////////////////////////////////////////////////////////////////////////// ismblock _set_wait_mask{wait_mask} () phantom; begin LDWS #wait_mask end '/////////////////////////////////////////////////////////////////////////////// V V _jump_t° V Jump to the given address. Used to loop back to start of code for a time zone. V '/////////////////////////////////////////////////////////////////////////////// ismblock _jump_to{loop_address} () phantom; begin JMP loop_address end V////////////////////////////////////////////////////////////////////////////// V LZ-/7 // _copy // // Copy a single word from the source to the destination location. +? // Used at the start of a segment to copy from output location to // output location buffer. // /////////////////////////////////////////////////////////////////////////////// t asmblock _copy(source; dest) phantom; begin LDA source STA dest end //////////////////////////////////////////////////////////////////////////////// // // _copy_address // // Copy the address of the source location to the destination location. // Used in init code to set up the fifo pointers. // //////////////////////////////////////////////////////////////////////////////// asmblock _copy_address{source_size=l) (source[source_size] , dest;) phantom; begin LDA #source STA dest end //////////////////////////////////////////////////////////////////////////////// // // _copy_constant // // Copy a constant to the destination location. // Used in init code to set up the gsp count for the Oth segment. // //////////////////////////////////////////////////////////////////////////////// asmblock _copy_constant{constant} (dest;) phantom; begin LDA #constant STA dest end //////////////////////////////////////////////////////////////////////////////// // // _get_sync_input // // Wait for wait flags to be cleared, then reload the wait flags register // with the given mask. // //////////////////////////////////////////////////////////////////////////////// asmblock _get_sync_input {wait_mask} (src_addr, dest_addr;) j phantom; begin LDWS #wait_mask $1: JWF $1 1 LDA src_addr STA dest addr end £V<f SUBSTITUTE SHEET //////////////////////////////////////////////////////////////////////////////// // // _loop_bottom // // Bottom of repeat loop for repeating decimated/interpolated segments. // //////////////////////////////////////////////////////////////////////////////// asmblock _loop_bottom{loop_address) (loop_counter;) phantom; duration 4; begin LDA loop_counter // decrement loop counter SUB #1 STA loop_counter JNE loop_address // go to top of loop if not zero end /////////////////////////////////////////////////////////////////////////////// // // _to_phant_array // // Copy a wire value to a phantom array for repeated // decimated/interpolated segments. // //////////////////////////////////////////////////////////////////////////////// asmblock _to_phant_array(array_ptr, wire_loc;) phantom; begin LDA wire_loc LDF array_ptr STA [F] LDA F ADD #1 STA array_ptr end /////////////////////////////////////////////////////////////////////////////// // // _fr_phant_array // // Copy a wire value from a phantom array for repeated // decimated/interpolated segments. // //////////////////////////////////////////////////////////////////////////////// asmblock _fr_phant_array(array_ptr, wire_loc;) phantom; begin LDF array_ptr LDA [F] STA wire_loc LDA F ADD #1 STA array_ptr end /////////////////////////////////////////////////////////////////////////////// // // _up_fr_ph_array // // Copy a wire value from a phantom array for repeated // decimated/interpolated segments, upsampling to the current timezone // rate. // //////////////////////////////////////////////////////////////////////////////// asmblock _up_fr_ph_array{up_fact) (array_ptr, wire_loc;) phantom; variable phase; begin LDF array_ptr LDA [F] STA wire loc // check phase to advanc // have we reached the u // if not, don't // advance and reset pha $1: end /////////////////////////////////////////////////////////////////////////////// // // _down_fr_ph_array // // Copy a wire value from a phantom array for repeated // decimated/interpolated segments, downsampling to the next time // zone rate (skip the appropriate number of samples) . // //////////////////////////////////////////////////////////////////////////////// asmblock _down_fr_ph_array{down_factor) (array_ptr, wire_loc;) phantom; begin LDF array_ptr LDA [F] // fetch next va STA wire_loc LDA F ADD #down_factor // advance array ptr the correct STA array_ptr end /////////////////////////////////////////////////////////////////////////////// // // _dupe_ph_array // // Copy contents of a phantom array. // //////////////////////////////////////////////////////////////////////////////// asmblock _dupe_ph_array{array_size} (from[array_size] , to[array_size] ;) phantom; duration 4+(3*array_size) ; begin LDB #from LDF #to LDL #array_size-l £-ώO SUBSTITUTE SHEET LDD #1 Jloop: LDA [B+L] STA [F+L] DJNE $loop end v////////////////////////////////////////////////////////////////////////////// V // _dummy 7 V////////////////////////////////////////////////////////////////////////////// ismblock _dummy{ } () phantom; begin end '/////////////////////////////////////////////////////////////////////////////// 7 7 _wait_nonz_compute '/ 7 If any compute flags have been counted, decrement them and proceed, else 7 wait for the next one. 7 '/////////////////////////////////////////////////////////////////////////////// ismblock _wait_nonz_compute{wait_mask} (compute_count;) phantom; begin LDA compute_count // test compute count JEQ $1 SUB #1 // non-zero, so STA compute_count JMP $3 ?1: JWF $1 // no built-up c LDWS #wait mask // reset wait flags register ?3: end '/////////////////////////////////////////////////////////////////////////////// 7 7 _poll_compute_line V 7 Test if a compute has come in. If so, reset compute flags and bump 7 the compute count. /////////////////////////////////////////////////////////////////////////////// asmblock _poll_compute_line{wait_mask) (compute_count;) phantom; begin JWF $1 // test compute LDWS #wait_mask // reset wait flags register fo LDA compute_count // bump compute count ADD #1 STA compute_count $l: end /////////////////////////////////////////////////////////////////////////////// // // _pr_reset // // Reset the probe when its fifo is half full. // /////////////////////////////////////////////////////////////////////////////// asmblock _pr_reset(probe_signal;) phantom; begin done: end * SUBSTITUTE SHEET APPENDIX f COLUMN 1 COLUMN 2 C58159 328000 C58168 90082Θ C58169 30084b c5816a 000000 300833 000000 f58004 10084d 318001 90084d 900833 000000 300832 040000 e5800c 4c800e 198001 5C0846 900832 ac084e 4C0489 740000 300834 5C8001 dl8013 740000 30048d 4C0849 e58013 a4084c ac0489 5C084C ac0834 4C0848 300800 30084a 21bfff 108001 700837 5c800e e58013 740000 300837 4C084C 34800e 5C8001 118001 4C0847 718837 30084a edδOld 108001 318835 5c800e 900837 740000 4c084c COLUMN 3 COLUMN k > 5c80ύα 5c800e 4c084e 740000 30084a 4c084f 108001 5C8001 5c800e 4c0847 30084d 30084a 112000 108001 el804b 5c800e 308001 740000 c5804e 4c084f 308001 5C8001 240000 4c084f 118001 30084a 90082d 108001 30084d 5c800e 112000 4C0851 900850 30084a 000000 108001 040000 5c800e 4c800e 300850 5C0846 112000 ac0851 el8078 740000 308001 5C8001 C5807b 740000 308001 4C0849 240000 a4084f 118001 5c084f 90082f 4C0848 4c082d 30084a 5c082e 108001 740000 F- 2- COLUMN 5 COLUMN 6 928000 308001 4dffff C580a5 30083c 308003 71883a 900829 e58089 300864 4d8000 900828 118001 100829 71883c 900864 ed808d 4C0830 318838 300865 90083C 71fff8 acθ455 edδOba 4c082f 718008 5c082e f580ba 740000 35886e 740000 44800e a40830 320000 4C082C 5c800e 300852 308008 71fff8 ed80b8 ed80a4 308004 718008 c580bb f580a4 306001 35885b C580bb 44800e 308003 320000 90082a 5c800e 300877 308008 900826 ed80a2 10082a F- 3 COLUMN 7 COLUMN 8 ed80c7 4C0822 300828 5C0822 900827 740000 4C0827 740000 5c082d a40831 740000 4C0825 740000 5c082f a40824 740000 300824 740000 fl80d3 a40823 240000 300823 118001 fl80f4 fl80d3 240000 240000 118001 90081e fl80f4 30081e 240000 35887b 90081d C58186 300891 a4087a 718911 30087a f58100 358885 340891 C58186 4c081d a40822 aeδOOO 30088f 4c081e 700826 ae8080 fl80e3 118001 300890 900891 700826 C58105 ed80e3 30081f 300826 711000 900825 ed8107 F- V COLUMN 9 COLUMN 10 ac045d * \ 312000 3009a8 90081c 718a28 300824 f5δl32 100823 3409a8 900819 4c0821 30081d aeδOOO 358993 4C0822 C581δ6 ae8080 a40992 118001 300992 9009a8 35δ99d C58137 C5δlδ6 300δlf a40821 711000 4C0819 ed8139 5c09a7 3189a9 740000 9009a8 740000 a40818 316000 c5813a 340841 312000 300816 900820 928000 4C0821 4dffff 5C0821 300841 740000 71δ83f 740000 e58121 a4082b 4dδ000 300831 118001 10082b 718841 90081b ed8125 4c081b 31883d 5c0aa9 900841 F -S COLUMN 11 COLUMN 12 COLUMN 13 4c081α C58168 ae8007 300aaa C58169 4c800e 118001 C5816a 5a8001 718b2b 440bff ae8006 f58150 d5816b 4e8009 aeδOOO 600bca 5a8005 900aaa 740000 740000 300832 740000 4e8008 f58150 740000 5a8004 318001 C5816b ae8009 900832 440bff 740000 300833 d58172 a68008 e58158 440bd8 C68000 198001 740000 900833 740000 C58004 740000 318001 C58172 900832 440bff 318000 d58179 900833 440be6 318635 740000 900800 740000 318635 740000 900837 C58179 318638 440bff 90083c d58180 31883d 44Obf4 900841 740000 318001 740000 900440 C58180 C58004 4e8007 F- € APPENDIX G COLUMN 1 COLUMN 2 000000 000000 .000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 OOOOff 000000 OOOOff 000000 OOOOff 000000 OOOOff 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 G--1 COLUMN 3 COLUMN 4 000002 000835 000000 000015 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000004 000000 000838 000000 000005 000000 000001 000000 000000 000000 100000 000000 000000 000000 000000 000000 000004 000000 00083d 000000 000005 000000 000001 000000 000000 000000 100000 000000 000000 000000 000000 G- -3L COLUMN 5 COLUMN 6 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 G- -3 COLUMN 7 COLUMN 8 0000C0 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 G-V COLUMN 9 COLUMN 10 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 (r - 5 *<- COLUMN 11 COLUMN 12 000000 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo oooooo G - € G- 7 COLUMN 15 COLUMN 16 0000C0 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo G - 8 COLUMN 17 COLUMN 18 0000C0 oooooo 000000 oooooo 000000 oooooo 000000 oooooo OOOOOO oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo (? - ? COLUMN 19 COLUMN 20 00OOC0 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo G- - /0 COLUMN 21 COLUMN 22 000000 oooooo 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo <? - // 287 COLUMN 23 COLUMN 24 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo OOOOOO oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo & - IZL COLUMN 25 COLUMN 26 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo OOOOOO oooooo OOOOOO oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo G- - I3 COLUMN 27 COLUMN 28 000000 oooooo 000000 oooooo 000000 oooooo OOOOOO oooooo OOOOOO oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo G- - I COLUMN 29 COLUMN 30 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo &- \s COLUMN 31 COLUMN 32 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo £ - € COLUMN 34 COLUMN 33 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo e5ae5a oooooo 133333 oooooo 092492 oooooo 0860a9 oooooo 6487ed oooooo 0020C4 oooooo OOOOOO oooooo 000000 oooooo OOOOOO oooooo OOOOOO oooooo OOOOOO oooooo OOOOOO oooooo fffffδ OOOOOl 004000 oooooo 008000 oooooo 010000 oooooo 020000 oooooo 040000 oooooo 080000 oooooo 100000 oooooo 200000 oooooo OOOOOl oooooo 000002 G -17 COLUMN 35 COLUMN 36 000040 C03d7f 000080 000000 000100 000000 000000 000000 fffffδ oooooo 004000 OOOOdb 008000 000053 010000 0000a6 020000 000053 040000 7f6b44 080000 C09411 100000 OOOOOO 200000 OOOOOO 000001 OOOOOO 000002 OOOOOO 000004 866667 000008 799999 000010 000892 000020 OOOOOO 000040 OOOOOO 000080 OOOOOO 000100 OOOOOO oooooo OOOOOO 866667 oooooo 799999 oooooo 000000 oooooo 0000d7 oooooo 00003d oooooo 00007b oooooo 00003d oooooo 7fc083 oooooo G - IS COLUMN 37 COLUMN 38 000000 oooooo 000000 oooooo OOOOOO oooooo 000000 oooooo OOOOOO oooooo OOOOOO oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo £- / ? COLUMN 39 COLUMN 40 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo & -ZO COLUMN 41 COLUMN 42 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo COLUMN 43 COLUMN 44 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo OOOlOf oooooo 00003d oooooo 00007b oooooo 00003d oooooo 7fc083 oooooo C03d7f oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo 000113 oooooo 000053 oooooo 0000a6 oooooo 000053 oooooo 7f6b44 oooooo C09411 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo COLUMN 45 COLUMN 46 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo OOOOOO oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo £-Λ3 COLUMN 47 COLUMN 48 000000 oooooo 000000 oooooo 000000 oooooo 000000 oooooo OOOOOO oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo & - 2 V COLUMN 49 COLUMN 50 000000 oooooo 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo Q-3. S COLUMN 51 COLUMN 52 000000 oooooo 000000 oooooo 000000 oooooo OOOOOO oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo 400000 oooooo OOOaab oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo G-3. G COLUMN 54 COLUMN 53 0U0000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo COLUMN 55 COLUMN 56 000000 oooooo 000000 oooooo 000000 oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo oooooo 304 APPENDIX - _Xram_configuration _Xreserved_1 _Xsproc_halt _Xsproc_βxit_brβa _Xrβsβrvβd_2 _Xserial_in_port_int_clk_0 _Xsβrial_in_port_int_clk_1 _Xsβπ"al_out_port_int_clk_0 _Xsβrial_out_port_int_cIk 1 _Xrβsβrvβd_3 _Xsβrial_in_port_bu _lβn_0 _Xserial_in_port_fifo_ix_len_0 _Xsβrial_in_port_ i o_start_0 _Xserial_in_port_config_0 _Xserial_in_port_reserved_0 _Xsβrial_in_port_buf_lβn_1 _Xsβria n_port_fifo_ix_lβn_1 _Xsβrial_in_port_fifo_start_1 _Xsβrial_in_port_config_1 _Xsβrial_in_port_resβrvβd_1 _Xsβrial_out_port_resβrvβd_0 _Xsβrial_out_port_buf_lβn_0 _Xsβrial_out_port_ ifo_start_0 _%serial_out_port_config_0 _Xserial_out_port_decimation_0 _Xserial_out_port_run_0 _Xsβrial_out_port_wait_mask_0 _Xsβπ"al_out_port_f111_0 _Xsβrial_out_ρort_rβsβrvβd_1 _Xsβrial_out_port_buf_lβn_1 _Xsβrial_out_port_fι'fo_start_1 _Xsβrial_out_port_config_1 _Xserial_out_port_decimation_1 _Xsβrial_out_port_run_1 _Xsβrial_out_port_wait_mask_1 _Xsβπ ' al_out_port_fi ll_1 _Xrβsβrvβd_ports _Xprobe_' n buf len 0 _Xprobe_in_fifo_ix_len_0 _Xprobe_in_fifo_start_0 _Xprobe_in_data_addr_0 _Xprobe_in_gain_0 _Xreserved_4 _Xprobe_out_rβsβrved_0 _Xprobe_out_buf_len_0 _Xprobe_out_fl o_start_0 _Xprobe_out_config_0 _Xprobe_out_decimation_0 _Xprobβ_out_run_0 _Xprobβ_out_wait_mask_0 _Xprobe_out_fi Il_0 _Xrβserved_5 _XparaIlel_port_clear_flags _Xgenβral_purposβ_rβgistβr _XparaIlel_port_rβeeivβ _Xgpio_register XparaIlel_port_mode_registβr _Xrβserved_6 _Xport_0_flag _Xport_1_flag //' / _n000020 _wn00001 _ n0000 2 _ nQ0D008 _wn000013 _ nθαθD09 _ n000007 _ n000006 _ n000021 _wnQ00005 _ n000003 _wn000001 _wn000002 _vn000004 _n000011 _zone_0_seg_0 _&probe_signal _zonβ_0_i n_f i f o_1 _zone_0_i n_f i f o_out_ptr_1 _zonβ_0_out_f i f c_0 _zone_0_out_f if o_i n_ptr_0 _zone_0_out_fifo_1 _zone_0_out_f i fo_iπ_ptr_1 _Xprobe_fifo_0 H-GL. osd.y12 osd.y13 osd .y14 osd.freq osd.s nval osd .sinramp osd.sinsgn *t osd.cosval osd .cos ramp osd.cossgn sealer2.shift scaler2.scaltab intl.temp scalerl .shift scalerl.scaltab hlim2. lower hlim2. upper filt2.out1 fi lt2.fi lter11. return fi lt2.fi Iter11.b0 filt2.filter11.b1 fi lt2.fi Iter11.b2 fi lt2.fi Iter11.a1 filt2.filter11.a2 fi lt2.fi Itβr11.x1 fi lt2.fi Itβr11.x2 filt2.filter11.y1 fi lt2.fi Iter11.y2 fi lt2.fi lter12. return fi U2.fi Iter12.b0 fi lt2.fi Iter12.b1 fi lt2.fi Iter12.b2 fi lt2.fi Iter12.a1 fi lt2.fi Uer12.a2 fi lt2.fi Iter12.x1 fi lt2.fi Itβr12.x2 fi lt2.fi Iter12.y1 fi lt2.fi Iter12.y2 hliml. lower hliml .upper raw. ptr raw. outvectorl raw.outvector2 filtl.outl fi lt1.fi lter11. return filt1.filter11.b0 fi lt1.fi Itβr11.b1 f lt1.filter11.b2 filt1.filter11.a1 filt1.filter11.a2 fi lt1.fi Iter11.x1 Mlt1.filter11.x2 filt1.filter11.y1 lt1.filter11.y2 fi ltl.fi lter12. return fi lt1.fi Iter12.b0 filt1.filter12.b1 fi lt1.fi Iter12.b2 fi lt1.fi Iter12.a1 -3 308 fi lt1.fi Iterl 2. a2 fitt1.fi Iter12.x2 filt1.filter1Z.y1 fiU1.fiUerl2.y2 a pl.gain f i Itβrβd.ptr f i Itered. outvectorl f i ttβred.outvβctor2 aap2.gain ■agnitud.ptr ■ agnitud.outvector _zone_0_turnsti le_1.semaphore _zone_0_frβe_seg_0.semaphore _zone_0_pr_rβset_0.probe_signa I inl.out adcinl.out adcinl.fifo adcin1.out_ptr adcin1.in_ptr os .sin osd .cos mult 2. ina ■u It 2. inb mult2.out dacoutl.in dacoutl .fifo dacoutl .buf f βr_ptr dacoutl ,sync_addr ■ultδ.ina ■u US. inb ■ultδ.out sealer 2. in scaler2.out intl.in intl.out scalerl.in scalerl.out int2.in int2.out hli«2.in hli»2.out auU4.ina ■ult4.inb ■ult4.out fwrZ.in fwr2.out fi lt2.in fi U2.out fi lt2.fi ltβr11. in fi lt2.fi Iterll. out fi U2.fi ltβrl2.in fiU2.filter12.out hliml. in hliml. out ιuU6.ina ιult6.out A'Ϋ mult3.ina mult3.inb auU3.out fwrl.in fwrl.out raw. ina raw. inb raw. reset raw. done suml.ina su l.inb suml.out filtl.in filtl.out fiU1.filter11.1n f1U1.f1lter11.out fi U1.fi Uβr12. in filt1.filter12.out ampl . i n ampl .out dacout∑.in dacout2.fi fo dacout 2. buf f βr_pt r dacout2. sync_addr fi Uered.ina fi Uered.inb fi Uered. reset fi ered. done fi lt_don.in sqrl.ina sqrl.inb sqrl.out sum2. i na sum2.inb sum2.out amp2. i n amp2.out πagnitud.in _zone_0_turnsti le_0. semaphore _zone_0_freβ_seg_1.semaphore _zone_0_copy_constant_0.dest _zone_0_copy_constant_1.dest _zone_0_copy_addrβss_0. source _zone_0_copy_address_0.dest _zone_0_copy_addrβss_1.source _zonβ_0_copy_address_1.dest _zonβ_0_copy_addrβss_2. source _zonβ_0_copy_addrβss_2.dest _zonβ_0_copy_addrβss_3. source _zonβ_0_copy_address_3. dest _zonβ_0_copy_constant_2. dest ϊstart _$loop_zone_0 _$start_gsp1 _$start_gsp2 _$start_gsp3 J$start_gsp4 zone 0 turnsti le 1.Sstart Af-s _zonβ_p_turnsti lβ_1.$1 0004 zonβ_0_f ree_seg_0.Sstart 0008 _zone_0_f ree_sβg_0.$1 000c zonβ_0_pr_rβsβt_0.Sstart 000c zone_0_pr_reset_0.done 0013 adcinl .Sstart 0013 adcinl .SI - 0013 adcinl .Sok 001d osd .Sstart 0020 osd .setarg 0020 osd.rv 0027 osd . terra! 002f oscl.term2 0033 osd .teπn3 003a osd . term4 0041 osd .norm 0048 osd .fixl 004b osd .sdone 004e osd .rvc 0054 oscl .ter d 005c oscl .termc2 0060 osd .termc3 0067 osd .termc4 006e osd .normc 0073 osd .fixlc 0078 osd . done 007b multΣ.Sstart 007c dacoutl .Sstart 0081 dacoutl .$1 0089 dacoutl .Sok 008d ■uU5.Sstart 008f scaler∑. Sstart 0094 sea lβr2. sealer 0094 sea ler2. unity 00a4 sea ler2. valid 009a scaler∑. right 00a2 sealer 2. left OOaO sealer 2. done 00a5 intl .Sstart 00a6 scalerl .Sstart OOaa sea lerl . sealer OOaa scalerl . unity OOba scalerl .valid OObO scalerl . right 00b8 scalerl . left 00b6 scalerl .done OObb int2.Sstart OObc hli«2. Sstart OOcO hli«2.done 00c7 ■u 4.Sstart OOcB fwr2.$start OOcd fwr2.done 00d3 fwr2.isneg OOcf f i U2.fi Uer11.Sstart 00d4 fi 2.fi Uβrll .postamble 00d7 fi U2.fi Uer12.Sstart 00d8 fi U2.fi lter12.posta.ible OOdb hliml .Sstart OOdc hliml .done 00e3 »ult6. Sstart 00e4 A-G ■u U3. Sstart 00e9 fwrl .Sstart OOee fwrl .done 00f4 fw .isneg OOfO raw. Sstart 00f5 raw.N0_ST0RE 0100 raw.CLR_DONE 0105 raw.SET_DONE 0107 raw.WRITEJJONE 0108 raw.DONE 0109 su 1.Sstart 0109 fi U1 .fi lter11 . Sstart 010c fi U1 . fi lter11 .posta ble 01Of fi U1 .fi lter12. Sstart 0110 fi lt1 .fi Uer12. postamb le 0113 ampl .Sstart 0114 dacout2.Sstart 0119 dacout2.$1 0121 dacout2.$ok 0125 filtered.Sstart 0127 fi Uered.N0_STORE 0132 filtered.CLR_D0NE 0137 fi Uered.SET_00NE 0139 fi ered. RITE_D0NE 013a filtered.DONE 013b sqrl .Sstart 013b sum2.Sstart 0140 amp2.Sstart 0143 nagnitud.Sstart 0148 nagnitud.DONE 0150 _zone_0_turnsti le_0.Sstart 0150 _zone_0_turnsti lβ_0.$1 0150 _zonβ_0_free_seg_1.Sstart 0154 _zonβ_0_frβe_seg_1.$1 0158 _zone_0_jump_to_0.Sstart 0158 _zone_0_copy_constant_0.Sstart 0159 _zonβ_0_copy_constant_1.Sstart 015b _zonβ_0_copy_address_0.Sstart 015d _zone_0_copy_address_1.Sstart 015f _zone_0_copy_address_2.Sstart 0161 _zonβ_0_copy_address_3.Sstart 0163 _zone_0_copy_constant_2.Sstart 0165 _zone_0_jump_to_1.Sstart 0167 _zone_0_jump_to_2.Sstart 0168 _zonβ_0_jump_to_3.Sstart 0169 _zone_0_jump_to_4.Sstart 016a Bstart 016b _Xpatch_ram_gsp1 016b _Xpatch_ram_gsp2 0172 _Xpateh_ram_gsp3 0179 _Xpatch_ram_gsp4 0180 (start 0186 forml 0186 _Xn_gsps 000004 flag_Iocs 000018 _Xcode_space_start 000000 _Xio_spac6_start 000400 _Xdata_spacβ_start 000800 _Xio_spacβ_size 000400 312 _Xpatch_ram_size 00003b Xcode_space_sizβ 000400 Xdata_space_size 0003ad Xfirst_serial_port 000000 _Xlast_serial_port 000003 _Xfirst_in_port 0Q0000 _Xπ_iπ_ports 000002 _Xfirst_out_port 000002 Xn_out_ports 000002 Xf i rst_computβ_linβ 000014 Xlast_compute_line 000017 _Xmc_freq_max 000010 _Xmc_freq 000010 _Xchip_gsp_rate 30d400 _Xabs_addr_fudge oooooo slO 000014 sl1 000015 *16 000001 «12 000002 <8 000003 lsb oooooo ■sb 000001 short 000001 long oooooo aff oooooo iefault ffffff intern 000001 H'# extern 000000 port_0_mask 000001 port_1_»ask 000002 port_2_mask 000004 port_3_mask 000008 gen_0_mask 000010 gen_7_mask 000800 gen_8_mask 001000 gen_9_mask 002000 gen_10_mask 004000 gen_11_mask 008000 gen_12_mask 010000 gen_13_mask 020000 gen_14_mask 040000 gen_15_mask 080000 compute_0_mask 100000 compute_1_mask 200000 computβ_2_mask 400000 compute_3_mask 800000 _Xin_elk_val_0 OOOOff _Xin_clk_val_1 OOOOff _Xout_clk_val_0 OOOOff _Xout_clk_val_1 OOOOff _Xprobe_out_port_coπf i g_0 000065 _Xgpio_output_fie ld 000010 gpio_0 oooooo gpio_1 000001 gpio_2 000002 gpio_3 000003 rts_0 oooooo rts_1 000001 rts_2 000002 rts_3 000003 _zone_0_out_f i f o_0_depth 000001 _zone_0_out_f i f o_1_depth 000001 _Xprobβ_f i f o_ len_0 000004 inl .Xsubr ffffff inl .Xrate oooooo inl .Xtrigger ffffff adcinl .Xsubr ffffff adcinl .Xtrigger oooooo adcinl .Xrate 000b72 adcinl .Xconfig 000015 adcinl .Xcompute 000014 adcinl . fifo_size 000002 adcinl . buf_size 000001 osd .Xsubr ffffff oscl.Xtrigger ffffff osd .Xrate oooooo osd .Xfreq 0020c4 mult2.Xsubr ffffff dacoutl .Xdest 000002 dacoutl .Xtrigger ffffff dacoutl .Xconfig 000005 H-? O 93/08524 31^ dacoutl .fifo_«iz β 000004 dacoutl. buf_βizβ 000001 multS.Xsubr ffffff *c»ler2.Xsubr ffffff scaler2.Xshift fffffβ int1.Xsubr ffffff scalerl .Xsubr ffffff scalerl .Xshi ft fffffδ iπtΣ.Xsubr ffffff hlim2.Xsubr ffffff hliaΣ.X lower 866667 hli«2. Supper 799999 muU4.Xsubr ffffff filt2.fi Uerll. Xsubr ffffff fi U2.fi Uβr11.Xb0 00003d fiU2.filter11.Xb1 00007b filt2.filter11.Xb2 00003d fi U2.fi Uβr11.Xa1 7fc083 fi U2.fi Uβr11.Xa2 c03d7f fi 2.fi UerU.Xsubr ffffff fi U2.fi Uer12.XbO 000053 fi U2.fi Uer12.Xb1 0000a6 fi U2.fi Uβrl2Λb2 000053 fi U2.fi Uer12.Xa1 7f6b44 fi U2.fi Uer12.Xa2 c09411 hliml .Xsubr ffffff hliml .Xlowβr 866667 hliml .Supper 799999 muU6. Xsubr ffffff mult3.Xsubr ffffff raw. Xsubr ffffff raw.Xlength 000080 sum1.Xsubr ffffff fiU1.fi UerU.Xsubr ffffff fiU1.filter11.XbO 00003d- fiU1.filter11.Xb1 00007b fiU1.filter11.Xb2 00003d filt1.filter11.Xa1 7fc083 fiU1.fi Uer11.Xa2 c03d7f filt1.filtβr12.Xsubr ffffff fiU1.filter12.XbO 000053 filt1.fiUerT2.Xb1 0000a6 filt1.filtβr12.Xb2 000053 fiU1.filter12.Xa1 7f6b44 filt1.filter12.Xa2 c09411 ampl .Xsubr ffffff a pl .Xgain cOOOOO dacout2.$dβst 000003 dacout2. St rigger ffffff dacout∑. config 000005 dacout∑ . f if o_si ze 000004 dacout2.buf_size 000001 filtered .Xsubr ffffff fi ered. Xlβπgth 000080 raw_doπβ. subr ffffff filtjdon. subr ffffff sqrl .Xsubr ffffff sum2. Xsubr ffffff amp2.Xsubr ffffff amp2.Xgain 400000 '/ magnitud.Xsubr ffffff agnitud.Xlength 000080 _zone_0_jump_to_0. loop_address 000004 _zone_0_copy_eonstant_0.constant 000001 _zone_0_copy_constant_1.constant oooooo _zone_0_copy_addrβss_0.source_size 000002 _zone_0_copy_address_1.source_size 000002 _zonβ_0_copy_address_2.source_size 000002 _zone_0_copy_address_3.source_size 000002 _zone_0_copy_constant_2.constant 000001 _zone_0_jump_to_1. loop_address 000004 _zonβ_0_jump_to_2. loop_address 000168 _zone_0_jump_to_3. loαp_address 000169 _zone_0_jump_to_4. loop_address 00016a return 000000 bO 000001 b1 000002 b2 000003 al 000004 a2 000005 x1 000006 x2 000007 yi 000008 y2 000009 0001 100000 0004 - l/ APPENDIX r ϊΗPDUAL.BLK Wednesday, October 2, 1991 4:19 pm Page 1 (finclude "sprocdef.h" fix24_type const yhpdual_load[] = { 3x00019800, 0x00000000, 3XC5815900, 0XC5816800, 0xC5816900, 0xC5816A00, 0x30083400, 0XF5800400, 0x318001 30, 0X90083400, 3x30083300, 0XE5800C00, 0x19800100, 0x90083300, 0X4C048A00, 0x30083500, 0XD18013 30, 0X30048E00, 3XE5801300, 0XAC048A00, 0xAC083500, 0x30080100, 0X21BFFF00, 0x70083800, 0XE58013 30, 0X30083800, 3X34800E00, 0x11800100, 0x71883700, 0XED801D00, 0x31883500, 0x90083800, 0x328000 30, 0X90082F00, 0X30O84COO, 0x00000000, 0x00000000, 0X10084E00, 0X90084E00, 0x00000000, 0x040000 00, 0X4C800E00, 0X5C084700, 0XAC084F00, 0x74000000, 0X5C800100, 0x74000000, 0X4C084A00, 0XA4084D 00, 0X5C084D00, OX4C084900, 0X30084B00, 0x10800100, 0X5C800E00, 0x74000000, 0X4C084D00, 0X5C8001 00, 0X4C084800, 0X30084B00, 0X10800100, 0x5C800E00, 0x74000000, 0X4C084D00, 0X5C800100, 0X4C084D 00, 0X30084B00, 0x10800100, 0X5C800E00, 0x4C084F00, 0X30084B00, 0x10800100, 0X5C800E00, 0X30084E 30, 0X11200000, 3XE1804B00, 0x30800100, 0xC5804E00, 0x30800100, 0x24000000, 0x11800100, 0X90082E 30, 0X30084E00, 3X11200000, 0X90085100, 0x00000000, 0x04000000, 0X4C800E00, 0X5C084700, 0XAC0852 30, 0X74000000, OX5C800100, 0x74000000, 0X4C084A00, 0XA4085000, 0X5C085000, OX4C084900, 0X30084B 00, 0x10800100, 0X5C800E00, 0x74000000, 0x4C085000, 0X5C800100, 0X4C084800, OX30084BOO, 0x108001 00, 0X5C800E00, 0x74000000, 0X4C085000, 0X5C800100, OX4C085000, 0X30084B00, 0x10800100, 0X5C800E 00, 0X4C085200, 0X30084B00, 0X10800100, 0x5C800E00, 0x30085100, 0x11200000, 0XE1807800, 0x308001 00, 0XC5807B00, 0x30800100, 0x24000000, 0x11800100, 0x90083000, 0X4C082E00, Ox5C082FOO, 0x740000 00, 0x74000000, 0XA4O82DOO, 0X34083D00, 0x30083000, 0x92800000, 0X4DFFFF00, 0X30083D00, 0X71883A 00, 0XE5808900, 0X4D800000, 0x11800100, 0x71883C00, 0XED808D00, 0x31883800, 0X90083D00, 0XAC0456 00, 0X4C083000, 0X5C082F00, 0x74000000, 0x74000000, 0XA4083100, 0X4C082D00, ' 0x30085300, 0X71FFF8 00, 0XED80A400, 0x71800800, 0XF580A400, 0X35885B00, 0X44800E00, 0x32000000, OX5C800EOO, 0x308008 00, 0XED80A200, 0X30800400, 0XC580A500, 0x30800100, 0XC580A500, 0x30800300, 0X90082A00, 0x300865 00, 0x90082900, 0X10082A00, 0X90086500, 0x4C083100, 0x30086600, 0X71FFF800, 0XED80BA00, 0x718008 00, 0XF580BA00, 0X35886E00, 0X44800E00, 0x32000000, 0X5C800E00, 0x30800800, 0xED80B800, 0x308004 00, 0XC580BB00, 0X30800100, 0XC580BB00, 0x30800300, 0X90082B00, 0x30087800, 0x90082700, 0X10082B τ-ι YHPDUAL.BLK Wednesday, October 2, 1991 4:19 pm Page 2 00, 0x90087800, 0 X 30087900, 0x70082900, 0XF180C700, 0X30087A00, 0x70082900, 0XED80C700, 0x300829 00, 0x90082800, 0X4C082800, 0X5C082E00, 0x74000000, 0x74000000, 0XA4082500, 0x30082500, 0xF180D3 00, 0x24000000, 0X11800100, OXF180D300, 0x24000000, 0X90081F00, 0X30081F00, 0X35887B00, 0xC58186 00, 0XA4087B00, 0X30087B00, 0x35888500, 0XC5818600, 0xA4082300, 0x30089000, 0x70082700, 0XF180E3 00, 0x30089100, 0X70082700, 0XED80E300, 0x30082700, 0x90082600, 0X4C082300, 0X5C082300, 0x740000 00, 0x74000000, 0XA4083200, 0X4C082600, 0X5C083000, 0x74000000, 0x74000000, 0XA4082400, 0x300824 00, 0XF180F400, 0x24000000, 0x11800100, 0XF180F400, 0x24000000, 0X90081E00, 0x30089200, 0x718911 00, OXF5810000, 0X34089200, 0X4C081E00, 0XAE800000, 0X4C081F00, 0XAE808000, 0x11800100, 0x900892 00, 0XC5810500, 0X30082000, 0x71100000, 0XED810700, 0x31889200, 0x90089200, 0x31800000, 0XC58108 00, 0x31800100, 0X90081D00, 0x30082500, 0x10082400, 0X90081A00, 0X30081E00, 0x35899300, 0xC58186 00, OXA4099300, X30099300, 0X35899D00, 0XC5818600, 0XA4082200, 0X4C081A00, 0X5C09A800, 0x740000 0, 0x74000000, XA4081900, 0x34084200, 0x30081900, 0x92800000, 0X4DFFFF00, 0x30084200, 0x71883F 0, 0XE5812100, X4D800000, 0X11800100, 0x71884100, 0XED812500, 0X31883D00, 0x90084200, 0XAC045E 0, OX3009A900, X718A2800, 0XF5813200, 0X3409A900, 0X4C082200, 0XAE800000, 0X4C082300, 0XAE8080 0, 0x11800100, X9009A900, 0XC5813700, 0x30082000, 0x71100000, 0XED813900, 0X3189A900, 0X9009A9 0, 0X31800000, XC5813A00, 0x31800100, 0x90082100, 0X4C082200, 0X5C082200, 0x74000000, 0x740000 0, 0XA4082C00, X30083200, OX10082COO, 0X90081C00, 0X4C081CO0, 0X5C0AAA00, 0x74000000, 0x740000 0, OXA4081BOO, X340AAB00, 0X4C081B00, 0X300AAB00, 0x11800100, 0X718B2B00, 0XF5815000, OxAEδOOO 0, 0X900AAB00, x30083300, OXF5815000, 0x31800100, 0x90083300, 0x30083400, 0XE5815800, 0x198001 0, 0x90083400, XC5800400, 0x31800100, 0x90083300, 0x31800000, 0x90083400, 0x31883500, 0x900801 0, 0x31883500, x90083800, 0x31883800, 0X90083D00, 0X31883D00, 0x90084200, 0x31800100, 0x900441 0, 0XC5800400, XC5816800, OXC5816900, 0XC5816A00, 0X440C0000, 0XD5816B00, 0X600BCB00, 0x740000 0, 0x74000000, x74000000, 0XC5816B00, 0X440C0000, 0XD5817200, 0X440BD900, 0x74000000, 0x740000 0, 0x74000000, XC5817200, 0X440C0000, 0XD5817900, 0X440BE700, 0x74000000, 0x74000000, 0x740000 0, 0XC5817900, X440C0000, OXD5818000, 0X440BF500, 0x74000000, 0x74000000, 0xC5818000, 0x4E8007 0, 0X5E800300, X-G ΪHPDUAL.BLK Wednesday, October 2, 1991 4:19 pm Page 3 3X74000000, 0X4E800600 0X5A800200 OXAE800700 0X4C800E00, 0X5A800100, 0XAE8006 30, 0X4E800900, 3X5A800500, 0x74000000 0X4E800800 0X5A800400 0XAE800900, 0x74000000, OXA68008 30, 0XC6800000, 3X0000F200, 0x00041000 3X0000FF00, OXOOOOFFOO OxOOOOFFOO OxOOOOFFOO 0X00000000, 0x00000000, 0x000000 30, 0X00000000, 3x00000000, 0x00000000 0x00000000 0X00000000 0X00000000, 0X00000000, 0X000000 30, 0X00000000, 3X00000000, 0x00000000 0x00000000 0X00000000 0x00000000, 0x00000000, 0x000000 30, 0x00000000, 3x00000000, 0x00000000 0x00000000 0x00000000 0X00000000, 0x00000000, 0x000000 30, 0x00000000, 3x00000000, 0X00000000 0x00000000 0x00000000 0x00000000, 0x00000000, 0x000000 30, 0X00000000, 3x00000000, 0X00000000 0x00000000 0X00000000 0x00000000, 0x00000000, 0x000000 30, 0X00000000, 3x00000000, 0x00000200 0x00083500 0x00001500 0x00000000, 0x00000000, 0x000000 00, 0x00000000, 0x00000000, 0x00000000 0x00000000 0x00000000 0x00000000, 0x00000000, 0X000000 30, 0X00000000, 3X00000000, 0X00000400 0x00083800 0X00000500 0x00000100, 0x00000000, 0X100000 30, 0x00000000, 3x00000000, 0x00000400 0X00083D00 0x00000500 0X00000100, 0X00000000, 0x100000 30, 0x00000000, 3X00000000, 0x00000000 0X00000000 0x00000000 0X00000000, 0X00000000, 0x000000 30, 0X00000000, 3X00000000, 0x00000000 0X00000000 0X00000000 0x00000000, 0x00000000, 0x000000 30, 0x00000000, 3x00000000, 0X00000000 0x00000000 0X00000000 0X00000000, 0X00000000, 0X000000 30, 0x00000000, 3x00000000, 0x00000000 0x00000000 0x00000000 0x00000000, 0x00000000, 0x000000 30, 0x00000000, 3X00000000, 0x00000000 0X00000000 0x00000000 0x00000000, 0x00000000, 0x000000 30, 0x00000000, 3x00000000, 0x00000000 0x00000000 0X00000000 0X00000000, 0X00000000, 0X000000 30, 0x00000000, 3X00000000, 0X00000000 0X00000000 0x00000000 0x00000000, 0x00000000, 0x000000 30, 0x00000000, 3x00000000, 0X00000000 0X00000000 0x00000000 0X00000000, 0x00000000, 0x000000 30, 0x00000000, 3X00000000, 0X00000000 0X00000000 0X00000000 0x00000000, 0X00000000, 0X000000 30, 0x00000000, 3x00000000, 0x00000000 0x00000000 0X00000000 0x00000000, 0x00000000, 0X000000 30, 0X00000000, 3X00000000, 0x00000000 0X00000000 0x00000000 0X00000000, 0X00000000, 0x000000 30, 0x00000000, * -, 3x00000000, 0x00000000 0x00000000 0x00000000 0x00000000, 0x00000000, 0x000000 30, 0x00000000, 3x00000000, 0X00000000 0x00000000 0x00000000 0x00000000, 0x00000000, 0x000000 30, 0X00000000, J - 3 YHPDUAL.BLK Wednesday, October 2, 1991 4:19 pm Page 4 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0X00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 00, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0x000000 00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000, 0x00031800, 0x00081400, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 0, 0x00000000, X00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 0, 0x00000000, X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 0, 0X00000000, X00000100, 0x00000000, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 0, 0x00000000, x00000000, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0x000000 0, 0x00000000, X00000000, 0x00000000, 0XE5AE5A00, 0x13333300, 0x09249200, 0X0860A900, 0X6487ED 0, 0X0020C400, X00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0X00000000, 0XFFFFF8 0, 0x00400000, X00800000, 0X01000000, 0x02000000, 0X04000000, 0x08000000, 0X10000000, 0x200000 0, 0x00000100, X00000200, 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0X00004000, 0x000080 0, 0x00010000, X00000000, 0XFFFFF800, 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x040000 0, 0x08000000, x10000000, 0X20000000, 0x00000100, 0X00000200, 0x00000400, 0X00000800, 0x000010 0, 0x00002000, X00004000, 0X00008000, 0X00010000, 0X00000000, 0x86666700, 0x79999900, 0x000000 0, 0X0000D700, X00003E00, 0X00007D00, OX00003EOO, 0X7FC08300, 0XC03D7E00, 0x00000000, 0x000000 0, 0x00000000, X00000000, 0X0000DB00, 0x00005300, OXOO00A7O0, 0x00005300, OX7F6B4400, 0XC09410 0, 0x00000000, X00000000, 0X00000000, 0x00000000, 0X86666700, 0x79999900, 0x00089200, 0x000000 0, 0x00000000, X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 0, 0x00000000, X00000000, 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0X00000000, 0x000000 τ- y YHPDUAL.BLK Wednesday, October 2, 1991 4:19 pm Page 5 00, 0x00000000, 0X00000000, 0x00000000 0x00000000 0x00000000, 0x00000000 0x00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000 0X00000000 0X00000000, 0X00000000 0x00000000, 0X000000 00, 0x00000000, 0x00000000, 0X00000000 0x00000000 0x00000000, 0x00000000 0X00000000, 0x000000 00, 0x00000000, 0x00000000, 0X00000000 0x00000000 0x00000000, 0X00000000 0x00000000, 0x000000 00, 0x00000000, 0x00000000, 0x00000000 0x00000000 0x00000000, 0x00000000 0x00000000, 0x000000 00, 0X00000000, 0X00000000, 0x00000000 0x00000000 0X00000000, 0x00000000 0X00000000, 0x000000 00, 0x00000000, 0X00000000, 0x00000000 0x00000000 0x00000000, 0x00000000 0x00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000 0X00000000 0X00000000, 0x00000000 0x00000000, 0X000000 00, 0x00000000, 0x00000000, 0x00000000 0x00000000 0x00000000, 0X00000000 0x00000000, 0x000000 00, 0X00000000, 0x00000000, 0x00000000 0x00000000 0X00000000, 0x00000000 0x00000000, 0x000000 00, 0X00000000, 0X00000000, 0x00000000 0x00000000 0x00000000, 0x00000000 0X00000000, 0X000000 00, 0x00000000, 0X00000000, 0x00000000 0X00000000 0X00000000, 0x00000000 0X00000000, 0X000000 00, 0X00000000, 0X00000000, 0x00000000 0x00000000 0X00000000, 0x00000000 0x00000000, 0x000000 00, 0X00000000, 0x00000000, 0x00000000 0x00000000 0X00000000, 0x00000000 0x00000000, 0x000000 00, 0x00000000, 0X00000000, 0x00000000 0X00000000 0X00000000, 0x00000000 0x00000000, 0x000000 00, 0x00000000, 0x00000000, 0x00000000 0x00000000 0x00000000, 0x00000000 0X00000000, 0x000000 00, 0x00000000, 0X00000000, 0x00000000 0x00000000 0X00000000, 0X00000000 0X00000000, 0x000000 00, 0x00000000, x00000000, 0X00000000 0X00000000 0X00000000, 0X00000000 0X00000000, 0x000000 00, 0X00000000, x00000000, 0x00000000 0x00000000 0x00000000, 0x00000000 0x00000000, 0X000000 0, 0X00000000, x00000000, 0X00000000 0x00000000 0x00000000, 0x00000000 0X00000000, 0x000000 0, 0x00000000, X00000000, 0x00000000 0X00000000 0x00000000, 0x00000000 0X00000000, 0x000000 0, 0X00000000, X00000000, 0X00000000 0X00000000 0x00000000, 0x00000000 0X00000000, 0x000000 0, 0X00000000, X00000000, 0X00000000 0x00000000 0x00000000, 0x00000000 0x00000000, 0x000000 0, 0X00000000, X00000000, 0x00000000 0x00000000 0X00000000, 0x00000000 0X00000000, 0x000000 0, 0X00000000, X00000000, 0x00000000 0x00000000 0x00000000, 0X00000000 0x00000000, 0x000000 0, 0x00000000, τ-s YHPDUAL.BLK Wednesday, October 2, 1991 4:19 pm Page 6 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 00, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0X000000 00, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0x000000 00, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0x000000 00, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 00, 0X00010F00, 0X00003E00, 0X00007D00, 0X00003E00, 0X7FC08300, 0XC03D7E00, 0x00000000, 0x000000 00, 0x00000000, 0x00000000, 0X00011300, 0x00005300, 0X0000A700, 0x00005300, 0X7F6B4400, 0XC09410 00, 0X00000000, 0X00000000, 0X00000000, 0X00000000, OXCOOOOOOO, 0X0009A900, 0x00000000, 0X000000 00, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X000000 00, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0X000000 00, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0X000000 00, 0X00000000, x00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0X000000 0, 0x00000000, X00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0X000000 0, 0x00000000, x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0x000000 0, 0x00000000, x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0X000000 0, 0X00000000, X00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0X000000 0, 0X00000000, X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 0, 0X00000000, x00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0X000000 0, 0X00000000, X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X000000 0, 0x00000000, x00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0x000000 0, 0X00000000, X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0X000000 0, 0x00000000, X00000000, 0X00000000, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0x000000 0, 0X00000000, x00000000, 0x00000000, 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0X000000 0, 0X00000000, X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0X000000 0, 0X00000000, x00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0x000000 0, 0x00000000, X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0X000000 T-G YHPDUAL.BLK Wednesday, October 2, 1991 4:19 pm Page 7 00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X000000 00, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 00, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0x000000 00, 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0x00000000, 0x000000 00, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 00, 0x00000000, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0x000000 00, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0x000000 00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 00, 0x00000000, X00000000, 0x00000000, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0x000000 0, 0x00000000, x00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0x000000 0, 0x00000000, x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 0, 0X00000000, X00000000, 0X00000000, 0x00000000, 0X00000000, 0X00000000, 0X40000000, OxOOOAAB 0, 0x00000000, x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 0, 0x00000000, x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 0, 0x00000000, X00000000, 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 0, 0x00000000, x00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 0, 0X00000000, X00000000, 0x00000000, 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0x000000 0, 0X00000000, x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000 0, 0x00000000, X00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000000, 0x000000 0, 0X00000000, x00000000, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0x00000000, 0x000000 0, 0X00000000, x00000000, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0x00000000, 0x000000 0, 0x00000000, X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000000, 0X00000000, 0x000000 0, 0X00000000, x00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0x000000 0, 0X00000000, -X -7 32*f YHPDUAL.BLK Wednesday, October 2, 19914:19 pm Page 0x00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000 00, 0x00000000, 0X00000000, 0x00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000 00, 0x00000000, 0x00000000, 0x00000000, 0X00000000, 0X00000000, 0x00000000, 0X00000000, 0x00000 00, 0X00000000, 0x00000000, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000000, 0x00000 00, 0x00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0X00000000, 0x00000 00, 0x00000000, 0x00000000, 0x00000000 } ; fix24_type const yhpdual_load_end = { OxOOBADBAD } ; :-? APPENDIX , Gf <1AINTEST.C Wednesday, October 2, 19914:25 pm Page 1 f* Copyright (c) Star Semiconductor, Inc. 1991. All Rights Reserved. _ This material may not be copied or used without prior written permission. * $Header: /home/solus/users4/release/CVS/linkl/funlib/maintest.c,v 1.11991/10 O2 12:27:10 krassow Exp $ * $Id: maintest-cv 1.11991/10/02 12:27:10 krassow Exp $ * $Revision: 1.1 $ */ /************************************************************************* maintest.c ************************************************************************** This file is a skeleton (stub) of what a SMI application main.c file should look like. */ /*******************/ /* requires */ /*******************/ /* SPROC specific interface declares */ Ifinclude "sprocdef.h" Ifinclude "sproclib.h" /* application specific declarations */ finclude "yhpdual.h" Ifinclude "yhpdual.blk" /*******************/ /* exceptions */ /*******************/ /* No exceptions */ / *******************/ /* constants */ / *******************/ #define OUTROW 12 #define OUTCOL 1 #define pi 3.1415926 fdefine Rref 1000.0 #define Fosc (2930 * 0.0002) fdefine real_length 256 /*******************/ /* types */ /******************* / J- l 3z r , MAINTEST.C Wednesday, October 2, 1991 4:25 pm Page /* definition section specific to impedance analyzers */ enum { REAL, MAG, OHMS } Display; enum { AVE, SNAP } Function; unsigned int Samples; typedef struct complex_tag { double real; double imag; } complex; typedef struct vector_tag { double magnitude; double phase; } vector; /*******************/ /* data */ /*******************/ unsigned int Debug; unsigned int Done; unsigned int loops; /* This declaration requires that the real sink length matches the */ /* imaginary sink length which is a reasonable assumption. */ sdata Sreal[real_length] ; sdata Simag[real_length]; complex Answer[real_length] ; complex Final; double Rut, Cut; /* device under test */ /*******************/ /* macros */ /*******************/ /*******************/ /* functions */ /*******************/ vector complex2vector(complex cvalue) ; double r_to_d(double rad) ; double scale(double val) ; void fix24_to_str(char *str, fix24_type src) ; /* interface declarations for my routines */ void get_new_data() ; void calc() ; void show_front_panel() ; void update_display() ; void delay_to_settle() ; J- L, MAINTEST.C Wednesday, October 2, 19914:25 pm Page vector complex_to_vector(complex eval) void delay(unsigned int count) ; void delay_to_settle(void) ; /*******************/ /* code */ *******************/ unsigned int main() { loops = 0; Done = 0; Function = AVE; Display = MAG; Samples = real_length; /* initialize hardware */ sproσ_rese (&yhpdual_control) ; /* load sproc */ sproc_load(&yhpdual_code, &yhpdual_load[0]) ; /* display screen header */ * show_front_panel() ; /* start sproc */ sproc_start(&yhpdual_control) ; /* perform the following forever */ do { /* sanity checker */ if (loops < 10000) loops++; else loops = 0; /* check for keyboard strike */ if (check_for_key()) { delay_to_settle() ; } /* get data from sproc */ get_new_data() ; /* calculate result */ calcQ ; /* refresh output */ GT- 3 MAINTEST.C Wednesday, October 2, 1991 4:25 pm Page 4 update_display() ; delay(200) ; ) while (!Done) ; /* perform any tidying up needed */ clean_exit() ; return(0) ; } /* end of main */ /*****************************************************************/ /* SPROC specific routines */ *****************************************************************/ void get_new_data() { unsigned int i; /* start new SINK collections */ yhpdual.capture_l.int24 = 0; /* wait for sink to become full */ while (!yhpdual.rdone_l.int24) delay(1); /* grab data from sproc */ for (i=0; i<Samples; i++) { Sreal[i] = yhpdual.raw.outvectorl[i] ; Simag[i] = yhpdual.raw.outvector2[i] ; Answer[i] .real = fix24_to_double(Sreal[i] .fix24) ; Answer[i].imag = fix24_to_double(Simag[i] .fix24) ; ) } /* end of get_new_data */ void update_display() ( char value_str[80] ; char funσt_str[12] ; vector answer_vector; unsigned int i; char temp_real_str[20] , temp_imag_str[20] ; switch (Display) { case REAL : sprintf(value_str, "Real = %10.5f Imaginary = %10.5f ", Final.real, Final.imag) ; break; J- Ϋ MAINTEST.C Wednesday, October 2 , 1991 4 : 25 pm Page 5 case MAG : answer_vector = complex_to_yector(Final) ; sprintf(value_str, "Magnitude = %10.5f Phase = %7.3f (radians) %8.3f (degrees)", answer_vector.magnitude, answer_vector.phase, r_to_d(answer_vector.phase)) ; break; case OHMS : sprintf(value_str, "Resistive value = %10.5f Impedance value = %10.5f Rut, Cut) ; break; default sprintf(value_str, "Invalid Display mode (%d)", Display) break; } switch (Function) { case SNAP Ϊ strcp (funct_str, "Snapshot: ") ; break; case AVE : strcpy(funct_str, " Average: ") ; break; default : strcpy(funct_str, "Func????: ") ; break; ) term_set_position(0UTR0W, OUTCOL) ; term_print(funct_str) ; term_print(value_str) ; /* display sanity check */ sprintf(value_str, ,τ loop=%5d", loops); term_set_position(0UTR0W+l, OUTCOL) ; term_prin (value_str) ; /* display other values for reference */ if (Debug) { strcp (value_str, "raw real raw imag Xr Xc\n") term_set_position(0UTR0W+2, OUTCOL) ; term_print(value_str) ; for (i=0; i<10; i++) { fix24_to_str(temp_real_str, yhpdual.raw.outvectorl[i] .fix24) ; fix24_to_str(temp_imag_str, yhpdual.raw.outvector2[i] .fix24) ; sprintf(value_str, "%s %081x %s %081x %12.5f %12.5f\n", temp_real_str, Sreal[i].int24, temp_imag_str, Simag[i] .int2 , zr-s- MAINTEST.C Wednesday, October 2, 1991 4:25 pm Page 6 fix24_to_double(Sreal[i] .fix24) , fix24_to_double(Simag[i] .fix24) ) ; term_print(value_str) ; } } /* end of Debug */ } /* end of update display */ /*****************************************************************/ /* end SPROC specific routines */ /*****************************************************************/ /*****************************************************************/ /* Application specific routines */ /*****************************************************************/ void calc() { unsigned int i; double real_tot = 0.0; double imag_tot = 0.0; /* compute final answer differently depending on mode */ switch (Function) { case AVE: for (i=0; i<Samples; i++) { real_tot += Answer[i] .real; imag_tot += Answer[i] .imag; } Final.real = real_tot / Samples; Final.imag = imag_tot / Samples; break; case SNAP : default: Final.real = Answer[0].real; Final.imag = Answer[0].imag; break; } /* Final answer is always related to reference scaling factor */ /* Xc = 1 / (2 * pi * Fosc * C) , so /* cut = 1 / ( 2 * pi * Fosc * Rref) /* /* Rut = Rref * real */ Final.real = scale(Final.real) ; Final.imag = scale(Final.imag) ; Rut = Rref * Final.real; GT- 6 MAINTEST.C Wednesday, October 2, 19914:25 pm Page 7 Cut = 1.0 / ( 2 * pi * Fosc * Rref * Final.imag) ; } /* end of calc */ unsigned int fact(unsigned int a) { unsigned int i = a; while (a > 1) { i = i * a; —; } return(i) ; } void fix24_to_str(char *str, fix24_type src) { sprintf(str, "%061x", src); } double scale(double val) { return(val * pi / 2.0) ; } /* end of scale */ double r_to_d(double rad) { return(rad / pi * 180.0); } /* end of r_to_d */ void show_front_panel() { term_set_position(2, 30) ; term_print("+ +") ; term_set_position(3, 30); term_print("| YHP Impedance Analyzer |"); term_set_position(4, 30) ; term_print("H +") ; term_set__position(6, 1) ; term_prin ("Display modes are: Magnitude/Phase or Real/Imaginary") ; term_set_position(8, 1); term_print("Functions are: Average or Snapshot\ n") ; /* reserve this line for values output */ term_set_position(0UTR0W, OUTCOL) ; term_print(" ") ; term_set_position(15, 10); term_print("Fl to change function"); term_set_position(16, 10) ; term_print("F2 to change display mode") ; term_εet_position(17, 10); term_print("F10 to terminate"); } /* end of show_front_panel */ <r~ MAINTEST.C Wednesday, October 2, 1991 4:25 pm Page 8 /* convert complex value (real and imag) to vector (magnitude and phase) */ vector complex_to_vector(complex eval) { vector ret_val; /* compute magnitude */ /* use multiply times self instead of pow function */ ret_val.magnitude = sqrt((eval.real * eval.real) + (eval.imag * eval.imag)); /* compute phase angle */ if (eval.real == 0.0) ret_val.phase = 0.0; else ret_val.phase = atan( eval.imag / eval.real) ; return(ret_val) ; } /* end of complex_to_vector */ /* this delay routine is target specific */ void delay(unsigned int count) { unsigned int i, j, k; for (k=l; k<=count; k++) { for (i=0; i<1000; i++) { j = } ) ) /* end of delay */ void delay_to_settle() { delay(20) ; ) * * J-? APPENDIX k /'* Generated by symtran.exe $Revision: 1.5 $ */ #include "sprocdef.h" sproc_code_space_type yhpdual_code ; sproc_control_space_type yhpdual_control ; before_volatile struct { sdata _reserved_0000 sdata _reserved_0001 sdata _reserved_0002 sdata _reserved_0003 sdata _reserved_0004 sdata _reserved_0005 sdata _reserved_0006 sdata _reserved_0007 sdata _reserved_0008 sdata _reserved_0009 sdata _reserved_0010 sdata _reserved_0011 sdata _reserved_0012 sdata _reserved_0013 sdata _reserved_0014 sdata _reserved_0015 sdata _reserved_0016 sdata _reserved_0017 sdata _reserved_0018 sdata _reserved_0019 sdata _reserved_0020 sdata _reserved_0021 sdata _reserved_0022 sdata _reserved_0023 sdata _reserved_0024 sdata _reserved_0025 sdata mag_l; sdata _reserved_0026; sdata rdone_l; sdata raw_ina_l; sdata raw_inb_l; sdata capture_l; sdata _reserved_0027; sdata filt_ina__l; sdata filt_inb_l; sdata _reserved_0028 sdata _reserved_0029 sdata _reserved_0030 sdata _reserved_0031 sdata _reserved_0032 sdata _reserved_0033 sdata _reserved_0034 sdata _reserved_0035 sdata _reserved_0036 sdata _reserved_0037 sdata _reserved_0038 sdata _reserved_0039 sdata _reserved_0040 sdata _reserved_0041 sdata _reserved_0042 sdata _reserved_0043 sdata _reserved_0044 sdata _reserved_00 5 sdata _reserved_0046[21; sdata reserved 0047; K 'l sdata _reserved__0052[4] ; /* 0842 V struct { sdata _reserved_0053; sdata _reserved_0054; sdata _reserved_0055; sdata _reserved_0056; sdata _reserved_0057; sdata _reserved_0058; sdata _reserved_0059; sdata _reserved_0060; sdata _reserved_0061; sdata _reserved_0062; sdata _reserved_0063; sdata _reserved_0064; } _reserved_0065; struct { sdata _reserved_0066; sdata _reserved_0067[17] ; } _reserved_0068; struct { sdata _reserved__0069; /* 0864 */ } _reserved_0070; struct { sdata _reserved__0071; sdata _reserved__0072[17] ; } _reserved_0073; struct { sdata _reserved_0074? } _reserved_0075; struct { sdata _reserved_0076; sdata _reserved_0077 } _reserved_0078; struct { sdata _reserved_0079; /* 087a V struct { sdata _reserved_0080; sdata _reserved_0081; sdata _reserved_0082; sdata _reserved_0083; sdata _reserved_0084; sdata _reserved_0085; sdata _reserved_0086; sdata _reserved_0087; sdata _reserved_0088; sdata _reserved_0089; } _reserved_0090; struct { sdata _reserved__0091; sdata _reserved_0092; sdata _reserved_O093; sdata _reserved_0094; sdata _reserved_0095; sdata _reserved_0096; sdata _reserved_0097; sdata _reserved_0098; sdata _reserved_0099; sdata _reserved_0100; } _reserved_0101; } _reserved_0102; struct { K-3. sdata reserved_0103; /* 088f V sdata outvectorl[128] sdata outvector2[128] /* 0892 m */ } raw; /* 0912 m */ struct { % sdata _reserved_0107; struct { /* 0992 */ sdata __reserved 0108; sdata _reserved 0109; sdata _reserved 0110; sdata _reserved 0111; sdata _reserved 0112; sdata _reserved 0113; sdata __reserved 0114; sdata _reserved 0115; sdata ^ reserved 0116; sdata _reserved 0117; } _reserved_0118; struct { sdata _reserved_ 0119; sdata _reserved 0120; sdata _reserved 0121; sdata _reserved 0122; sdata _reserved_ 0123; sdata _reserved_ 0124; sdata _reserved_ 0125; sdata _reserved 0126; sdata _reserved_ 0127; sdata _reserved_0128; } _reserved_0129; } _reserved_0130; struct { sdata _reserved_0131; } _reserved_0132; /* 09a7 struct { sdata _reserved_0133; sdata outvectorl[128] /* 09a8 */ sdata outvector2[128] /* 09a9 m */ ) filtered; /* 0a29 */ struct { sdata _reserved_0134; } _reserved_0135; /* 0aa9 */ struct { sdata _reserved_0136; sdata outvector[128] ; /* Oaaa */ } magnitud; /* Oaab m */ after_volatile yhpdual; k- 3 APPENDIX L /* Generated by symtran.exe $Revision: 1.5 $ */ #include "sprocdef.h" extern sproc_code_space_type yhpdual_ extern sproc_control_space_type yhpdual extern before_volatile struct { sdata _reserved_0000, sdata _reserved_0001; sdata _reserved_0002, sdata _reserved_0003 sdata _reserved_0004 sdata _reserved_0005] sdata _reserved_0006; sdata _reserved_0007 sdata _reserved_0008, sdata _reserved_0009; sdata _reserved_0010, sdata _reserved_0011; sdata _reserved_0012 sdata _reserved_0013, sdata _reserved_0014 sdata _reserved_0015, sdata _reserved_0016ι sdata _reserved_0017 sdata _reserved_0018 sdata _reserved_0019 sdata _reserved_0020; sdata _reserved_0021ι sdata _reserved_0022 sdata _reserved_0023, sdata _reserved_0024 sdata _reserved_0025 sdata mag_l; sdata _reserved_0026; sdata rdone_l; sdata raw_ina_l; sdata raw_inb_l; sdata capture_l; sdata _reserved_0027; sdata filt_ina_l; sdata filt_inb_l; sdata _reserved_0028; sdata _reserved_0029ι sdata _reserved_0030; sdata _reserved_0031; sdata _reserved_0032, sdata _reserved_0033 sdata _reserved_0034 sdata _reserved_0035 sdata _reserved_0036; sdata _reserved_0037 sdata _reserved_0038 sdata _reserved_0039; sdata reserved 0040; - 1 sdata _reserved_004l; sdata _reserved_00 2; sdata _reserved_0043; sdata _reserved_0044; sdata _reserved_0045; sdata _reserved_0046[2] ; sdata _reserved_00 7; sdata _reserved_0052[4] ; struct { sdata _reserved_0053; sdata _reserved_0054; sdata _reserved_0055; sdata _reserved_0056; sdata _reserved_0057; sdata _reserved_0058; sdata _reserved_0059; sdata _reserved_0060; sdata _reserved_0061; sdata _reserved_0062; sdata _reserved_0063; sdata _reserved_0064; } _reserved_0065; struct { sdata _reserved_0066; sdata _reserved_0067[17] ; } _reserved_0068; struct { sdata _reserved_0069; /* 0864 } _reserved_0070; struct { sdata _reserved_0071; /* 0865 */ sdata _reserved_0072[17] ; /* 0866 */ } _reserved_0073; struct { sdata _reserved_0074; /* 0877 } _reserved_0075; struct { sdata _reserved_0076; /* 0878 */ sdata _reserved_0077; /* 0879 */ } _reserved_0078; struct { sdata _reserved_0079; /* 087a */ struct { sdata _reserved_0080; /* 087b */ sdata _reserved_0081 /* 087c */ sdata _reserved_0082; /* 087d */ sdata _reserved_0083; /* 087e */ sdata _reserved_0084; /* 087f */ ' sdata _reserved_0085; /* 0880 */ sdata _reserved_0086; /* 0881 */ sdata _reserved_0087; /* 0882 */ sdata _reserved_0088; /* 0883 */ sdata _reserved_0089 /* 0884 */ } __reserved_0090; 1- 2. struct { sdata _reserved_0091; sdata _reserved_0092; sdata _reserved_0093; sdata _reserved_0094; sdata _reserved_0095; sdata __reserved_0096; sdata _reserved_0097; sdata _reserved_0098; sdata _reserved_0099; sdata _reserved_0100; } _reserved_0101; } _reserved_0102; struct { sdata _reserved 0103; sdata outvectorl[128] ; sdata outvector2[128] ; ] raw; struct { sdata _reserved_0107; /* 0992 struct { sdata _reserved_0108; /* 0993 */ sdata _reserved_0109; /* 0994 */ sdata _reserved_0110; /* 0995 sdata _reserved_0111; V /* 0996 sdata _reserved_0112; V /* 0997 */ sdata _reserved_0113; /* 0998 sdata _reserved_0H4; */ /* 0999 */ sdata _reserved_0115; /* 099a */ sdata _reserved_0116; /* 099b */ sdata _reserved_0117; /* 099c */ } __reserved_0118; struct { sdata _reserved_0119; /* 099d */ sdata _reserved_0l20; /* 099e */ sdata _reserved_0121; /* 099f */ sdata _reserved_0122; /* 09a0 */ sdata _reserved_0123; /* 09al */ sdata _reserved_0124; /* 09a2 */ sdata _reserved_0125; /* 09a3 */ sdata _reserved_0126; /* 09a4 */ sdata _reserved_0127; /* 09a5 */ sdata _reserved_0128; /* 09a6 */ } _reserved_0129; } _reserved_0130; struct { sdata _reserved_0l31; /* 09a7 */ } _reserved_0132; struct { sdata _reserved_0133; /* 09a8 */ sdata outvectorl[128]; /* 09a9 m */ sdata outvector2[128] ; /* 0a29 m */ } filtered; struct { sdata _reserved_0134; /* 0aa9 */ } _reserved_0135; struct { sdata _reserved_0136; /* Oaaa */ sdata outvector[128] ; /* Oaab m */ } magnitud; L " 3 ) after volatile yhpdual; #define YHPDUAL_clO 0X000014 #define YHPDUAL_cll 0X000015 idefine YHPDUAL_cl2 0X000016 #define YHPDUAL_cl3 0X000017 #define YHPDUAL_no_cl OxFFFFFF fdefine YHPDUAL_no_trigger OxFFFFFF #define YHPDUAL_portO 0X000000 Idefine YHPDUAL__portl 0X000001 idefine YHPDUAL_port2 0x000002 fdefine YHPDUAL_port3 0X000003 #define YHPDUAL_genO 0X000004 fdefine YHPDUAL_genl 0X000005 fdefine YHPDUAL_gen2 0x000006 fdefine YHPDUAL_gen3 0x000007 fdefine YHPDUAL_gen4 0X000008 fdefins YHPDUAL_gen9 OXOOOOOD fdefine YHPDUAL_genlO 0X00000E fdefine YHPDUAL_genll 0X00000F fdefine YHPDUAL_genl2 0x000010 fdefine YHPDUAL_genl3 0X000011 fdefine YHPDUAL_genl4 0X000012 fdefine YHPDUAL_genl5 0X000013 fdefine YHPDUAL_w2 0X000000 fdefine YHPDUAL_wl6 0x000001 fdefine YHPDUAL_wl2 0X000002 fde ine YHPDUAL_w8 0X000003 fdefine YHPDUAL_lsb 0X000000 fdefine YHPDUAL msb 0X000001 fdefine YHPDUAL_short 0X000001 fdefine YHPDUAL_long 0X000000 fdefine YHPDUAL_on 0x000001 fdefine YHPDUAL_off 0X000000 fdefine YHPDUAL_default OxFFFFFF fdefine YHPDUAL_intern 0X000001 fdefine YHPDUAL_extern 0X000000 fdefine YHPDUAL_port_0_mask 0X000001 define YHPDUAL_port_l_mask 0X000002 fdefine YHPDUAL_port_2_mask 0X000004 fdefine YHPDUAL_port_3_mask 0X000008 fdefine YHPDUAL_gen_0_mask 0x000010 fdefine YHPDUAL_gen_l_mask 0X000020 fdefine YHPDUAL_gen_2_mask 0X000040 fdefine YHPDUAL_gen_3_mask 0X000080 fdefinG YIIPDUΛL_gen_4_mask 0x000100 fdefine YHPDUAL_gen_5_mask 0X000200 fdefine YHPDUAL_gen_6_mask 0X000400 fdefine YHPDUAL_gen_7_mask 0X000800 fdefine YHPDUAL_gen_8_maεk 0X001000 fdefine YHPDUAL_gen_9_mask 0X002000 fdefine YHPDUAL_gen_10_mask 0X004000 fdefine YHPDUAL_gen_ll_mask 0X008000 fdefine YHPDUAL_gen_12_mask 0X010000 fdefine YHPDUAL_gen_13_mask 0X020000 fdefine YHPDUAL_gen_14_mask 0x040000 fdefine YHPDUAL_gen_15_mask 0X080000 fdefine YHPDUAL_compute_0_mask 0X100000 L- fdefine YHPDUAL_compute_l_mask 0x200000 fdefine YHPDUAL_compute_2_mask 0X400000 fdefine YHPDUAL_compute_3_mask 0X800000 fdefine YHPDUAL_gpio_0 0x000000 fdefine YHPDUAL_gpio_l 0X000001 fdefine YHPDUAL_gpio_2 0X000002 fdefine YHPDUAL_gpio_3 0X000003 fdefine YHPDUAL_rts_0 0X000000 fdefine YHPDUAL_rts_l 0X000001 fdefine YHPDUAL_rts_2 0X000002 fdefine YHPDUAL_rts_3 0x000003 fdefine YHPDUAL_inlDPεubr 0X000000 fdefine YHPDUAL_inlDPrate 0X000000 fdefine YHPDUAL_inlDPtrigger OxFFFFFF fdefine YHPDUAL_adcinlDPsubr OxFFFFFF fdefine YHPDUAL_adcinlDPtrigger 0X000000 fdefine YHPDUAL_adcinlDPrate 0X000B72 fdefine YHPDUAL_adcinlDPconfig 0x000015 fdefine YHPDUAL_adcinlDPcompute 0x000014 fdefine YHPDUAL_adcinlDfifo_size 0x000002 fdefine YHPDUAL_adcinlDbuf_size 0x000001 fdefina YHPDUAL_mult2DPsubr OxFFFFFF fdefine YHPDUAL_dacoutlDPdest 0x000002 fdefine YHPDUAL_dacoutlDPtrigger OxFFFFFF fdefine YHPDUAL_dacoutlDPconfig 0x000005 fdefine YHPDUAL_dacoutlDfifo_size 0x000004 fdefine YHPDUAL_dacoutlDbuf_size 0x000001 fdefine YHPDUAL_mult5DPsubr OxFFFFFF fdefine YHPDUAL_scaler2DPsubr OxFFFFFF fdefine YHPDUAL_scaler2DPshift OxFFFFFδ fdefine YHPDUAL_intlDPsubr OxFFFFFF fdefine YHPDUAL_scalerlDPsubr OxFFFFFF fdefine YHPDUAL_scalerlDPshift OxFFFFFδ fdefine YHPDUAL_int2DPsubr OxFFFFFF fdefine YHPDUAL_hlim2DPsubr OxFFFFFF fdefine YHPDUAL_hlim2DPlower 0X866667 fdefine YHPDUAL_hlim2DPupper 0x799999 fdefine YHPDUAL_mult4DPsubr OxFFFFFF fdefine YHPDUAL_filt2DfilterllDPsubr OxFFFFFF fdefine YHPDUAL_filt2DfilterllDPbO OX00003E fdefine YHPDUAL_filt2DfilterllDPbl 0X00007D fdefine YHPDUAL_filt2DfilterllDPb2 0X00003E fdefine YHPDUAL_filt2DfilterllDPal 0X7FC083 fdefine YHPDUAL_filt2DfilterllDPa2 0XC03D7E fdefine YHPDUAL_filt2Dfilterl2DPsubr OxFFFFFF fdefine YHPDUAL_filt2Dfilterl2DPbO 0X000053 fdefine YHPDUAL_filt2Dfilterl2DPbl 0X0000A7 fdefine YHPDUAL_filt2Dfilterl2DPb2 0x000053 fdefine YHPDUAL_filt2Dfilterl2DPal 0X7F6B44 fdefine YHPDUAL_filt2Dfilterl2DPa2 0XC09410 fdefine YHPDUAL_hlimlDPsubr OxFFFFFF fdefine YHPDUAL_hlimlDPlower 0X866667 fdefine YHPDUAL_hlimlDPupper 0x799999 fdefine YHPDUAL_mult6DPsubr OxFFFFFF fdefine YHPDUAL mult3DPsubr OxFFFFFF 1-5 fde ine YHPDUAL_rawDPsubr OxFFFFFF fdefine YHPDUAL_rawDPlength 0X000080 fdefine YHPDUAL_sumlDPsubr O FFFFFF fdefine YHPDUAL_filtlDfilterllDPsubr OxFFFFFF fdefine YHPDUAL_filtlDfilterllDPbO 0X00003E fdefine YHPDUAL_filtlDfilterllDPbl 0X00007D fdefine YHPDUAL_filtlDfilterllDPb2 0X00003E fdefine YHPDUAL_filtlDfilterllDPal 0X7FC083 fdefine YHPDUAL_filtlDfilterllDPa2 0XC03D7E fdefine YHPDUAL_filtIDfilter12DPsubr OxFFFFFF fdefine YHPDUAL_filtlDfilterl2DPbO 0x000053 fdefine YHPDUAL_filtlDfilterl2DPbl 0X0000A7 fdefine YHPDUAL_filtlDfilterl2DPb2 0x000053 fdefine YHPDUAL_filtlDfilterl2DPal 0X7F6B44 fdefine YHPDUAL_filtlDfilter12DPa2 0XC09410 fdefine YHPDUAL_amplDPsubr OxFFFFFF fdefine YHPDUAL_amplDPgain OxCOOOOO fdefine YHPDUAL_dacout2DPdest 0X000003 fdefine YHPDUAL_dacout2DPtrigger OxFFFFFF fdefine YHPDUAL_dacout2DPconfig 0X000005 fdefine YHPDUAL_dacout2Dfifo_size 0x000004 fdefine YHPDUAL_dacout2Dbuf_size 0X000001 fdefine YHPDUAL_filteredDPsubr O FFFFFF fdefine YHPDUAL_filteredDPlength 0x000080 fdefine YHPDUAL_raw_doneDPsubr 0X000000 fdefine YHPDUAL_filt_donDPsubr 0x000000 fdefine YHPDUAL_sqrlDPsubr OxFFFFFF fdefine YHPDUAL sum2DPsubr O FFFFFF tdeϊiiiώ YHPDUAL_return 0X000000 fdefine YHPDUAL_bO 0X000001 fdefine YHPDUAL_bl 0X000002 fdefine YHPDUAL_b2 0x000003 fdefine YHPDUAL_al 0X000004 fdefine YHPDUAL_a2 0X000005 fdefine YHPDUAL_xl 0x000006 fdefine YHPDUAL_X2 0X000007 fdefine YHPDUAL_yl 0X000008 fdefine YHPDUAL_y2 0X000009 - G APPENDIX Α. SUBSTITUTE SHEET M-1 // alloctab.cxx // functions for alloc_table class //T. Montlick // 10/31/89 /* source code control: */ static char SccsIDQ = "@(#)aUoctab.cxxl.56 10/7/91"; #include "alloctab.hxx" #endif luuiniwiiuinniuuiiuiiunnuuiiiMiHiiiniuHHiHnuiiiiiiiii II alloc_table::alloc_table // Constructor. alloc_table.:alloc_table():// initializer list for all arrays and hash tables indices(SZ), name_table(SZ), sϊzes(SZ){next_index = 0;} II alloc_table::~alloc_table // Destructor. alloc_table: :~alloc_table0 {} II alloc_table "allocate // Allocate an element of the given size. BOOLEANalloc_table::aIlocate(string&name, expr* size, int* index) { int oldval; string*new_string; // make sure name not already present if (indices.find(name, &oldval)) return FALSE; // store name in hash table with next storage index indices.add(name, next_index); *index = next_index; // save this size expression sizes[next_index] = size; // create a copy of the name string, and enter it into name table -2 new_string = new string(name); name_table[ (int) next_index] = new_string; // advance index next_index++; return TRUE;} II alloc_tablε : :index_to_location // Return the location of the given index, -1 if no such index. int alloc_table::index_to_location(int index) { long loc_so_far = 0, next_size; if ( (indcx>sizes.size()) II (index<0) ) return -1; for (int i=0; i<index; i++){ // null sized defaults to 1 if (sizes[i] == 0) next_size = 1; else next_size = int_value(sizes[i]); // if size is not known (evaluates to 0), then make it 1 if (next_size == 0) next_size = 1 ; loc_so_far += next_size;} return loc_so_far;} // alloc_table::location_to_index // Return the index of the given location, -1 if no such location. int alloc_table::location_to_index(int location)! long loc_so_far = 0, next_size; for (int i=0; i<sizes.size(); i++){ // null sized defaults to 1 if (sizes[i] == 0) next_size = 1 ; else next_size = int_value(sizes[i]); // if size is not known (evaluates to 0), then make it 1 if (next_size == 0) next_size = 1; M-3 if ( (location >= loc_so_far) && (location <= (loc_so_far + next_size - 1)) ) return i loc_so_far += next_size; } return (-1);} II alloc_tabIe::fmd // Find the given name in the table. Return the index and size. // Returns FALSE if not in table. BOOLEANaUoc table::find(string&name, int* index_ptr, expr** size){ if (indices.find(name, index_ptr)){ *size = sizes[*index_ptr]; return TRUE;} return FALSE;} II alIoc_table:name_at_index // Returns pointer to name string for this index. string*alloc_table::name_at_index(int index) { if (index >= 0){ return name_table[index];} else return NULL;} If alloc_table:name_at_location // Returns pointer to name string for this location. string*alloc_table::name_at_location(int location) { int index; index = location_to_index(location); if (index >= 0){ return name_table[index];} else return NULL;} II alIoc_table::alloc_size // Return the allocated size of the whole table. M-4 int alloc_table::alloc_size(){ long loc_so_far = 0, next_size; for (int i=0; i<sizes.size(); i++){ // null sized defaults to 1 if (sizes[i] == 0) next_size = 1; else next_size = int_value(sizes[i]); // if size is not known (evaluates to 0), then make it 1 if (next_size == 0) next_size = 1; loc_so_far += next_size;} return loc_so_far; } II alloc_table::set_size // Set the given size for element at given index. void alloc_table::set_size(int index, expr* size){ // save this size expression (NULL = size of 1) if (!size) size = int_to_expr((long) 1); sizes[index] = size;} II alloc_table::get_size // Get the given size for element at given index. expr*alloc_table::get_size(int index) { return sizes[index];} II alloc_table::all_sizes_set // Returns TRUE if all sizes have been set. BOOLEANalloc_table::all_sizes_set(){ if (sizes.sizeO < next_index) return FALSE; else{ for (int i=0; i<next_index; i++) if (!sizes[i]) return FALSE; } M-5 return TRUE;} // alloctab.hxx // alloc_table class II Υ. Montlick // 10/31/89 /* source code control: @(#)alloctab.hxxl.56 10/7/91 */ #define ALLOC_TABLE_DEF #include "expr_arr.hxx" #endϊf #ifndef INT_HASH_DEF #include "int_hash.hxx" #endif #ifndef STRG_ARRAY_DEF #include "strg_arr.hxx" #endif #ifdef SZ #undef SZ #endif #defineSZ 4 /* default array and hash table size */ class instance; // the following neg. number signals an undefined address #define NO_ADDRESS-l // class to support allocation of named elements, which can be arrays class alloc_table{ intjiashindices; // storage name to index strg_arrayname_table; // index to name expr_arraysizes; // expr for size of each storage name int next_index;// next available storage index public: alloc ableO; ~alloc_table(); int ϊndex_to_Iocation(int index) ; int location_to_index(int location) ; BOOLEANallocate(string& name, expr* size, int* index); BOOLEANfind(string&name, int* index, expr** size); string* name_at_index(int index); string* name_at_location(ϊnt location); int size() { return next_index; }; }; // array.cxx // array class functions // Terry Montlick // 5/9/89 /* source code control: */ static char SccsID[] = "@(#)array.cxxl.56 10/7/91"; #include "array.hxx" IIarrayclass II array: :array // Constructor. // Allocate an array using the minimum size and 0 initial elements. array::array(){ p = new elem [alloc_sz=ARRAY_SIZE]; sz = 0;} II array::array // Constructor with size. // Allocate an array with the given size. array::array(int size){ int k; p = new elem [alloc_sz=size]; sz = size; for (k=0; k<sz; k++) p[k] = NULL;} II array-array // Constructor with array as argument. array::array(array& a){ int k; -7 // create array storage, getting size from source array p = new elem [alloc_sz=a.sizeO]; sz = alloc_sz; // copy array elements for (k=0; k<sz; k++) p[k3 = a[k];} iiummmumiiiiπiiiiiummimuitiiiiiimiimiπiiiimimiim! II array::~array //Destructor. // Deallocate the array. niiiiiimiittiimuiuitiuminiiuimmmmiiπmuimmuiiiiiM array "-array (){ delete[alloc_sz] p;} II array: :operator D // Access elements of our array class. // Automatically grows size of array to accomodate higher indices. elem&array::operator Q (int i)// return or set element, auto-extending array{ int j, k; // enlarge allocated size if access is beyond current bounds if (i >= alIoc_sz){ j = aUoc_sz + ARRAY_SIZE; if (i >=j)j =ϊ+l; elem* pO = new elem [j]; for (k=0; k<alloc_sz; k++) p0[k] = p[k]; delete[alloc_sz] p; P =ρ0; alloc_sz =j;} // enlarge max index if beyond current bounds if (i >= sz){ for (k=sz; k<i+l; k++) p[k] = NULL; sz = i + I;} if (ϊ >= 0) return p[i];} mnu imui iuiniiiini um iui n mmi ni n II array: :operator = // Assigment of array. void array-operator = (array& a){ M-8 for (int i=0; i<a.size(); i++) (*this)[i]=a[i];} II array: :size // Return or sets the size of the array. int& array: :size(){ return sz;} II array-find // Finds an element within the array. // Returns the array index or -1 if element couldn't be found. int array: :find(elem pO)// find the given element{ int i = 0; while ((i < sz) && (p[i] != pO)) i++; if (i < sz) return i; else return -1; } II array: :insert // Inserts at the given element from the array, shifting this and // higher elements up by 1. void array ::insert(inti){ if((i>=0)&&(i<sz)){ for (int j=sz-l; j>=i; j— ) this->operator[](j+l) = this->operator[](j); this->operatorO(i) = NULL; }} II array::remove // Deletes the given element from the array, shifting higher elements //down by 1. void array::remove(int i)// delete at given pointer position} if((i>=0)&&(i<sz)){ for (int j=i; j<sz- 1 ; j++) this->operator[](j) = this->operator[](j+l); this->operator[](sz-l) = NULL; sz-; M-9 }} iiiiimππfiiπiiiHπm iiuiiiiiiπiiiiiiiiiπiiii iiiiiiiπiiiπi II array-clear II Clear the array. iMiιιιmιmιιιuιuιmιmmmnuιιιιnιmuιtmιmιιmιιuniHiιι void array::clear(){ sz = 0;} II array::append // Appends the element to the end of the array, extending it by 1. void array::append(elem p0){ this->operatorQ(this->sz) =p0;} II array-append // Appends all the element of another array to the end of this array. array &array::operator+(array& a){ for (int i=0; £<a.sz; i++) append(a[i]); return *this;} // array.hxx // header for array class //T. Montlick // 5/7/89 /* source code control: @(#)array.hxxl.56 10/7/91 */ #define ARRAY_DEF #ifndef STAND ARD_DEF #include "standard.hxx" #endif // Class "array" is a dynamic array which automatically enlarges to // fit any indices. // It has a "delete" function which deletes an element at a particular index // and shifts the higher indices down, and an "insert" which shifts up to // make room for a new element at a particular index. // It also has a "find" function which finds a particular element pointer // and returns its index, else it returns -1. // Arrays of specific types may be created by deriving classes from this class. // chunk size for allocating arrays arrayO; array (int); array (array&); -arrayO; elem&operator[](int);// return or set element, auto-extending array void operator=(array&); int& size(); int find(elem); // find the given element void insert(int); // insert at given element position void remove(int);// delete at given element position void clear(); void append(elem); array &operator+(array&) ; array &operator+=(array& a) {a = *this + a; return *this; } }; // blck_arr.cxx // derived class for block array // Terry Montlick // 10/10/89 /* source code control: */ static char SccsID[] = "@(#)blck_arr.cxxl.56 10/7/91"; #include "blck_arr.hxx" // blck_arr.hxx // header for derived block array class //T. Montlick // 10/10/89 /* source code control: @(#)blck_arr.hxxl.56 10/7/91 */ #define BLOCK_ARRAY_DEF #ifndef ARRAY_DEF #include "array.hxx" #cndif class block; class block_array : public array { public: block*& operator Q (inti) { return (block*&) array::operator[] (i); } int find(block* ptr) { return array::find(ptr); } void append(block* ptr){ array::append( (elem) ptr); } block_array& operator+(block_array& a) { return (block_array&) array: :operator+((array&) a); } block_array& operator+=(block_array& a) {a = *this + a; return *this; } }; // blck_ref.cxx //bIock_ref class //T. Montlick // 11/9/89 /* source code control: */ static char SccsIDG ="@(#)blck_ref.cxxl.56 10/7/91"; #ifndef BLOCK_REF_DEF #include "blck_ref.hxx" #endif #ifndefBLOCK_DEF #include "blockhxx"// so we can call block member functs #endif II arg_set::arg_set //Constructor. arg_set::arg_set(BOOLEAN store_by_name) { // make the appropriate storage structure if (by_name = store_by_name) args.named_args = new expr_hash(SZ) ; * else args.positional_args = new expr_array(SZ); count = 0;} II arg_set::~arg_set // Destructor. arg_set::~arg_setO{ if (by_name) delete args.named_args; else M-12 delete args.positional_args;} II arg_set::add_posit_expr // Add a positional expression to the argument set. // Returns FALSE if arguments are named, not positional. BOOLEANarg_set::add_posit_expr(expr* e){ int i; if (!by_name){ i = (*args.positional_args).size(); (*args.positional_args)[i] = e; count++; return TRUE;} else return FALSE;} II arg_set::add_named_expr // Add an expression by name to the argument set. // Returns FALSE if arguments are not named, but positional, // or if name already present. BOOLEANarg_set::add_named_expr(string& s, expr* e){ if (by_name) if ((*args.named_args).add_new(s, e)) { count++; return TRUE; } else return FALSE; else return FALSE;} II arg_set::expr_at_name // Look up an expression by name to the argument set. // Returns FALSE if name not found. BOOLEANarg_set::expr_at_name(string& s, expr** e){ if (by_name) return (*args.named_args).find(s, e); M-13 else return FALSE;} mnπiiiHiimuiiiiiiiiπiiimiiiiimmπiiiiiiiriiiiiiiiiϊiiiiiiiii II arg_set::expr_at_position // Look up an expression by position in the argument set. // Returns NULL if not stored by position. iiituimmmumiiimuumuiHiimiuuimiiiiHiiHUimumiiiii expr*arg_set::expr_at_position(int i) { if (!by_name) return (*args.positional_args)[i]; else return (expr*) NULL;} II arg_set::get_expr_hash() expr_hash*arg_set::get_expr_hash(){ return args.named_args;} II arg_set::get_expr_array() expr_array*arg_set::get_expr_array(){ return args.positionaI_args;} II arg__set::size() int arg_set:size(){ return count;} II block_ref::block_ref // Constructor. block_ref::block_ref (string& blk, string& inst, int 1) { values = ports = 0; block iame = new string(blk); instance_name = new string(inst); line_num = 1; block_ptr = (block*) NULL;} II block_ref::~block_ref // Destructor. block_ref : : -blockjref () { // dealocates any classes we point to if (values) delete values; if (ports) delete ports; delete block_name; delete instance_name;} II blockjref: :store_vals // Store an arg_set of values in the block_ref. // Returns FALSE if values already present. BOOLE ANblockjref : :store_vals(arg_set* v) { if (values) return FALSE; values = v; return TRUE;} II block_ref::store_ports // Store an arg_set of ports in the block_ref. // Returns FALSE if ports already present. BOOLE ANblock_ref: :store_ports(arg_set* p) { if (ports) return FALSE; ports = p; return TRUE;} II block_ref : : get_block_info // Get all info on this block reference. /////////////////////////////////////////////////////////////////////////////// void block_ref::get_block_info(string** blk_name, string** inst_name, arg_set** vals, arg_set** prts, int* 1){ *blk_name = block rame; *inst_name = instance_name; *vals = values; M-15 *prts = ports; *l = line_num;} II block_ref::add_connection // Add a connection from one of this block refs outputs to another block // refs input. The index of the other block in this parent block is given, // as well as which input in the block. Finally, the number of our output //is given. void block_ref::add_connection(int blkjndex, intinput_number, int our_output){ int i = blocks_connected_to.sizeO; blocks_connected_to[i] = blkjndex; inputs_connectedJ:o[i] = input_number; our_outputs[i] =our_output;} II block_ref::n_connections // Returns the number of inputs in other block refs that this block ref // connects to. int block_ref::n_connections(){ return blocks_connected_to.size(); } II block_ref::get_connection // Get a connection from one of this block refs outputs to another block // refs input. The index of the other block in this parent block is returned, // as well as which input in the block. Finally, the number of our output // is returned. BOOLEANblock_ref::get_connection(int ϊ, int* blkjndex, int* input_number, int* our_output){ if (ϊ < blocks_connected_to.size()){ *blk_index = blocks_connectedJ:o[i] ; *input_number = inputs_connected_to[i]; *our_output = our_outputs[i]; return TRUE;} else return FALSE;} II block_ref::all jnputs_marked // Return TRUE if all inputs marked by sequencer as having been passed through. // NOTE: if no inputs, then always return TRUE. BOOLEANblock_ref: :all jnputs_marked() { if (block_ptr){ for (int i=0; i<block_ptr->io_table_size(); i++) { if (!block_ptr->io s_output(i)) { if (!input_reached[i]) return FALSE; } } return TRUE;} return FALSE;} II block_ref::io_size // Return number of I/Os for block. int block_ref::io_size(){ if (block_ptr) return block_ptr->io_table_size(); else return 0;} II blockjref: :is_input // Return TRUE if given I/O is input. BOOLEANblock_ref::is jnput(int i) { if (block _ptr) return (!block_pύ»iojs_output(i)); else return FALSE;} II block_ref::parent_wire_for o // Returns index of parent wire for this IO. If no parent, returns -1. int block_ref::parent_wire_for jo(int i){ if (instance _ptr) M-17 return instance_ptr->get_wire jn_parent(i) ; else return -1;} // blckjrefhxx // blockjref class //T. Montlick // 11/9/89 /* source code control: @(#)blck_ref.hxxl.56 10/7/91 */ #define BLOCK_REF_DEF ndef STR GJDEF #include "string.hxx" #end ' ϊf #ifndef EXPR_HASH_DEF #include "exprhash.hxx" #endif #ifndef EXPR_ARRAY_DEF #ϊnclude "expr_arr.hxx" #endif #ifndefINT_ARRAY_DEF #include "int_arr.hxx" #endif #ifndef UmiTYJDEF #include "utility.h" #endϊf #ifdefSZ #undefSZ #endϊf #defineSZ 4 /* default array and hash table size */ class block; class instance; // class to support a set of arguments, specified by either name or position class arg_set{ BOOLEANby ame; // TRUE if args are by name union { expr_array*positional_args;//if args by position expr_hash*named_args;// if args by name } args; int count; // # of entries in arg set public: -18 arg_set(BOOLEAN store j yjiame);// constructor ~arg_set(); // destructor BOOLEANadd_posit_expr(expr*); BOOLEANadd_named_expr(string&, expr*) ; BOOLEANstored_by_name(){ return byj ame; } exprjιash*get_exprjιash(); expr_array*get_expr_array(); BOOLEANexpr αt_name(string& s, expr** e); expr* expr_at position(int i); int size(); }; // class which defines a reference to a block in a hierarchical block class block -ef { string* block ame; // name for block prototype block* block_ptr; // ptr to prototype block string* instance ame; // name for this block instance instance*instance jptr;// ptr to this instance arg_set*values; // symbol and param values arg_set*ports; // port values int line ϊum; // line number of reference int arrayblocks_connected_to^/ input blk refs this blk ref connected to int_arrayinputs_connected_to;// which inputs of above int_arrayour_outputs;// which of our outputs connected int_arrayinput_reached / TRUE when sequencer reaches this input int_arrayloop jo; // TRUE if I/O in feedback loop public: block jref(string& blk, string& inst, int Ijium); -block j * ef(); BOOLE ANstore_vals(arg_set*) ; BOOLEANstorejports(arg_set*); void get loc nfo(string**, string**, arg_set**, arg_set**, int*); void add_connection(int blkjndex, int inputjuimber, int ourjoutput); void set_block_pointer(block* p) { block _ptr = p; } block* get_block_pointer() { return block ptr; } void set jnstance_pointer(instance* p) { instance ptr = p; } instance*getjnstance_pointer() { return instance ptr; } void change jolockjιame(string* name) { blockjiame = name; } string* get jιstance_name() { return instancej ame; } int n_connections(); BOOLEANget_connection(int which, int* blk_index, int* inputjiumber, int* ourjoutput); void mark_input_as_reached(intinp) { input_reached[inp] = TRUE; } BOOLEANis_input_marked(int inp) { return inputjreached[inp]; } BOOLEANall_inputs_marked(); void markJ[oop_io(ϊnt i) { loop_ϊo[i] =TRUE; } BOOLEANis_Ioop_io(int i) { return loop_io[i]; } int io_size(); BOOLEANis_input(int i); int parent_wire_forjo(inti); int get_line_number() { return linej um; } }; //blckhash.cxx // functions for block hash table class //T. Montlick // 9/12/89 /* source code control: */ static char SccsIDQ = "@(#)blckhash.cxxl.56 10/7/91"; #ifndef BLOCKJHASH.DEF #include "blckhash.hxx" #endif // bring in hash functions, customized from our defines #ϊnclude "hash.cxx" // blckhash.hxx // header for block hash table class //T. Montlick // 9/12/89 /* source code control: @(#)blckhash.hxxl.56 10/7/91 */ M-20 #define BLOCK_HASH_DEF class block; // define symbols which make a custom hash table class #ifdef HASH #undef HASH #endif #define HASH block_hash #ifdef HASH_ELEM #undef HASH_ELEM #endif #define HASH_ELEM block jιash_elem #ifdef HASH_LIST #undef HASH_LIST #endif #define HASH_LIST block_hash_list #ifdef VAL_TYPE #undef VAL_TYPE #endif #define VAL_TYPE block* // don't "use pointer", because this will allocate/deallocate storage! #ifdef USE_POINTER #undef USE_POINTER #endif // suppress output stream function #define NO OUTSTREAM #include"hash.hxx" // blckstakcxx // block_stack class functions // Terry Montlick // 10/20/89 /* source code control: */ static char SccsID[] = "@(#)blckstak.cxxl.56 10/7/91"; #include "blckstak.hxx" // blckstak.hxx // header for block stack classes // T. Montlick // 11/20/89 /* source code control: @(#)blckstak.hxxl.56 10/7/91 */ #define BLOCK_STACK_DEF M-21 #ifndef STACK_DEF #include "stack.hxx" #endif class block; class block_stack : public stack{ public: void push(block* ρ){ stack::push(p); } block*pop() { return (block*) stack::ρoρ(); } }; // block xx // functions for block class //T. Montlick // 10/31/89 /* source code control: */ static char SccsIDD ="@(#)block.cxxl.56 10/7/91"; #ifndefBLOCK_DEF #include "block.hxx" #endif #undef DEBUG II block_io::block_io // Constructor. iifiiiiiiiiiiiiiiiiiiiiiiiiiiiriiiiiiiiiifiiiiifiiiiinmiiiimiiiimmiiii block_io::block_ioO {} IIblock_io::~block_io //Destructor. block_io::~block_ioO {} II block_io: :set_ϊo j3ize md_direction // Sets an I/O size, plus direction(input or output) referred to by the // given name. // An expression for the storage size is also passed, the value of // which may not yet be known. // Returns FALSE if the name was not present. M-22 BOOLEANblockjo::setjo_size ιnd_direction(string* name, expr* size, int dir){ int index; expr* old _size; if (!io_table.find(*name, &index, &old_size)) return FALSE; else{ io_table.set >ize(index, size); io_direction [index] = dir; return TRUE; } } /////////////////////////////////////////////////////////////////////////////// // block_chip jo::block_chip_io // Constructor. block_chip jo: :block_chip jo() { portjiumber = trigger_source = port_config = (expr*) NULL; port js Dutput = is port j lock = FALSE; } /////////////////////////////////////////////////////////////////////////////// // block_chip jo::~block_chip jo // Destructor. block_chip jo: :~block_chip jo() { } II block_chip jo::set_asjport // Declare that this block is connected to a serial I/O port. // Returns FALSE if this has already been set. BOOLEAN block_chip jo::set_asjport(expr* portjium, expr* trigger, BOOLEAN is_output, expr* config, expr* entry _size){ is_port_block = TRUE; portjiumber = portjium; trigger _source = trigger; port js Dutput = is_output; port_config = config; port entryjsize = entry_size; return TRUE;} iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiniiniiiiiinmiii II block_chϊp_io::set_compute_line // Set a compute line number for this block. BOOLEAN block_chip_io::set_compute ine(expr* num){ if (trigger source = (expr*) NULL){ trigger_source = num; return TRUE;} else return FALSE;} II block_micro_io: :block_micro_io // Constructor. blockjnicro_ϊo::block_micro_ioO {} //block_micro_io::~block nicro_io // Destructor. iiiiiiiiiiiiiiiiiiiriiiiiiiiririfiiiiiiiiiiiiiifiiriiinmiimifiiiiiiiiiiiii block_micro_io::~block_micro_io() {} II block_storage::block_storage // Constructor. block_storage::block_storage() : storage_init_val(SZ), storage ine_numbers(SZ), top_level storjϊne(SZ) {} If block jstorage::~block_storage //Destructor. block_storage::~block_storage() {} -24 // block_storage::add_storagejnit // Associates a storage index with an expression which supplies the // initialization value. /////////////////////////////////////////////////////////////////////////////// void block torage::add_storage jnit(int index, expr* expr ptr) { storage jnit_val[index] = expr jptr; // record line number of initialization for error msg purposes storage jinejiumbers [index] = line; // also record top level line # if nested include file if (the jile_stack.size()) top jevel _stor _line[index] = the j le_stack.line_at_file jevel(O) ; else top jeve stor jine[index] = line;} II // Constructor. block_zone::block ione() { timezonejiame = timezonejrate = (expr*) NULL; } II block ζone::~block_zone // Destructor. block_zone : : -block sone() { } II block_zone::set imezone // Set a timezone expression for this block when it is parsed, optionally // declaring it globally. // The name is an expression which evaluates to a name string. // Returns FALSE if the timezone has already been set. BOOLEANblock_zone::set_timezone(expr* name, expr* rate){ if (Itimezone jiame) { timezonejiame = name; timezone_rate = rate; return TRUE;} M-25 else{ other _error("BLK023", "A time zone for this block has already been declared."); return FALSE; }} II block_zone::get_timezone // Get expressions for the timezone name and rate. // Returns FALSE if no timezone defined. BOOLEANblock_zone::getjimezone(expr** name, expr** rate){ if (timezone_name) { *name = timezonejiame; *rate = timezonejrate; return TRUE;} else return FALSE;} II block_virtual::block_virtual // Constructor. block_virtual::block_virtualO{ is_virtual_io lock = FALSE;} II block_virtual::~block_virtual // Destructor. block_virtual::~block_virtual() 0 II block_v tual::set_virtual_storage // Set storage element i as virtual, passing the path string and instance which // provides the context for that path to the physical storage location to use.// void block_virtuaI::set_virtual_storage(inti, string* path, instance* path_inst){ virt_storagejpath[i] =path; ϊs_virtual_storage[i] = TRUE; virt_stor_path jnst[i] = path_inst;} M-26 II block_rate_change: :block_rate_change // Constructor. block jrate_change::block_rate_change(){ rate_change_block = FALSE;} II block_rate_change: :~block_rate_change // Destructor. block_rate_change::~blockjrate_change() { } II block_rate_change: :set_decimating // Record the fact that this block decimates, producing a new sample rate out. // Passed the decimation ratio. /////////////////////////////////////////////////////////////////////////////// void block_rate_change::set_decimating(expr* ratio) { decimation = TRUE; change j"atio = ratio; rate_change_block = TRUE; } II blockj-ate_change: :se jnterpolating // Record the fact that this block interpolates, producing a new sample rate // out. // Passed the decimation ratio. void block_rate_change::setjnterpolating(expr* ratio) { decimation = FALSE; change j-atio = ratio; rate_change lock = TRUE; } /////////////////////////////////////////////////////////////////////////////// // blockjsubroutine: :block_subroutine // Constructor. block_subroutine: :block _subroutine() { subr_block = call j)lock = subr_form = M-27 subr nst_made = FALSE; n_times :alled = 0; subr_inst_ptr = (instance*) NULL;} //block_subroutine::~blockj3ubroutine // Destructor. block_subroutine::~block_subroutine() { } II block::block // Constructor. block::block():// initializer list for all arrays and hash tables symbol_val_table(SZ), alias_name_table(SZ), label_sequence(SZ), label_offset(SZ){ absolute _origin = is_instantiated = is_indϊvisible = in_hierarchy = FALSE; override_table = (expr_hash*) NULL; instancejptr = (instance*) NULL; n_params = element jiumber = 0; ljndex = 0; phantom = init = FALSE; block ιas_Ioops = FALSE; variant_count = 0; // record input file which this block was declared in filenam = in_filename 3tring; // also record starting line # for block starting_line = line; } II block::-block // Destructor. M-28 block: :~block() { } II block::set_block_name // Sets the prototype name for this block. // Returns FALSE if a block by this name already exists. BOOLEANblock::set_blockjιame(string* name){ block*block_ptr; string subr jiame; string call jiame; // form name of subr body block, which we need subrjiame = subrjiame + *name + SUBR SUFFIX; call_name = calljiame + *name + CALL SUFFIX; // if this is subroutine call or body, append special suffixes if (is_subr_block()){ // this is subr block, so mark in-line form if exists yet if (prototype 3locks.find(*name, &blockjptr)) block jptr->set 5ubr_form() ; // change our name to subroutine name *name = *name + SUBR_SUFFIX;} else if (is_call_block()){ // this is subr call block, so mark in-line form if exists yet if (prototype_blocks.find(*name, &blockjptr)) blockjptr->set 5ubr_form(); // change our name to call name *name = *name + CALL_SUFFIX;} else{ // block is in-line, so see if subr or call form exists if (prototype_blocks.find(subr_name, &blockjptr) II prototype )locks.find(call_name, &blockjptr)) set 5ubr_form(); // it does, so record that subr exists} // set name string for this block blockjiame = *name; // add this block to list of prototypes, but make sure not already there if (prototype j)locks.find(*name, &blockjptr)) return FALSE; // store name in hash table with pointer to us M-29 > prototype ιlocks.add(*name, &(*this)) ; return TRUE;} If block::get j lock iame // Returns the name of this block. ////////////////////////////^^^^^^ string*block::get_bIock_name(){ return &block_name; } imiiunmninunmmuuHiuimmnummmiuimiiiwmmtii II block::add_io_name // Adds a new I/O offset referred to by the given name. // Returns as an argument the offset (next sequential) // which was allocated. //Returns FALSE if the name was already present BOOLEANblock::add_io_name(string* name, int* offset, BOOLEAN is_micro){ int index; expr* old jsize; if (!io_allσcate(*name, (expr*) NULL, offset)) return EALSE; else{ // set flag for uP interface io_find(*name, &index, &old_size); set_micro_io(index, isjnicro); return TRUE; }} II block::addjparam_name // Adds a new parameter to the parameter interface for this block. // Returns as an argument the index (next sequential) // which was allocated. // Parameters precede symbols. // Returns FALSE if the name was already present BOOLEANblock::addjparamjιame(string* name, int* index) { // count as a new parameter n params++; return param_tabIe.allocate(*name, (expr*) NULL, index);} // block: :add_symbol_name // Adds a new symbol to this block. // Returns as an argument the index (next sequential) // which was allocated. // Returns FALSE if the name was ' already present BOOLEANblock::add 3ymbol_name(string* name, int* index, BOOLEAN is_micro){ BOOLEANstatus; status = param rable.allocate(*name, (expr*) NULL, index); if (status) set jriicro _symbol(*index, is _micro) ; return status;} II block::add_symbol_name // Adds a new symbol to this block, with micro interface state. // Returns as an argument the index (next sequential) // which was allocated. // Returns FALSE if the name was already present. BOOLEANblock::add_symboljιame(string* name, int* index) { return param_table.allocate(*name, (expr*) NULL, index);} /////////////////////////////////////////////////////////////////////////////// // block::add_expressionjιame // Associate an expression with a symbol name. // Returns FALSE if the name was already present. BOOLEANblock::add_expression_name(string* name, expr* exprjptr){ expr* old _expr; // make sure name not already present if (symbol_val jable.find(*name, &old_expr)) return FALSE; // store name in hash table with expression pointer symbol_val_table.add(*name, expr jptr); return TRUE;} II block: :add ιlias_name // Adds a new alias name and associate it with an equivalent name. // Returns FALSE if the name was already present. M-31 BOOLEAi^lock::add_aHas_name(string* new_name, string* equϊv_name){ expr* old expr; string*old_equiv_name; // make sure name not already present if (look ιp_symbol_name(new jiame, &old_expr)) return FALSE; // also look in alias table to make sure not present if (aliasjname_table.find(*new jiame, &old_equiv_name)) return FALSE; // store name in hash table with equivalent name alias jιame_table.add(*new_name, equiv iame) ; return TRUE;} ff block::add_storage_name // Adds a new memory location or locations referred to by the given name. //Returns as an argument the storage index (next sequential) // which was allocated. // An expression for the storage size is also passed, the value of // which may not yet be known. If the size expression is NULL, set a size // of 1. // A storage type character is passed, which sets the type for the storage //location(s). // Also, flags for whether this is a microprocessor interface variable, // and if this storage is variable storage vs. wire storage. // Returns FALSE if the name was already present imiuiiiiimHnniuinuuumuumimuimiinπmumitmiuuu BOOLEAJ^lock::addj5torage_name(string* name, expr* size, int* indexjptr, char type, BOOLEAN isjnicro, BOOLEAN is_variable) { BOOLEANresult; result = storage_allocate(*name, size, indexjptr); if (result) { set_storage_size(*indexjptr, size); set_storage_type(*index_ptr, type); setjrnicro_var(*index ptr, isjnicro) ; set_as_variable(*index_ptr, is_variable); } return result;} ummuniiiMiiiuimuumimmmmiimiiimmimmiummu If block::get 5torage_init // Get storage init value, calling our instance if phantom storage. M-32 expr* block: :get_storage jnit(int index) { int size; if (index < (size = non phantom_storage_table_size())) • return nonjphantom_storage jnit(index); else if (instance jptr) return instance jptr->get jphantom ?torage jnit(index-size) ; else return NULL;} II block: :get_storage_type // Get storage type, calling our instance if phantom storage. char block: :get_storage_type(int index) { int size; if (index < (size = nonjphantom _storage_table_size())) return get jion jphantom_storage jype (index) ; else if (instance_ptr) return instance_ptr->getjphantom_storage_type(index-size); else return NULL;} II block: :storage_table_size // Return size of storage table. int block: :storage_table_size() { int size; size = non_phantom_storage jable_size(); if (instance jptr) size += instance jptr- >phantom_storage_table_size(); return size; } II block: :storage_name_at ndex // Return the name in the storage table at the given index. // Uses instance phantom storage if index is beyond our storage table. string*block::storage_name_atjndex(int index){ int size; if (index < (size = nonjphantom _storage_table_size())) M-33 return nonjphantom jtorage_name_at_index(index) ; else if (instance ptr) return instance jptr->phantom_storage_name_at_index(index-size) ; else return new stringCTNVALID.STORAGE"); } II block::storage_offset_at jndex // Return the storage offset in the storage table at the given index. // Uses instance phantom storage if index is beyond our storage table. int block-storage rjffset_at_index(int index) { int size; if (index < (size = nonjphantom_storage_table_size())) return storage_index_to_location(index); else if (instancejptr) return instance _p tr->phantom_storage 3ffsct_at jndex(index-size) ; else return 0;} luiiiii inπuπππiiiHiiiπiiii πiiiiiiiiiiiiiiiiiiirπirπiiii If block::storage_entry_size // Return the storage entry size in the storage table for the given index. // Uses instance phantom storage if index is beyond our storage table. expr* block::storage_entry_size(int index) { int size; if (index < (size = non_phantomjstorage_table_size())) return non_phantom 5torage_entry 3ize(index); else if (instancejptr) return instance jptr->phantom_storage_entry_size(index-size) ; else return NULL;} iiiiiiiiiiiiiiiiiiiriiiiiiiifiifiiirifiiiiiiiiifiiiiiiiiiiiiiiiiiiiiiiifiiiiiri II block::look_up_storage_name // Find the given name in the storage table. // Returns TRUE if found, along with the storage index. // Also checks any phantom storage, if instance present. BOOLEANblock::look_up 5toragejιame(string* s, int* index) { expr*dummy_size; if (storage_find(*s, index, &dummy_size)) return TRUE; else if (instancejptr) return instancejptr->look_upjphantom_storagejιame(s, index); else return FALSE;} II block: :look_upjparam jiame // Find the given name in the parameter table. // Returns TRUE if found, along with the index. BOOLEANblock::lookjαpjparamjιame(string s, int* index) { expr* dummy _size ; return param_table.find(s, index, &dummy_size);} II block: :look_up_symbol jiame // Find the given name in the symbol table. // Returns TRUE if found, along with the index. BOOLEANblock::look_up 5ymboljιame(string* s, expr** exprjplr){ return symbol_valjable.find(*s, exprjptr);} II block: :add_verify_expression // Add an expression whose truth is to be evaluated when this block // is instantiated. void block::add_verify_expression(expr* exprjptr, string* fail_string){ int i; i = verify_expressions.size(); verify_expressions[i] = exprjptr; verify_msgs[i] = fail_string; } // block::same jeveljxanslation // Returns the expression which is the translation of the given // symbol name. // If the name is an alias, translate until an expression is found. // If name not found, return NULL. // Do not search higher levels in the hieararchy. M-35 expr*block::same JevelJransIation(string* name) { expr* exprjptr; string* name ptr; expr* size; int number; expr* return_value; BOOLEANgot_addr = FALSE; namejptr = name; return_value = (expr*) NULL; // keep translating alias names until we don't find one while (alias_name_table.find(*namejptr, &name_ptr)) II first see of it is an IO frame pointer offset if (io_find(*namejptr, &number, &size)){ // have i/o index, but we need actual i/o location // if this block being instantiated, ask our instance for this info if (instancejptr) { if (instancejptr->valid parent_io()) { number = instancejptr->get_addr_of _io(number); got_addr =TRUE; } } if (!got_addr) number = io_indexj:oJlocation(number); return new expr((long) number, RELATIVE);} // not that, so try to look up in storage table else if (look_up 5torage_name(namejptr, &number)){ // have storage index, but we need actual location // if this block being instantiated, ask our instance for this info if (instancejptr) number = instance_ptr->get_addr_of_storage(number); else number = storage_indexJ;o_location(number); return new expr(Qong) number, RELATIVE);} // name not found so far, so it should then be a symbol // look up as ordinary symbol if (look jp_symbol_name(namejptr, &exprjptr)) M-36 return exprjptr; . // last chance is label name, in which case we return address of label else if (labeljιamej:o ndex(namejptr, &number)) return new expr((long) label αddress(number), RELATIVE); return return_value ; } II block: :translate_with jnstances // Returns the expression which is the translation of the given // symbol name. // If the name is an alias, translate until an expression is found. // If name not found, return NULL. // Search higher levels, if necessary, returning context if different from // current. expr* block: :translate_with jnstances(string* name, instance** path jnstjptr, instance** symbol jnstjptr) { string* namejptr; expr* return_value = NULL; instance*instjptr; block* blockjptr; expr* expr_ptr; expr* name_exprjptr = NULL; namejptr = name; // assume symbol instance context same as current for now *symbol jnstjptr = instancejptr; // if the translation name is a path, the instance where the path // is defined will get filled in *path jnstjptr = (instance*) NULL; // first check for override of this name if (override_table){ if (override_table->find(*namejptr, &exprjptr)) { // translated name, so see if it results in a string if (exprjptr->evaljo 5ymbol(&name_ptr)) { // it does, so save this string as an expression // in case there's no further translation name_exprjptr = exprjptr; } -37 else { // translated override name to non-symbol expression // so just return it return expr_ptr; } }} if (namejexpr ptr 1= (expr*) NULL){ // string translation found in our override table, so see if // we can translate it further higher up pop_block(); if (cur_block) { // there is a higher level block, so get translation and // advance relocation level for this expression if (return_value = cur_block->translate_with_instances(namejptr, path jnstjptr, sy boljnstjptr)) return_value->set_reloc_level( return_value->whatjreloc evel() + 1); } else // not found in override table, so check ordinary translation if (!(return_value = same_Ievel_translation(namejptr))){ // no translation found, so see if name is path to lower level block if (instancejptr) { if (instjptr = instance_ptr~> get_instance_ofjιame(name_ptr, &name_ptr)) { // 1st part of name matches one of our decendents blockjptr = inst ptr->prototype(); // make sure to set this block context for expr evaluation instjptr->push_contextO; // translate symbol in a decendent, returning instance for // symbol if found if (return_value = bloc jptr->same eveljxanslation(namcjptr)) *symboljnstjptr = instjptr; instjptr->ρop_context(); M-38 } } if (!return_value) { // still no translation found, so check any higher level block pop_block(); if (cur j)lock) { // there is a higher level block, so get translation and // advance relocation level for this expression if (return_value = cur )lock->translate_with jnstances(namejptr, path jnstjptr, symbol jnstjptr)) return_value->set_relocjevel( return_value->whatj-eloc jevel() + 1); } push_block(this); } } // if no translation, see if there is a translated name from override // symbol table, and return this if (!return_value && name_expr_pιr) return_value = name_expr jptr; // if no path instance was found in a higher level translation, use the // current instance as the path instance if (*path jnstjptr == (instance*) NULL) *path jnstjptr = instancejptr; return return_value;} II block: :translation // Version if translate Λάth jnstances which doesn't return path and symbol // instances. expr*block::translation(string* name){ instance*pathjnst; instance*symboljnst; return translate_withjnstances(name, &pathjnst, &symboljnst);} /////////////////////////////////////////////////////////////////////////////// // block::translate_tojparam_val // Returns the parameter value which is the translation of the given // symbol name. M-39 expr*block::ϋranslatej:ojparam_val(string* name){ string* name_ptr; expr* return_yalue = NULL; expr* exprjptr; expr* name_exprjptr = NULL; namejptr = name; if (override_table){ if (override_table->find(*namejptr, &exprjptr)) retum_value = exprjptr;} return return_value;} II block::translate_to_io // Returns the FO location which is the translation of the given // symbol name. // If the name is an alias, translate until found. // If name not found, return FALSE. BOOLEANbIock::translate_to_io(string* name, int* value) { string*name ptr; expr*size; int number; BOOLEANgot_addr; namejptr = name; //keep translating alias names until we don't find one while (alias_name_table.find(*namejptr, &namejptr)) If see of it is an IO frame pointer offset if (io_find(*namejptr, &number, &size)){ // have i/o index, but we need actual i/o location // if this block being instantiated, ask our instance for this info if (instancejptr) { if (instance_ptr->valid_parent_ioO) { number = instancejptr->get_addr_of jo(number); got_addr = TRUE; } } -40 if (!got_addr) number = io jndex_to jocation(number); *value = number; return TRUE;} else return FALSE;} II block: :translate_to_storage // Returns the storage location which is the translation of the given // symbol name. // If the name is an alias, translate until found. // If name not found, return FALSE. BOOLEANblock::translate_to_storage(string* name, int* value) { string*namejptr; int number; namejptr = name; // keep translating alias names until we don't find one while (alias_name_table.find(*namejptr, &namejptr)) // see of it is a storage table offset if (look_up_storage_name(namejptr, &number)){ // have storage index, but we need actual location // if this block being instantiated, ask our instance for this info if (instancejptr) number = instancejptr->geLaddr_of_storage(number); else number = storage jndex_to ocation(number); *value = number; return TRUE;} else return FALSE;} II block::known_symbol // Returns TRUE if the given symbol name has been declared, regardless // of whether it has a defined value. BOOLEANblock::known_symbol(string* name){ expr* exprjptr; M-41 string*namejptr; expr* size; int number; BOOLEANreturn_value; namejptr = name; //keep translating alias names until we don't find one while (alias_name_table.find(*name ptr, &name_ρtr)) // first see of it is an IO frame pointer offset if (io_find(*name_ptr, &number, &size)) return TRUE; // not that, so try to look up in storage table else if (look_up_storage_name(name ptr, &number)) return TRUE; // name not found so far, so it should then be a symbol // first look up in override symbol table, if any if (override_table) if (override_table->find(*namejptr, &exprjptr)) return TRUE; // check if ordinary symbol if (look jp_symbol_name(name_ptr, &expr jptr)) return TRUE; else{ // no translation found, so check any higher level block popJ)lock(); if (cur_block) { // there is a higher level block, so check if known return_value = cur lock->known_symbol(namejptr); } else return_value = FALSE; push_block(this); return return_value; }} II block::translation αiown // Returns TRUE if the given name has a known value. iiiπiitiiiiiifiiiiiiiiiftiiiriiiiiiiiiiiiiiiirriiiifiiiiiiiiiiifiiiiiiffiiiiii M-42 BOOLEANblock::translation jcnown(string* name) { expr* exprjptr; exprjptr = translation(name); return (exprjptr != (expr*) NULL);} II block::lookjjp jojiame // Find the given name in the io table. // Returns TRUE if found, along with the io index. BOOLEANblock::lookjjpjo_name(string* s, int* index) { expr* dummy _size; return io_find(*s, index, &dummy_size);} II block: :param_expr_at jndex // Returns the expression for the parameter at the given index. expr* block: :param_expr αt jndex (int index) { expr* exprjptr = NULL; string* namejptr; // get name at index namejptr = paramjιame_at jndex(index); // first check for name in override table if (override_table) override_table->find(*name jptr, &expr jptr) ; // if no value, look in regular symbol table if (exprjptr == (expr*) NULL) look_up_symbol jιame(name jptr, &expr jptr) ; // if still no value, return 0 if (exprjptr == (expr*) NULL) exprjptr = new expr(Qong) 0); return exprjptr;} II block-verify )lockjrefs // Verify that all blocks referenced by this block exist. // If not, return the name of one which does not. string*block: : verify_block _refs() { // base class has no referenced blocks return NULL;} M-43 II block::refs_iter_init // Initialize the iterator index for the block refs iterator. void block: :refsjter_init(){ // base class has no reference blocks} //block::next_ref // Get the next block referred to by this block. If no more // blocks, return FALSE. BOOLEANblock::next_ref(block_ref** ref jptr) { // base class has no reference blocks NOREF(ref_ptr); return FALSE;} iiiiimiiiiiiiinππiiiiiiiiiiiiiiiiiiiiπiiiiiiniπirniπiiniiiiiπim II block: :check_verify expressions // Check all the verify expressions for truth. If we encounter a false one, // this function returns with a pointer to it. expr* block::check_verϊfy_expressions() { expr* e; expr_element value; int eval_status; BOOLEAN verify.OK; char msg[100]; extern int instr_line; for (int i=0; i<verify_expressions.size(); i++){ e = verify_expressions[i]; verify_OK = TRUE; // evaluate the expression if (eval_status = e->eval(&value)) { // set global variable "instr_line" to reflect 0 line number instrjine = 0; value_goof nsg(eval_status, e, "verify expression", msg); eval_status = other_error("BLK001", msg); } else M-44 { switch(value.what_type()) { case INT.VALUE: verify OK = (BOOLEAN) value.int_value(); break; case REAL ALUE: verify OK = (value.real_value() != 0.0); break; default: break; } } if (!verify_OK) { return e; } } return NULL;} II block: :hier jo _name_at jndex() // Returns a string which is the hierarchical i/o name at the given index. // If we have no instance, just return the normal i/o name. string*block::hierjo_name_atjndex(int index){ string* hierjiame; if (instancejptr) { // use hierarchical name if not top block if ( ϋnstance jptr->is_top jevel()) { // get hierarchical name of instance as a string hierjiame = instance ptr->hier_name_string(); // concatenate the io name onto this *hier_name = *hier_name + "." + *io_name ιt jndex(index); return hierjiame; } } return io jιame_at_index(index); } II block: :hier _storage _name_at jndex() // Returns a string which is the hierarchical storage name at the given index. M-45 // If we have no instance, just return the normal storage name. string*block::hier_storage_name_at_index(int index) { string* hierjiame; if (instancejptr){ // use hierarchical name if not top block if (!instancejptr->is_top_level()) { // get hierarchical name of instance as a string hierjiame = instance _ptr->hier_name 5tring(); // concatenate the io name onto this *hier iame = *hier_name + "." + *storage_name_at jndex(index); return hierjiame; }} return storage_name_at_index(index);} II block: :hier_label _name_at_indexO // Returns a string which is the hierarchical label name at the given index. // If we have no instance, just return the normal label name. umuπttimmumimiii ummiimmmnniuumiumiiiiium stxing*block::hier_label_name_at ndex(int index) { string* hierjiame; if (instancejptr) { // use hierarchical name if not top block if (!instance_ptr->is_top_level()) { // get hierarchical name of instance as a string hier_name = instance ptr->hier_namej5tring(); // concatenate the io name onto this *hier_name = *hier_name + "." + *label_name_at jndex(index); return hierjiame; }} return label_name_at_index(index);} nittmimiiimmmtuimmimummmiimmiumtumiumiiπ II block::hier_param_name_at jndex() // Returns a string which is the hierarchical param name at the given index. // If we have no instance, just return the normal param name. string*block-hier_param ame_atjndex(int index) { M-46 string* hierjiame; if (instancejptr)! // use hierarchical name if not top block if (!instancejptr->isj:op jevel()) { // get hierarchical name of instance as a string hierjiame = instance jptr->hier_name_string(); // concatenate the io name onto this *hier jiame = *hierjιame + "." + *paramjιame_at jndex(index); return hierjiame; } } return param jιame_at jndex(index); } II block-add abel_name // Adds a new label name along with its sequence #. // Returns FALSE if the name and a seq # were already present. BOOLEANblock::addjabeljιame(string* name, int address) { int index; expr* old _size; // see if name already present if (!label_table.find(*name, &index, &old_size)){ // name not present, so allocate a new one and get its index index = assign Jabel jndex(name);} // store the label seq # in a table, provided not already there if (label_sequence [index] == NULL II label_sequence[index] == NO_ADDRESS){ label_sequence [index] = address; return TRUE;} else return FALSE;} II block::labeljιame_to jndex // Get the index for the given label name. // Returns FALSE if name not present. // Label table extends to phantom labels in instance, if present. BOOLEANblock::labeljιame_to jndex(string* name, int* index) { expr* size; if (label_table.find(*name, index, &size)) M-47 return TRUE; else{ if (instancejptr) return instance ptr->phantom_label_name_to jndex(name, index); else return FALSE; }} II block::assign abel jndex // Gets an index (not an address!) for a label name. // If the name was not encountered before, a new, unique index is allocated //for it int block-assign abel_index(string* name){ int index; expr* old_size; // see if name already present if (label_table.fmd(*name, &index, &old_size)) return index; else{ // store name in hash table with new index label_table.allocate(*name, (expr*) NULL, &l_index); label_sequence[I_ϊndex] = NO_ADDRESS; // need label for this index return l_index++; }} iiiiiriiiiiiififiriiiiiiifiiiiiiiiiritiififiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii II block::labeljabIe_size // Get the size of the label table. //Label table extends to phantom labels in instance, if present int block::label_table_size(){ int size; size = label_table.sizeO; if (instancejptr) size += instance _ptr->phantom_label_table_size(); return size; } II block::label ιame_at_index // Get the name at the given label index. M-48 // Label table extends to phantom labels in instance, if present. string*block: :label_name_at jndex (int index) { int size; // see if in block's table if (index < (size = label_table.size())) return label_table.name_at jndex(index) ; else{ // else look in instance's table of phantom labels if (instancejptr) return instancejptr->phantomjabel_name_atjndex(index-size); else return new string("INVALID_LABEL"); } } II block: :label_seq_at jndex // Get the seq # at the given label index. // Label table extends to phantom labels in instance, if present. int block: :label _seq _at jndex(int index) { int size; if (index < (size = label_table.size())) return label_sequence[index]; else{ if (instancejptr) return instance jptr- >phantom abel_seq ιt_index(index-size) ; else return 0; } } II block: :label_offset_at jndex // Get the offset at the given label index. // Label table extends to phantom labels in instance, if present. int block::label_offset_at jndex(int index) { int size; if (index < (size = label_table.size())) return label Dffsetfindex]; else{ -49 if (instancejptr) return instancejptr->phantom Jabel_offset_at_index(index-size) ; else return 0; }} II block::set_labeI_offset // Set the offset for the given label index. // Label table extends to phantom labels in instance, if present. void block::set_label }ffset(int index, int offset)! int size; if (index < (size = label_table.size())) labeI_offset[index] = offset; else{ if (instancejptr) instance_ptr->setjphantom_labe offset(index-size, offset); }} II block::label_address // Gets an absolute address for a label index. II If no label offset available, just use label seq. # in block. // This is so that we can use this routine for resolving the address of // a label when we're checking jump instructions for backward jumps. int block::label_address(int index)! int address; // we need absolute address of label // if this block being instantiated, ask our instance for this info if (absolute_origm)[ if (label_offset[index]) address = label _offset[index] + origin_address; else address = label_sequence[index] + origin_address; } else if (instance_ptr) address = instance_ptr->get_addr_of_label(index); else! if (label 3ffset[index]) address = label_offset[index]; else address = label_sequence[index];} return address;} II block: :get_address_from jabel_name // Find the given label name in the block, searching higher level blocks // as necessary. Return the address, else the special (neg) value // "NO_ADDRESS". int block: :get_address_fromjabeljιame(string* name)! int index; int jmp iddress; instance*instjptr; block* block jptr; expr* exprjptr; // assume we can't find jmp_address = NO_ADDRESS; // allow him to use alias // keep translating alias names until we don't find one while (alias_name_table.find(*name, &name)) // look for label in the current block if (labeljiame _to jndex(name, &index)) jmp_address = label_address(index); // if not in current block, may be in higher level block if (jmp_address == NO_ADDRESS){ // see if override symbol which translates to label in higher block if (override_table) if (override_table->find(*name, &exprjptr)) exprjptr->eval_to_symbol(&name); // not in current block, so look in any higher level block pop_block(); // if there is a higher level block, look for label recursively if (cur_block) jmp_address = cur j)lock->get_address xom jabeljιame(name); push_block(this);} if (jmp_address == NO_ADDRESS){ // if no label found in this block's context, check if absolute name // from top of instance hierarchy -51 if (top_instance) { if (instjptr = top_mstance->get nstance_of_namε(name, &name)) { // name may refer to an absolute label from top of hierarchy // get ptr to block and check its label table block ptr = inst_ptr->prototype(); // set instance for this block blockjptr->instancejptr = instjptr; if (block_ptr->label_narnej:o jndex(name, &index)) jmp_address = instjptr->get_addr_of abel(index); } } if (jmρ_address = NO_ADDRESS) { // There are actually two "tops" of the instance free. The // "_true_top", which we just used, and "_top", which is the // top instance in the user's design. Check if an absolute // name firom the user's top since he doesn't necessarily know // that he is not the real top of the instance tree, if (userjxrφ j stance) { if (instjptr = userjop_instance->get jnstance_of_name(name, &name)) { // name may refer to an absolute label from top of hierarchy // get ptr to block and check its label table blockjptr = inst_ptr->prototype(); // set instance for this block block ptr->instancejptr = instjptr; if (blockjpϋ»label_name_to_ϊndex(name, &index)) jmp_address = instjptr->get_addr_of jabelrindex); } } }} return jmp_address; } II block::storage_error // Output error text for storage initialization. Passed text and M-52 // index of storage location. int block: :storage_error(char* msg_code, int index, char* s){ char msg[100]; extern intinstr_line; // set global variable "instr jine" to reflect line number of storage init instr jine = get_storage jinejιumber(index); if (instance ptr) instance_ptr->out_error(msg_code, cerr, FALSE); else out _err _header(msg_code) ; cerr « "Initializing storage location '" « *non phantom_storage_name_atjndex(index) « "' - " « s « "\n"; return 1; } II block: :storage_warning // Output warning text for storage initialization. Passed text and // index of storage location. int block::storage_warning(char* msg_code, int index, char* s){ char msg [100]; extern intinstr_line; // set global variable "instr jine" to reflect line number of storage init instr jine = get_storage jinejιumber(index); if (instance_ptr) instancejptr->out_warning(msg_code, cerr, FALSE); else out_warn_header(msg_code); cerr « "Initializing storage location "' « *nonjphantom_storage_name_atjndex(index) « "' - " « s « "\n"; return 0; } #ifdef OWC extern "C" { #endif II read_init_file // Open the given init file and read it into the initialization vector. int read_init_file(string* name string, int size, long_array* storage_vector, int index)! int status = 0; long val; //initialization value int token; / token value from yylex() BOOLEAN negate = FALSE; string* failedjpath; BOOLEAN broke = FALSE; int last_i; extern int line; // current line # for lex analyzer // open input file with file pointer yyin, for lex if (!push_file(name_string, &failedjpath)) status = COULD_NOT_EVAL; if (.status)! // read the data from the init file for (int ϊ=0; i<size; i++) { // get next token from lexical analyzer token = yylex(); // handle minus sign while (token == UMTNUS II token = '-') { negate = 'negate; // get new token from lexical analyzer token = yylex(); } // if end of file, break out of loop if (token == 0) { // remember where we broke so we can zero rest last_i = i; broke = TRUE; break; } // if not valid number token, get out with error else if ( token != INTEGER && token != REAL ) { M-54 yyerror("dummy") ; status = INIT ?ILE SYNTAX_ERR; // remember where we broke so we can zero rest last_i = i; broke = TRUE; break; } else { // now have number token, so get integer value if (token == REAL) { // check for real number out of range, but make sure // we handle unary minus correctly if ( (negate && real_out_of _range(-yylval.rval)) II (Inegate && real_out_of_range(yylval.rval)) ) { charmsg[100]; sprintf(msg, "real value %f at line %i of init file '%s' is not in ran»e -2.0 to +1.9999.", yylval.rval, line, &(*name_string)[0]); status = storage _error("BLK024", index, msg); status = Γ T_ΠLE_SYNTAX_ERR; } // get 24 bit integer equivalent of real value val = (long) (yylval.rval * REALJFACTOR); } else val = (long) yylval.ival; // if previous unary minus, then negate flag was set if (negate) { val = -val; negate = FALSE; } (*storage_vector)[i] = val; } if (status) // remember where we broke so we can zero rest last j. = i; broke = TRUE; break; } } // if we broke, fill in rest of array with zero ! if (broke) { for (i= last_i; i<size; i++) (*storage_vector)[i] = 0; } pop_file(); // done with init file} return status;} ffifdef OWC} #endif II block::out_storage_code // Output a single word of storage initialization for the given storage index. // Return nonzero error code if init error. // If the storage is a vector, return "is_yector" true, and also return // an array of all the storage values. iiiiπiiiiπiπiiuiiiiiiiniiiiπimiiπiiininiiniiiiiumiiiiiiiiiiiiM int block::out_storage_code(int index, ostream& out, BOOLEAN* is_vector, long_array* storage_vector)[ expr* e = (expr*) NULL;// expression for storage initializer // initialization value reloc_type; reloc_level; // 24 bits of output value eval_status = 0; expr; // expression for size of vector int size;// number for size of vector int i; expr_element value; // expression which yields init value string* name string / init file string BOOLEAN vector_initialized = FALSE; BOOLEAN is real; // TRUE if storage code is real 4oι char storage_type; int dummy; // if storage is virtual, don't output anything if (is_storage_virtual(index)) { • *is_vector = FALSE; return 0;} // get expression for storage initializer // if instance present, check for override initializer if (instancejptr) e = instance jptr->get_storage_override jnit(index); if (!e) e = get_storage jnit(index); else val = 0; // default value to 0 val = 0; // see if this storage is a vector size = 1; size_expr = storage_entry_size(index); // if vector, get size of array to hold init values if (size_expr){ size = (int) int_value(size_expr); // make sure array size not larger than we need if (storage_vector->size() > size) storage_vector->size() = size;} if (e){ // there is an initialization expression, so get the type for this // storage location storage jype = get_storage_type(index); if (e->is jnt_valued()) { // expression has integer value, so see if storage type // conflicts if (storage ype == 'f ) { // must convert integer to fixed, so give warning storage _warning("BLK007", index, "Converted integer to fixed point"); cerr « " ("; cerr « e->int_value(&dummy, &dummy) « " -> "; //just add "fix" operator, but do this on copy of original e = new expr(*e); e = concat_expr(e, operatorjo_expr('F')); // format real value so decimal point shows cerr«form("%f , e->real_value(&dummy, &dummy)); cerr« ")\n"; } } else if (e->isjreal_valuedO) { // expression has fixed point value, so see if storage type // conflicts if (storagejype = ) { // must convert fixed to integer, so give warning storage_warning("BLK008", index, "Converted fixed point to integer."); cerr «" ("; // format real value so decimal point shows cerr «form(" f , e->real_value(&dumnιy, &dummy)); cerr «" ->"; //just add 'TNT" operator, but do this on copy of original e = new expr(*e); e = concat_expr(e, operator_to_expr(T)); cerr « e->int_value(&dummy, &dummy); cerr « ")\n"; } } if (eval_status = eval_24_bit_value(e, &val, &reloc_type, &reloc_leveI, &is_real)) { // couldn't evaluate expression, so see if its a symbol if (eva status = NUM_VALUE OT_KNOWN) { // it is, so open a file with this name // we will read it via yylex, so open compatibly if (e->eval(&value)) { if (value.what_type() == SYMBOL.VALUE) { // gave a symbol, so treat as file to read values from name_string = value. symbol(); vector jnitialized = FALSE; if (eval_status = read jnit_file(name_string, size, ■ storage_vector, index)) { // output msg if it doesn't get otherwise output if (eval_status == COULD_NOT_EVAL) { charmsg[100]; sprintf(msg, "\n couldn't open a storage init file called '%s'.", &(*name_string)[0]); if (valuesjnust ejcnown) storage 3rror("BLK002", index, msg); else storage arning("BLK002", index, msg); } } else vector jnitialized = TRUE; if (vector jnitialized) { // get first value, but only if we have a vector val = (*storage_vector)[0]; } } } } } } out_val = val & WORD MASK; out « form("%061x ",out_val); // test if vector, and init if not previously inited if (*is_vector = (size > 1)){ if (! vector jnitialized) { for (i=0; i<size; i++) (*storage_vector)[i] = val; M-59 }} if (values nust_be αιown) return eval_status; else • return 0;} // block::out_rest_of_storage_vector // If the given storage is a vector, repeat the init value for rest of size. void block: :outjrest Df_storage_vectorOong_array* vect, ostream& out)! int i; unsigned longout_val; for (i=l; i<vect->size(); i++){ out « "\n"; out_val = (*vect)[i] & WORD_MASK; out «form("%06fx ",out_val); } } II bIock::outj3torage // Output the storage initialization, starting at 0. int block::out_storage(ostream& data){ int result = 0; int status = 0; BOOLEANmore; BOOLEANfatal = FALSE; long irraystorage_vector; for (int i=0; ϊ<storage_table_sizeO; i++){ if (status = out_storage_code(i, data, &more, &storage_vector)) { char msg[100J; expr*e = get_storage jnit(i); result 1= status; switch (status) { case NUMJVALUE_NOT_KNOWN: { string*s; if (s = e->unknown_symbol()) sprintf(msg, "\n value for symbol %s is not known.", &(*s)[0] ); else sprintf(msg, "\n value for initialization is not known."); if (valuesjrιust_beJcnown) status = storage_error("BLK003", i, msg); else status = storage_warning("BLK003", i, msg); } break; case REAL_OUT_OF_RANGE: sprintf(msg, "real value %f is not in range -2.0 to +1.9999.", real_value(e)); status = storage_error("BLK004", i, msg); fatal = TRUE; break; case OVERFLOW: sprintf(msg, "integer value %i doesn't fit in 24 bits.", int_value(e)); status = storage 3rror("BLK005", i, msg); fatal = TRUE; break; case COULD_NOT_EVAL: case INIT_FILE_SYNTAX_ERR: fatal = TRUE; break; // msg already output default: if (values_must_be_known) status = storage _error("BLK006", i, "couldn't evaluate."); else status = storage_warning("BLK006", i, "couldn't evaluate."); break; M-61 if (more) out rest 3f_storage_vector(&storage_vector, data) ; data «"\n"; if (fatal) break;} // if just warning, return 0 if (! values jnustjiejαiown && Ifatal) result = 0; return result;} II block: :sequence_children // If this is a hierarchical block, sequence its children. // Returns TRUE if error. BOOLEANblock::sequence_children(BOOLEAN* new -atejptr) ! NOREF(new_rate_ptr); return FALSE;} II asm_block::asm j lock // Constructor. asm_block::asm_block():// initializer list for all arrays and hash tables operand_values(SZ), opcode ιeIds(SZ), addr_mode_fields(SZ), operand_fields(SZ), instr_line_numbers(SZ) , relocation(SZ), reloc_Ievel(SZ), linked_addrjrnode(SZ), linked rjperand(SZ), * top_level_instr_line(SZ) ! autosequence = FALSE; is_indivisible = leaf_block = TRUE; manual jblock = FALSE; duration = (expr*) NULL; } II asm_block::~asm_block M-62 // Destructor. asm_block::~asm_block() { } II asm_block::add_operand_value // Record an operand value expression and return an unique index which // identifies the expression, so that the operand field of the instruction // can be evaluated later. int asm_block::add operand_value(expr* exprjptr)! static int operand_value jndex = 0; operand_values[operand_value jndex] = exprjptr; return operand_valuejndex++;} II asm_block::enter_fields // Enter the fields of a new instruction into the arrays for each field. // The number for this instruction is passed, as this is used as the // array index for the fields. // Keeping the instruction fields in distinct arrays makes it easier // to do successive compiler passes, eliminating the need for masking // of the composite instruction. void asm_block::enter_fields(int index, int linejium, int opcode, int addrjnode, int operand, in reloc_type){ opcode_fields[index] = opcode; addrjnode ϊelds[index] = addrjnode; operand_fields[index] = operand; instr _line_numbers[index] = linejium; relocation[index] = relocjype; // also add file inclusion nest level, used for listing output, // as well as line number in top-level file if (the_file_stack.size()) top eveljnstrjine[index] = the_file_stack.line_at_filejevel(0); else top jevel jnstr inefindex] = linejium;} II asm_block::set_duration // Sets an expression for the duration of this block, plus whether 4o8 M-63 // or not duration can be variable. // Returns FALSE of duration was previously set iiiiiiπiiiiuiiiii iiπiiiiiπiπiiii/uiiiiiuiiiiiiiiiiπiπiiiiiiiim BOOLEAN asm_block::set_duration(expr* dur)[ if (duration) return FALSE; else{ duration = dur; return TRUE; }} II value_goof_msg // Create a message string for a value warning or error void value_goof jrnsgønt eval_status, expr* exprjptr, char* name, char* msg)! switch (eval_status){ case REAL_OUT_OF_RANGE: sprintffmsg, "Real %s %f is not in range -2.0 to +1.9999", name, real_value(expr jptr)) ; break; case OVERFLOW: sprintf(msg, "Integer %s ld doesn't fit in 24 bits", name, int_value(exprjptr)); break; case OPERAND .OVERFLOW: sprintf(msg, "%s %ld is too big to fit in the 15 bit operand field", name, int_value(exprjptr)); break; case NULL_EXPR: sprintf(msg, "No %sϋ Internal error!!", name); break; case NOT_BOTH UMBERS 3R_STRINGS: sprintf(msg, "Both arguments for this %s operator need to be either numbers or strings", M-64 name); break; case INT_REQUIRED: sprintf(msg, "Arguments for this %s operator need to be integers", name); break; case ADDRESSES_CODE_SPACE: sprintf(msg, "%s %ld refers to code space, not data space", name, int_value(exprjptr)); break; default: sprintf(msg, "Value unknown for %s", name); break; } } II asm j>lock::value_error // Report a value error for an expression. void asm j)lock::value_error(int eval_status, expr* exprjptr, int i, char* name){ char msg[100]; extern intinstr jine; int status; char *msg_code = "BLK010"; // change low char based on status // set global variable "instr jine" to reflect line number instr jine = instr jine jιumbers[i]; // set low digit char from eval status enumeration msg_code[5] = '0' + eval_status; value joof jnsg(eval_status, exprjptr, name, msg); status = other_error(msg_code, msg); } II asm_block::value_warning // Report a value warning for an expression. void asm_block::value Λ'arning(int eval_status, expr* exprjptr, int i, char* name)! char msg[100]; M-65 ^ 10 extern mtmstr_line; int status; char *msg_code = "BLK010"; // change low char based on status // set global variable "mstr ϊne" to reflect line number instr_line = mstr_line_numbers[i]; // set low digit char from eval status enumeration msg_code[5] = '0' + eval_status; value_ oof_msg(eval_status, exprjptr, name, msg); status = waπιing(msg_code, msg);} II asm_bIock::eval_operands // Evaluate all operand values and indexed offsets and set them in their //respective instructions. //This is called both at compile and link time, since all operands // need not be known at compile time // The arrays "linked_addr_mode" and "linked pperand" and set, so // the original arrays "addr_mode_fields" and "operand_fields" are // not touched. iiiπ iiniiuiiiπiiiiπiiiiiiiiiπiiiHiπiπuiiriiiiiuπiiiniiiiiiHiii int asm j)lock::eval_operands( BOOLEAN must_bej nown){ long immed_val; long high nts; int eval_status = 0; int warn_status; expr* expr_ptr; BOOLEANisjreal; // TRUE if operand is real int • jmp_address; string* name; int return_value = 0; for (int i=0; i<n_ϊnstructions; 1++) ! // assume operand and address is ok for now Iinked_addr_mode[i] = addr_mode_fields[i]; linked _operand[i] = operand_fields[i]; // if immediate mode address, try to evaluate if (is_immediate_mode(addr_mode_fields[i])) { // but make sure we trap only source operand class opcodes if (is_source_op_opcode(opcode_fields[fj)) M-66 { exprjptr = operand_values[operand_fields[i]]; if (eval_status = eval_24 it_value(exprjptr, &immed_val, &relocation[i], &reloc jevel[i], &is_real)) if (must_be_known II eval_status != NUM_VALUE_NOT_ KNOWN) { value _error(eval_status, expr_ptr, i, "immediate value"); return_value = 1; } // see if we must decide justification if (addr_mode_fields[i] == IMMEDIATE_MODE) { // test if it will fit in operand field unshifted // first extract potential high bits highjnts = immed_val & ~OPER_MASK; if (high_bits && (high_bits != HIGH_MASK)) { // too big to fit unshifted, so shift down // but if not real, output a warning // unless phantom block, where we assume we know // what we're doing if (Usj-eal && iphantom) { wam_status = OPERAND .OVERFLOW; value_warning(warn_status, exprjptr, i, "Immediate integer"); } immed_val = immed val » HIGH_SHIFT; // set address mode to left justify linked_addr_mode[i] = IMMED_L_MODE; } else // will fit right justified and sign extended linked_addr_mode[i] = IMMED_R MODE; } // set operand_field, but make sure to use only our bits! tøιked_operand[i] = (int) (immed_val & LOW MASK); } else if (is jum _opcode(opcode_fields[i])) { // get name for this label name = label_name_at_index(operand_fields[i]); // find label in this block or higher level block jmp_address = get_address_from_label_name(name); if (mustjbe Jmown && jmp.address == NO_ADDRESS) { eval_status = NUM JVALUE OTJ NOWN; vaIue_error(eval_status, (expr*) NULL, i, "jump address"); return_yalue = 1; } linked Dperand[i] = (int) (jmp_address & LOW MASK); } } // else if indirect mode address, try to evaluate else if (is_indexed_mode(addr_mode_fields[i])) { // but make sure we trap only correct opcode classes if (is source_op_opcode(opcode_fields[i]) II is_dest_op rjpcode(opcodeJϊelds[i]) II isjump_opcode(opcode_fields[i]) ) { // indexed mode is same, but only allow right-justified number expr_ptr = operand_values[operand_fields[i]]; if (eval_status = eval_24_bit_value(expr ptr, &immed_val, &relocation[i], &reloc_level[i], &ϊsjreal)) if (must_bejαιown II eval status != NUM_VALUE_NOT_- KNOWN) { value_error(eval_status, exprjptr, i, "index value"); return_value = l; } // test if it will fit in operand field unshifted // first extract potential high bits high ήts = ϊmmed val & -OPER_MASK; if (high_bits && (high.bits != HIGH MASK)) -68 // too big to fit unshifted, so value is out of range! eval_status = OPERAND_OVERFLOW; value_error(eval_status, exprjptr, i, "Indexed mode offset"); return_value = 1; } else { // set operand, but make sure to use only our bits! linked _operand[i] = (int) (immed_val & LOWJvIASK); } } } // else if direct mode address, try to evaluate else if (is_directjnode(addr_mode_fields[i])) { // but make sure we trap only correct opcode classes if (is_source_op_opcode(opcode jϊelds[i]) II is_dest_op_opcode(opcodejιelds[i]) II is jump_opcode(opcode_fields[i]) ) { // only allow right-justified number exprjptr - operand_values[operand_fields[i]]; eval_status = eval_24_bit_value(expr_ptr, &immed_val, &relocation[i], &reloc jevelp], &isj"eal); // make sure operand is legal, which can't be negative high_bits = immed_val & ~OPER_MASK; if (high j ts) eval.status = OPERAND .OVERFLOW; // give warning if trying to address code space if (must jr>e j nown && eval_status == 0 && immed_val < io_space_start) { warn_status = ADDRESSES_CODE_SPACE; value_warning(warn_status, expr_ptr, i, "Address"); } if (eval _status) { if (must_be_known II eval_status != NUM_VALUE_NOT_- -69 KNOWN) { value 3rror(eval_status, expr_ptr, ϊ," Address"); return_value = 1; } } //if there's a fudge factor (chip bug) for absolute addresses, // add it if (abs_addr_fudge) finked_operand[i] = (int) ((immed_val & LOWjMASK) + abs_addr_fudge); else linked_operand[i] = (int) (immed_val & LOW_MASK); } }} return return_value;} II asm_block::check_duration // If no duration given, make sure the block has no backward //jumps if there are any condition jumps, which would could create // data-dependent loops. // Returns FALSE if it fails this test // If no duration and no backward jumps, then set the duration // equal to the number of instructions. // If any conditional forward jumps, set duration as variable. // "eval Dperands" must first have been called, since this resolves //jump addresses. BOOLEAN asm_block::check_duration(){ BOOLEANconditionals = FALSE; BOOLEANbackward umps = FALSE; if (duration) return TRUE; for (int i=0; i<n jnstructions; ϊ++) ! if (is_jump_opcode(opcode_fields[i])) { if (is_cond_jump 3pcode(opcode_fields[ϊ])) conditionals = TRUE; M-70 // test if this is a backward branch if (linked _operand[i] < i) backward jumps = TRUE; } } // if any conditionals, don't allow backward jumps if (conditionals)! if (backward jumps) { other _error("BLK020", "With condition jumps and backward jumps, you must specify a duration."); return FALSE; } } // set duration expression from # of instructions duration = int_to_expr((long) n_instructions); return TRUE;} II asm_block::out_instruction // output assembly code for the given line. void asm_block::out_instruction(int line, ostream& out){ long instruction; instruction = ((long) opcode_fields[line] « OP_SHIFT) I ((long) linked_addr_mode[line] « MODE_SHIFT) I (long) linked _operand[line]; out « form("%061x",instruction); } II asm_block::out_reloc jnstruction // output assembly code for the given line, but put appostrophe on // at end if operand field is relocatable. void asm_block::out_reloc jnstruction(int line, ostream& out){ long instruction; instruction = ((long) opcode_fields[line] « OP SHIFT) I ((long) linked_addr_mode[line] « MODEjSHIFT) I (long) linked Dperand [line]; out « form("%061x", instruction); if (relocationfline] >= RELATIVE) out « "'"; M-71 else if (relocation[line] = UNDEFINED) out«"?"; else out« " "; // if non-zero relocation level, print it if (reloc jeveipine]) out « "*" « reloc_level[line] « " "; else out« " "; } II asm_block::out_asm // output assembly code directly, without linking int asm jr>lock::out_asm(ostream& out)! for (int i=0; i<n_instructions; i++){ out_instruction(i, out); out«"\n";} return 0;} II asm_block: :out_addr_and jnstruction // Output the instruction address followed by the instruction. void asm_block::out_addr αnd_instruction(int nextjnstr, ostream& listing)! int address; // if code has absolute origin, displace output addr by this amount address = nextjnstr; if (absolute jrϊgin) address += origin_address; listing « form("%04x ", address); out jreloc_instruction(next_instr, listing) ; } II asm_block::out_listing // Output the program listing. int asm jr>lock::outJisting(istream& in, ostream& listing, int& in jine) ! int nextjnstr = 0; int next_storage = 0; int n_storage; M-72 BOOLEAN new Jine = TRUE; char ch; int status = 0; BOOLEAN more; long_array storage_vector; // get size of storage table n_storage = nonjphantom_storage_table_size(); while ( (nextjnstr < n jnstructions) II (next_storage < n_storage) ){ if (in.rdstate() != jood) break; in.get(ch); if (new Jine) { // check for output of instruction code // - use top level instruction line in case code was generated // from inside an include file if ( (topjevel jnstr Jine[next jnstr] <= injine+l) && (nextjnstr < n jnstructions) ) { out ιddr_andjnstruction(next jnstr, listing) ; nextjnstr++; } // check for output of storage initialization else if ( (get_topJevel_storJine(next_storage) <= injine+l) && (next_storage < n_storage) ) { listing « form("%04x ", storage Jndex_toJocation(next torage)); status 1= out_storage_code(next_storage, listing, &more, &storage_vector); next_storage++; } else listing « " "; new Jine = FALSE; } listing.put(ch); M-73 if(ch = '\n') { // output remaining multi-code instruction line while ( (top Jevel_ str_mιe[next jnstr] <= injine+l) && (nextjnstr < n Jnstructions) ) { out_addr_andJnstruction(next Jnstr, listing) ; fisting «"\n"; nextjnstr++; } // output remaining multi-code initialization line while ( (getj:opJevel_storJine(next_storage) <= injine+l) && (next_storage < n _storage) ) { listing « form("%04x ", storage jndex_toJocation(next_storage)); status 1= out_storage_code(next_storage, listing, &more, &storage_vector); listing « "\n"; next_storage++; } injine++; new_line = TRUE; } } return status;} II hier_block::hier_block // Constructor. hierJ)lock::hier_block() : instances(SZ)! autosequence = TRUE; leaf_block = FALSE; manuaI_block = FALSE; refs sonnected = FALSE; children_sequenced = FALSE; } iiuiiiiiiuiiiuiinimui iuniiiuiπ uiiiπiiiiiiiimπiiiiiiiii II hier_block::~hier_block // Destructor. M-74 hier_block: :~hier_block() { } II hier_block::add_block_ref // Add a block j-ef for a new instance. // Returns FALSE if an instance by this name already exists. BOOLEAN hier_block::add_block_ref(block_ref* ref ptr) { int i; string* name; // make sure instance name is unique name = refjptr->getjnstancej ame(); for (i=0; i<instances.size(); i++){ if (*name == *instances[i]->get JnstancejiameO) return FALSE;} i = instances.sizeO; instances[i] = ref jptr; return TRUE;} II hier_block::refs jter jnit // Initialize the iterator index for the block refs iterator. void hier_block::refs jter_init() { refjndex = 0;} II hier_block::next_ref // Get the next block referred to by this block. If no more // blocks, return FALSE. BOOLEANhier_block::next_ref(block_ref** ref_ptr){ if (ref jndex < instances.sizeO)! *refjptr = instances[ref jndex++]; return TRUE;} else return FALSE;} II hier dock:: verify j lockjrefs M-75 // Verify that all blocks referenced by this block exist Also set a ptr // to the block in the block ref. // If not, return the name of one which does not strmg*hierj3lock::verify )lock refs0{ block_ref*refjptr; string* blkjiame; string* instj ame; argjset*vals; arg_set*ports; int In; block* blk jptr; for (int ϊ=0; i<instances.size(); i++)! ref jptr = instances[i]; ref _ptr->get_blockjnfo(&blk iame, &inst_name, &vals, &ports, &ln); if (prototype_blocks.find(*blkj ame, &blkjptr)) ref jptr->setJ)lock pointer(blk jptr); else return blkjiame;} return NULL;} II hier_block::sequence_children // If this is a hierarchical block, sequence its children. // This function sequences children recursively. // It sets a boolean argument newjratejptr to TRUE if any rate changes // (decimation or interpolation) were performed in the children. // We need to know this because such rate changes created time sub-zones // which need to be kept together in block sequencing. This lets us split // " sub-zones easily, by just checking for a change in zone in the block // sequence. // Returns TRUE if error. iiiiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiriiiiiiiffiiiiiiiiiiiiiiiiiiiniiiinifiiim BOOLEANhier_block::sequence_children(BOOLEAN* ne jratejptr) { int i inpjistremaining; // inputs (block and input index) remaining int_arraypendingJ)locks;// blocks with inputs pending int blkjndex; int inp iidex; M-76 BOOLEANstatus = FALSE; BOOLE ANnewjrate = FALSE;// if any child has new rate, set as TRUE // set this block prototype as the current block for error ms s push )lock(this); // sequence if this is autosequence and we have block inputs if (is_autosequence() && block jnputs.size()){ // first make sure all our references are marked if (!refs_connected) { ofher_error("BLK901", "INTERNAL ERROR - Trying to sequence block with¬ out first connecting refsΛn"); pop_block(); return TRUE; } ' // we must auto-sequence, so start off with inputs to block remaining = block jnputs; // first make a list of all blocks with inputs pending // and also filter out any block which is really the parent block // output psuedo-block, which has a negative block index remaining.iterjnitO; while (remaining.next(&blk jndex, &inp jndex)) { if (blkjndex >= 0) { // first mark initial inputs to blocks as reached instances[blkjndex]->markjnput_as_reachcd(inpjndex); #ifdef DEBUG cerr « "marking input " « inp jndex « " of block " « *instances[blkjndex]->getjnstancejpointer()->hier_name_string() « " as reached\n"; #endif // next add new block number to pending blocks list if (pending J>locks.find(blk jndex) < 0) { pending_blocks[pending_blocks.size()] = blkjndex; #ifdef DEBUG cerr « "adding « *instances[blkjndex]->getjnstancejpointer()->hier_name_string() « " to pending blocks on sequence children\n"; M-77 #endif } else remaining.removeO / remove parent output pseudo-block } // repeat while any inputs remaining or any blocks with pending input while (Jremaining.emptyO II pending_bIocks.size()) { // Pass through blocks which have all inputs marked. This // marks inputs in the connected blocks, which, in turn, we // try to pass through if all their inputs are marked. // The process continues until there are no more blocks. //If there are blocks but we can't pass through any, then // we are blocked with a feedback loop. // // If block passed through or any of its child blocks have a new // sample rate, then newjrate is set TRUE. if (!pass through_fulIy_marked_blocks(remaining, pending locks, &new_rate)) markJoops(remaining, pending_blocks, &newjrate); } } else! // not autosequence, so set the sequence that the user specified // set our block as sequenced & recursively sequence children for (i=0 i<instances.sizeO; i++) set 3equenced_and_call_children(i, &newjrate); } // make sure all child blocks are sequenced for (i=0; i<instances.sϊze(); i++) { if (!instances[i]->get_instancejpointerO->is_sequenced()) { // only virtual I/O blocks can be left out of sequence // add them at the end if (instances[i]->get_blockjpointer()->is_block_virtualjo()) { // add virtual I/O block at end of sequence sequence.appendri) ; instances[i]->getjnstancejpointer()->set_sequenced(); -78 } else { instances[i]->getjnstancejpointer()-> out 3rror("BLK022", cerr, TRUE); cerr « "Unable to place this instance in a" « " firing sequenceΛn" « " Is it connected to anything?\n"; status = TRUE; } } } // mark us has having sequenced children set_children _sequenced() ; // we're no longer the current block pop_block(); // tell caller if this block or any child block has a sample rate change *new_ratejptr = newjrate; return status;} II hier_block::markJoops // Used by hier_block::sequence_children to mark feedback loops, // and let user know he has feedback. void hier_block::markJoops(inpJist& remaining, int_array& pending_blocks, BOOLEAN* new_ratejptr){ int j; int blkjndex; block* blkjptr; string* blkjiame; string* iojiame; // we hit a loop! if (pending J)locks.size()) { // find unmarked inputs for pending block, and mark as loop blkjndex = pending_blocks[0]; for (j=0; j<instances[blk jndex] ->io_size(); j++) { if (instances[blkjndex]->isjnput(j)) { M-79 if (!instances[blk_index]->is_input_marked(j)) { // found an input that's not mark // so mark normally and as loop input instances[blk_index] ->mark Joop Jo (j) ; #ifdef DEBUG cerr « "marking as loop I O " « j « " of block " << *instances[blk ndex]->getJnstancejpointer()->hierjιame_string() « " as reached\n"; #endif instances[blkjndex]->markjnput_as_reached(i); #ifdef DEBUG cerr « "marking input " « « " of block " << *instances[blkJndex]->get_mstancejpointerO->hier jiame stringO « " as reached\n"; #endif // mark this wire as a loop wire loop_wires[ instances[blkJndex]->parent_wireJorjo(j)]= TRUE; // tell user that he has a feedback loop blk ptr = instances[blkJndex]->get_blockjpointer(); io_name = blkjptr->io_name_at jndex(j); blkjiame = blkjptr->getJ)Iock_name(); line = instances[blkjndex]->getjine_number(); out_warn_header("BLK021"); cerr « "Do you know you have a feedback loop to input '" « *io_name «"' of block '" « *blk_name «"'?\n"; } } } // can now pass through this block pass_through(bl Jndex, remaining, pending Jilocks, newjratejptr); blockjias Joops = TRUE; }} umimmmimiuittiiiiiimuiuimmuHHuiHimmmimmmH //hϊerj3lock::pass_through_full_marked_blocks M-80 // Used by hier_block::sequence_children to pass through all blocks which // have all their inputs marked. // Returns TRUE if we passed through any blocks. BOOLEAN hier_block: :pass_through Jully_marked_blocks(inp Jist& remaining, int_array& pending >locks, BOOLEAN* newjratejptr)! int i; int blkjndex; BOOLEANpassed_through = FALSE; // If all block's inputs marked, can pass through this block. // HOWEVER: // We must pass through blocks which cross into new time // subzones at the last possible moment. This results in // subzone sequencing within a block sequence; that is, all // the blocks in a subzone are kept in a contiguous sequence. // Scan pending blocks first for any which doesn't cross to // a new subzone boundary (new sample rate). if (pending_blocks.size()){ for (i=0; i<pending_blocks.size(); i++) { blkjndex = pending J)locks[i]; if (instances[blkjndex]->alljnputsjτιarked() && !instances[blkjndex]->getjnstance pointer()-> // isjiewjrateJtlockO) prototype()->is_rate_changeJ>lockO) { pass_through(blk jndex, remaining, pending_blocks, passed_through = TRUE; } }} // if no ordinary blocks passed through, we can now pass through // a new subzone block if (!passed_through && pending )locks.size()){ for (i=0; i<pending_blocks.size(); i++) { blkjndex = pending J>locks[i]; #ifdef DEBUG cerr « "testing pass through for possible rate change block " M-81 << * stancesl lkjndex]->get_mstancejpointer0->hier_name 5tring() «"\n"; #endif if (instances[blkJndex]->allJnputs_markedO &&instances[blkJndex]->getJnstancejpointer()-> prototype()->isjrate_change_block()) { pass_through(blk Jndex, remaining, pending_blocks, newjratejptr); passed_through =TRUE; // make sure to break through just one subzone boundary //at a time! break; } return passed_through;} πiiiiii ifiiiiiiπimiπiiiimiiHiiiiuriiiiiiiiiiniiiiiiiiiimiiin^ // hier_block::set 3equenced_and_call_children // Mark this block as sequenced, and also recursively call //hierJ)Iock::sequence_children() to sequence all children if they // have not been sequenced before. // This is so that we can mark sub-zone info // for child blocks which we need to keep sub-zones together in parent blocks. void hierJ)lock::set 5equenced_and_call_children(int blkjndex, BOOLEAN* newjratejptr)! instance*instjptr; // make this block next in sequence sequence.append lk Jndex); instjptr = instances[blkJndex]->getjnstancejpointer(); // if child is hierarchical, try to sequence it if (!inst ptr->prototypeO->is Jeaf_block()) ! // if block has not been sequenced before, sequence its children, // then mark it as sequenced if (!( (hier tlock*) instjptr->prototype() )->are_children _sequenced()) { // save current block context and set instance info in block instjptr->push_context() ; M-82 ^ II recursively call sequence_children instjptr- >prototype()->sequence_children(newjrate_ptr); // restore previous context instjptr->pop_context(); } } else{ // block is primitive, so check if it's a rate change block, which // would create a new sample rate if (instjptr->prototype()->isj-ate_change_block()) // mark new instance as sequenced inst_ptr->set_sequenced(); } II hier_block::pass_through // Used to pass through a block which has all inputs marked. // Recursively calls hier_block::sequence_children() to sequence children // of the passed through block. This is so that we can mark sub-zone info // for child blocks which we need to keep sub-zones together in parent blocks. void hier_block::pass_through(int blkjndex, inpjist& remaining, int_array& pending Jriocks, BOOLEAN* newjratejptr)! int j; int inp jndex; int output jndex; int nxt tlk; BOOLEANnew_rate = FALSE; #ifdef DEBUG cerr « "passing through " « *instances[blkjndex]->getjnstancejpointer()->hier_name_string() « "\n"; #endif // set our block as sequenced & recursively sequence children set _sequenced_and_call_children (blk jndex, &new_rate) ; // remove this block from pending blocks list pending_blocks.remove(pending_blocks.find(blk jndex)); // remove this block's inputs from remaining inputs list remaining.iter jnit() ; while (remaining.next(&nxt_blk, &inp jndex)) { if (nxt_blk = blkjndex) M-83 remaining.remove(); } // add its output connections to our remaining list for (j=0; j<n_connections(blk Jndex); j++){ get_connection(blk_index, j, &nxt_blk, &in Jndex, &output jndex); // add to list only if input not marked, which would make a loop, // and if not really an output to the parent block, which is a special // negative pseudo-block index if (nxtjblk>= 0) { if (!mstances[nxtj lk]->ϊs_input_marked(inp Jndex)) { // add to remaining inputs list remaining.add(nxt_blk, inp jndex); // mark this input as reached mstances[nxt 3lk]->mark_input_asjreached(inp jndex); ffifdef DEBUG cerr « "marking input " « inp Jndex « " of block " << *mstances[nxtj)lk]->getjnstance pointer0->hierjιame 5-rϊng() « " as reached\n"; #endif // also add to pending blocks list if block not already on if (pending_blocks.find(nxt_blk) < 0) { pending_blocks[pending_blocks.size()] = nxt_blk; #ifdefDEBUG cerr « "adding " << *mstances[nxtJ lk]->getJnstancejpointer()->hier_name_string() « " to pending blocks on pass throughXn"; #endif } // if child set a new sample rate (sub-zone), // mark connecting blocks as newjrate blocks if (new_rate) instances[nxtJ)lk]->getJnstancejpointer()-> set_as jiew jrate_block() ; } else { -84 // this output goes to a marked input, which would make a loop // save this info about the output instances[blkjndex]->markJoopjo(output jndex); #ifdef DEBUG cerr. « "marking as loop FO " « outputjndex « " of block " « *instances[blkjndex]->getJnstancejpointer()->hier_name_string() « " as reached\n"; #endif } } } // tell caller if we had a rate change if (new rate) *newj-atejptr = newj"ate;} II seq J>lock::seqJ)lock // Constructor. seq >lock::seq >lock() { autosequence = FALSE; leaf_block = FALSE; manual J>lock = FALSE;} II seqJ>lock::~seqJ>lock // Destructor. seq Jtlock: : ~seq_block() { } II gsp_block::gsp_block // Constructor. gsp_block::gsp_block() ! autosequence = FALSE; leaf _block = FALSE; manuaLblock = TRUE; } II gsp_block::~gspj lock // Destructor. M-85 gspj>lock::~gsp >lock0 {} II new_gsp _asm_name // Create a new name for an asm block embedded in a gsp block. // Returns both a block name and an instance name. void new_jjsp_asm_name(string** blkjiame, string** inst_name)! static intasm >lock_count = 0; char coun ext| rOA_LIMIT]; char blk_name_arr|TrOA_LIMIT+10]; // create unique strings for block and instance names itoa(asm_block_count, count_text, 10); strcpy(blk ame_arr, "$$asm"); strcat(blk_name_arr, count_text); *blk_name = new string(blk_name_arr); strcpy (inst iame irr, "$$asmF'); strcat(inst ιame_arr, count_text); *inst_name = new string(instjιame_arr); // advance the index for next time around asm »lock_count++; } If gspJ)lock::add_new_asm _section // Add a new assembly language section, created as an asm block, in // this gsp block. mmmππiiiπiiπiiiiπiiirππuiiiiiimiiiuiuiminiiiπiiiiim void gspJblock::add ιew_asm_section(block* section)! string* blkjiame; string* inst_name; // generate a new name for this embedded asm block new_gsp_asm_name(cS blk_name, &inst_name) ; // set the name for this block, provide it doesn't already exist while (!section->set_block_name(blk ιame)) new_jjsp a5m_name(&blk_name, &inst jiame); // add a reference to this block hier Jrlock::addJ)lock ref(new blockjref(*blk_name, *inst_name, line)); } // block.hxx //block class M-86 //T. Montlick // 10/31/89 /* source code control: @(#)block.hxxl.56 10/7/91 */ #define BLOCK.DEF #ifndef STAND ARD_DEF #include "standard.hxx" #endif extern "C" { #include "mystdlib.h"} #ifndef INTRFACE_DEF #include "intrface.hxx" #endif #ifndef STRING_DEF #include "string.hxx" #endif #ifndef EXPR_DEF #include "expr.hxx" #endif #ifndef EXPR_HASH_DEF #include "exprhash.hxx" #endif #ifndef STRG_HASH_DEF #include "strghash.hxx" #endif #ifndef EXPR_ARRAY_DEF #include "expr arr.hxx" #endif #ifndef HMT_HASH_DEF #include "int_hash.hxx" #endif #ifndef BLOCK_HASH_DEF #include "blckhash.hxx" #endif #ifndef INT_ARRAY_DEF #include "int_arr.hxx" #endif #ifndef LONG_ARRAY_DEF #include "long_arr.hxx" #endif M-87 2+32 #ifndef STRG_ARRAYJ)EF #include "strg_arr.hxx" #endif #ifndefALLOCJTABLE_DEF #include "alloctab.hxx" #endif #ifndefBLOCK_ARRAY_DEF #include "blck_arr.hxx" #endϊf #ifndef BLOCK_REF_ARRAY_DEF ^include "bref_arr,hxx" #endif #ifndefFIELDS_DEF #include "fields.h" #endif #ifndef UTILITY JDEF #ϊnclude "utility.h" #endif #ifndef INSTANCE JDEF #include "instance.hxx" #endif #ifndef INP.LIST DEF #include "inp Jisthxx" #endif // we use yylex to get init values from files, so need token values #ifdefDOS #ϊnclude "ytab.h" #else #mclude "y.tab.h" #endif #ifdef SZ #undefSZ #endif #defineSZ 10 /* default array and hash table size */ // suffixes added to block names for subroutine body and call #defineSUBR_SUFFrX"$S" #defineC4 Δ XL_SUFFTX"$C" class instance; #ifndef INST_ARRAY_DEF M-88 #include "inst_arr.hxx" #endif // base class of block class which maintains info for a port block class block_chipJo{ BOOLEANis_port_block; // TRUE if block is an FO port expr* port_number; // which port number expr* trigger_source; // if signal source, which trigger number BOOLEANportJs .output; // TRUE if serial FO is output expr* port_config; // port config. word expr* port_entry_size;// size of a fifo entry expr_arraygpio_numbers;// non-empty when gpios declared int_arraygpio_directions;// non-zero for outputs expr_arrayrts_numbers;// non-empty when its' declared int_arrayrts_directions / non-zero for outputs public: block_chipJo(); -block_chipjo(); expr* trigger _source_expr() { return trigger _source; } expr* portjiumber _expr() ! return portjiumber; } expr* port_config_expr() { return port_config; } expr* port_entry _size_expr() { return port_entry_size; } BOOLEANis_port_output() { return port js_output; } BOOLEAN set_asjport(expr* portjium, expr* trigger, BOOLEAN is output, expr* config, expr* entry _size); BOOLEANis_sproc_output() { return (isjport_block && port js_output); } BOOLEANis_serial port() { return (isjport_block); } BOOLEANset_computeJine(expr* num); void setjjpio(expr* e, BOOLEAN b) { gpio_numbers.append(e);gpio_directions.append(b); } void set_rts(expr* e, BOOLEAN b) ! rts_numbers.append(e); rts_directions.append(b); } BOOLE ANhas_gpio(){ return (gpiojiumbers.sizeO > 0); } M-89 int n_gpiosO { return gpio_numbers.size(); } expr*gpio_expr(int i, BOOLEAN* is_out_ptr) ! *is Dut ptr = gpio_directions[i]; return gpio_numbers[i]; } BOOLEANhas_rts(){ return (rts_numbers.size() > 0); } int njrtsO [ return rts_numbers.size() ; } expr*rts_expr(inti, BOOLEAN* is outjptr) ! *is Dut ptr =rts_directions[i]; return rts_numbers[i]; } }; // base class of block class which maintains info for Fo to block class blockjo{ alloc_tableio jable; // inputs and outputs, in order declared ϊnt_arrayio_direction;// non-zero for outputs expr arrayio Jnit_val^/ init. expr. for pseudo-sampled output public: block Jo(); ~blockJo(); BOOLEANio illocate(string&name, expr* size, int* index) ! return io_table.allocate(name, size, index); } BOOIl£ANio jnd(string& name, int* index, expr** size) ! return io_table.find(name, index, size); } BOOLE ANallJo_declared()! return io_tøble.all_sizes_set(); } int io_table_size() { return io_table.size(); } expr*io_entry_sϊze(int i) ! return ioj:able.get_size(i); } string*ϊo ιame_atJoc(int loc) { return io_table.name_atJocation(loc); } string*io _name_atjndex(int index) ! return io_table.name_at_index(index); } int iojndex_toJocation(int index) { return Io_table.index_toJocation(index); } BOOLEANio Js_output(int i) ! return (io_directioπ[i] != 0); } void setJoJnit_value(inti, expr* e) { io jnit val[i] = e; } expr*getJo_inϊt_value(int i) { return io_init_val[i]; } BOOLEANsetJojsize ffld i ection(stιring* name, expr* size, int direction); }; // base class of block class which maintains info for micro intrface -90 class block_micro jo{ int arrayisjnicrojo;// TRUE if FO is uP interface location int_arrayis_micro_var;// TRUE if storage is uP interface variable int_arrayis_micro_symbol;// TRUE if symbol is uP interface public: block_microJo(); ~block_microjo(); void setjnicro Jo(int i, BOOLEAN b) ! isjnicro jo[i] = b; } void set_micro_var(int i, BOOLEAN b) ! isjnicro var[i] = b; } void setjnicro _symbol(int i, BOOLEAN b) { isjnicro_symbol[i] = b; } BOOLEANget_micro Jo(int i) ! return isjnicro Jo[i]; } BOOLE ANget_micro_var(int i) ! return isjnicro_var[i]; } BOOLEANget_micro_symbol(int i) { return is_micro_symbol[i]; } }; // base class of block class which maintains info for storage to block class block _storage{ alloc_tablestorage_table;// local storage, in order declared expr_arraystorageJnit_vai / storage location to init. expression int_arraystorage_line_numbers;// line #s which init storage locations int arraytop Jevel_stor Jine;// if include file, last top level line # int arraystorage ypes;// fixed, integer, hex, etc. int_arrayvariable_storage;// TRUE if variables, as opposed to wires public: block _storage(); ~block_storage(); BOOLEANstorage_allocate(string& name, expr* size, int* index) ! return storage_table.allocate(name, size, index); } void set_storage_size(int index, expr* size) { storage jable.set_size(index, size); } void set_storage_type(int index, char type) { storage_types[index] = (int) type; } void set_as_variable(int index, BOOLEAN var) ! variable_storage[index] = var; } -91 J BOOLEANϊs_a_variable(int index) ! return variable _storage[index]; } char get_non_phantom_storage_type(int index) { return (char) storage_types[index]; } stιrmg*nonjphantom 3toragejname itJndex(int index) ! return storage_table.name_atjndex(index); } string*storage_name atJocation(int location) ! return storage_table.name_atJocation(location); } int storage Jndex_to Jocation(int index) ! return storage jable.index_toJocation(index); } expr*non phantom 3torage_entry_size(int index) ! return storage_table.get_size(index); } BOOLEANstorageJmd(string& name, int* index, expr** size) { return storage_table.find(name, index, size); } void add _storageJnit(int index, expr* exprjptr); expr*non_phantom 5torage_init(int index) { return storage_init_val[index]; } int get_storageJine_number(inti) ! return storage Jine_numbers[i]; } int getj:opJevel 5torJine(inti) ! return topJevel_storJine[i]; } int non_phantom_storage_table_size() [ return storage_table.size(); } int non_phantom ιlloc 5torage_size() ! return storage_table.alloc_size(); } }; // base class of block class which maintains info for timezone class block_zone! expr* timezonejiame; // expr evaluating to a timezone name string expr* timezone rate; // rate, if specified, for timezone public: block_zone(); ~block_zone0; BOOLE44 set_timezone(expr* name, expr* rate); BOOLEANget_timezone(expr** name, expr** rate); BOOLE ANisjlmezonejriggeredO ! return timezone_name != (expr*) NULL; } BOOLEANis_sprocJuτput() { return is_timezone_triggered(); } M-92 }; // base class of block class which maintains virtual storage and FO info class block_virtual{ int_arrayis_virtual_storage;// TRUE if storage is really elsewhere strg_arrayvirt 5toragejpath-// path string for where virtual storage is inst_array virt_stor path Jnst;// instance reference for path BOOLEANis_virtualjo_block;// TRUE if this block is virtual FO block public: block_virtual(); ~block_virtual(); BOOLEANis 5torage_virtual(int i) ! return is_virtual_storage[i]; } string*get_virt_storagejpath(int i, instance** path jnst) { *pathjnst = virt_storjpath jnst[i]; return virt_storagejpath[i]; } void set_as_virtualJo() { is_virtualJo_block = TRUE; } BOOLEANis J>lock_virtualjo() ! return is_virtualJo_block; } void set_virtual 5torage(int i, string* path, instance* path jnst); }; // base class of block class which maintains info about a block which is // on a rate change boundary (decimation or interpolation) class block_rate_change! BOOLEANrate_change_block;// TRUE if block is before rate boundary BOOLEANdecimation; // TRUE if decimation, FALSE if interp. expr* change ratio; // interpolation or decimation ratio public: block_rate_change(); ~block_rate_change() ; void set_decimating(expr* ratio); void setJnterpolating(expr* ratio); BOOLEANis_rate_change_block() { return rate_change_block; } BOOLE ANis_decimating() ! return (rate_change_block && decimation); } BOOLEANis JnterpolatingO { return (rate_change_block && idecimation); } expr* get_change_ratio() M-93 { return change jratio; } }; class block_subroutine{ BOOLEANsubr j lock; // TRUE if block is subroutine BOOLEANcall J)Iock; // TRUE if block is subroutine call BOOLEANsubr j rm; // TRUE if inline block & has subr form int n_times_called;// if subr, # times called BOOLEANsubr Jnst_made; // in call block, TRUE if subr. instance instance*subr Jnst_ptr / ptr to subroutine instance public: block_subroutine(); ~block_subroutine() ; void set_subr_block() ! subr_block = TRUE; } BOOLEANis_subr_block() ! return subr_block; } void set_caU_block() ! caU_block = TRUE; } BOOLEANis_call_block() ! return caU_block; } void set_subrjbrmO { subr_form =TRUE; } BOOLEANhasjJubrjTor O { return subr brm; } void increment_call_count(){ n_times_called++; } int get_njimes_called()! return n_times_called; } void set_subr Jnst_made(instance* inst) { subrjnstjnade = TRUE; subr jnstjptr = inst; } BOOLEANis _subrjnst_made(){ return subr Jnst_made; } instance*get_subrjnstance(){ return subr Jnstjptr; } }; class block : public block_chip Jo, public block nicro Jo, public block_zone, public block_virtual, public block Jo, public block_storage, public bIock_rate_change, public block_subroutine{ string block jiame; // name for this block prototype string* filename; // name for file this block is in int startingjine;// line number for start of block alloc_tableparam_table;// parameters and symbols, in order decl. int njparams; //# of initial params in previous table expr_hashsymbol_val_table;// symbol name to expression strgjιashalias_name_table;// alias name to (symbol or alias) name expr arrayverϊfy expressions;// expressions to verify as TRUE strg_arrayverify_msgs / msg to output on verify failed BOOLEANautosequence // TRUE if block refs to be autosequenced BOOLEANleaf J lock; // TRUE if block is leaf (ASM) block M-94 BOOLEANmanual rtock; // TRUE if block has GSP phantom blocks BOOLEANis jnstantiated;// TRUE if block is instantiated by another BOOLEANinJiierarchy; // TRUE when this block in inst. hierarchy BOOLEANis Jndivisible; // TRUE of block should not be split expr_hash*override_table;// symbols to check first instance*instance jptr;// instance if block being instantiated alloc_tablelabel_table;// label name to index int_arraylabel_sequence;// index to sequence # of label int_arraylabel_offset;// index to label offset from start int_arraylabel_final;// label value is final rel. address BOOLEANabsolute_origin;// TRUE if block not relocatable int origin iddress;// start address if block not reloc. int elementjiumber;// # of elem. (typically instructions) int 1 jndex; // next index # for label BOOLEANphantom; // TRUE if phantom (linker-inserted) BOOLEANinit; // TRUE if init (once-only execution) BOOLEANblockJias Joops;// TRUE if instances form loops int arrayloop _wires; // TRUE for wires which form loops int variant_count;// # of variant instances for this block friend class asm J>lock; friend class hier_block; friend class seq tlock; friend class gsp_block; public: block(); ~block(); BOOLEANset_block_name(string*); string*get_block jiameO ; string* get_filename(){ return filename; } int get_startingjine(){ return starting Jine; } BOOLEANadd jo_name(string* name, int* index, BOOLEAN isjnicro); BOOLEANaddjparam_name(string* name, int* index); BOOLEANadd_symbol_name(string* name, int* index); BOOLEANadd_symbol_name(string* name, int* index, BOOLEAN isjnicro); BOOLEANadd _expression_name(string* name, expr* exprjptr); BOOLEANadd_aliasjιame(string* newjiame, string* equivjiame); BOOLEANadd_storage_name(string* name, expr* size, int* index, char type, BOOLEAN isjnicro, BOOLEAN is_variable); expr* get _storage_init(int index); -95 char get_storagejype(int index); int storage_table_size(); expr*storage entry_size(int i); string*storage_name_atjndex(int index); int storage )ffset_atjndex(int index); void add_verifyj≥xpression(expr* exprjptr, string* fail_string); expr*sameJeveI_ttansIation(string* name) ; expr*translate_wϊthjnstances(string* name, instance** path Jnstjptr, instance** symbol_instjptr); expr*transIation(string* name); expr* translate_to param_val(string* name); BOOLEANtranslateJoJo(string* name, int* value); BOOLEANtranslatej:o 5torage(string* name, int* value); BOOLEANknown 5ymbol(string* name); BOOLEANtranslation j own(string* name); BOOLE ANis_autosequence(){ return autosequence; } BOOLEANis JeafJblockO { return leaf_block; } BOOLEANis JndivϊsibleJ)lockO{ return is jndivisible; } void set_asjndϊvisible(){ is Jndivisible = TRUE; } BOOLEANis jnanualjjlockO! return manual J>lock; } virmalstrmg*verifyJr)lock jrefsO ; virtualvoid refsjter jnit(); virtualBOOLEANnextjref(block_ref**); expr*check_verify_expressions(); void set_asJnstantiatedO{ ϊsJnstantiated =TRUE; } BOOLE ANϊsJtJnstantiatedO! return is Jnstantiated; } void set n_hierarchy(BOOLEANb){ in_hierarchy = b; } BOOLEANis JnJιierarchyO{ return injiierarchy; } BOOLEANlook_up 5torage_name(string* s, int* index); BOOLEANlook_up_symbol_name(string* s, expr** expr_ptr); BOOLEA ook upJo_name(string* s, int* index); BOOLEANlook_up param_name(string s, int* index); string*param_name_atJoc(int loc) { return param_table.name_atJocation(loc); } string*param _name_atjndex(int index) ! return param_name_atJoc(param able.index_toJocation(index)); } expr*param_expr_atjndex(int index); int param_table_size()! return param jable.size(); } int get_n paramsO { return njparams; } void set_override_symbols(expr_hash* symbols) ! override_table = symbols; } int n_verify_expressions() ! return verify _expressions.size(); } expr* get_verif y expression (int i) ! return verify_expressions[i]; } int storage _error(char* msg_code, int loc, char* s); int storage_warning(char* msg_code, int loc, char* s); int out_storage_code(int i, ostream& out, BOOLEAN* is_vector, long_array* v); void outjrest_of 5torage_vector(long_array* p, ostream& data); int out_storage(ostream& out); string*get_verifyjnsg(int i) { return verify jnsgsfi]; } void set jnstance(instance* inst) { instancejptr = inst; } string*hierjo_name_atJndex(int index); string*hier_storage _name_at jndex(int index) ; string*hier Jabel jιame_at jndex(int index) ; string* hierjparam_name_at jndex(int index); BOOLEANlabel_name_toJndex(string* name, int* index); BOOLEANadd Jabel jιame(string* name, int address); int assign Jabel jndex(string* name); int label_table_size(); string*label_name_atjndex(int index); int label_address(int index); int label_seq_at jndex(int index); int labe offset_at jndex(int index); int get_addressJromJabel_name(string*); void set Jabel Dffset(int index, int offset); void iterJnit_symbols(); BOOLEANnext_symbol(string** namejptr, string** hierjptr, expr** valjptr); void set_origin(int org) { absolute Diigin = TRUE; origin_address = org; } BOOLEANis_absolute(){ return absolute Drigin; } int org() { return origin_address; } int instrjiumberO! return element jiumber; } void advanceJnstrjiumberO ! element_number++; } void set_phantomO{ phantom = TRUE; } BOOLEANis_phantom(){ return phantom; } void set_init() init = TRUE; } BOOLEANis_init0{ return init; } v uaBOOLEANsequence_children(BOOLEAN* newjratejptr); BOOLEANdoesJ>lock_haveJoopsO{ return blockjiasjoops; } BOOLEANisJoop_wire(inti){ return Ioop_wires[i]; } int new_variant_number() { return variant_count++; } }; // constants used to evaluate asm operands and 24-bit numbers #define HIGH MASKOxFFFF8000 #defineLOW_MASK0x00007FFF #defineffiGH_SHIFT9 /* 24 bite width - 15 bit operand */ #define REALj?ACTOR4194304 /* 2 Λ 22 */ #define MAX_REAL1.99999999999 #define MTN_REAL-2.0 #defineWORD_MASK0x00FFFFFF #define NEG_WORD_OVERFL0xFF000000 class asm_block : public block! expr ιrrayoperand_vaIues;// operand value index to expression // arrays for instruction fields, indexed by instruction number: int_arrayopcode_fields; int_arrayaddrjnode_fields; int_arrayoperand_fields; int_arrayinstrjine_numbers; int arrayrelocation; int_arrayrelocJevel; int nτaylinked_addr_mode; int_arraylinked_operand; int arrayincludejevel; int_arraytopJevel jnstr Jine; expr* duration; int n Jnstructions;// # of instructions in block public: asmj>lock0; ~asm_block0; int add_operand_value(expr* exprjptr); void enter_fields(int index, int linejium, int opcode, int addrjnode, int operand, int relocjevel); int eval_operands(BOOLEAN ope ands_known); void out jnstruction(int line, ostream& out); void outjreloc jnstruction(int line, ostream& out); int out_asm(ostream& out); void value_error(int eval_status, expr* exprjptr, int i, char* name); void value_warning(int eval_status, expr* exprjptr, int i, char* name); int outJisting(istream& in, ostream& out, int& listing Jine); BOOLE ANset_duration(expr*) ; void set_njnstructions(int n){ n jnstructions = n; } int getjijnstructionsO! return n jnstructions; } expr*get_duration_expr() ! return duration; } BOOLEAN check_duration(); void out_addr_and jnstruction(int instr, ostream& listing); }; #ifdef OWC extern "C" ! #endif int readjnit_file(string* name string, int size, long_array* storage_vector, int index); #ifdef OWC} #endif class hier_block : public block! bref_arrayinstances; // blocks instantiated in this one BOOLEANchildren sequenced / TRUE if child blocks have been sequenced int ref jndex; // ref names iterator index BOOLEANrefs_connected; // TRUE when refs have been wired together inp Jistblockjnputs;// child inputs that are block inputs int_arraywire _use_count;// # of inputs from each wire int_arrayinput_use_count;// # of inputs from each block input int_arraysequence; // sequence for refs public: hier_block(); ~hier_block(); BOOLEAN add J>lock_ref(block_ref*);// add a block ref for a new instance string*verify_block _refs() ; void refsJterjnitO; BOOLEANnext_ref(block_ref**); int get_n_children() { return instances.sizeO; } void add_connection(int i, int blkjndex, int input jium, int output) ! instances[i]->add_connection(blkJndex, input_num, output); } int n_connections(inti) ! return instances[i]->n_connections(); } BOOLEANget_connection(inti, int which, int* blkjndex, int* inputjium, int* output) ! return instances[i]->get_connection(which, blkjndex, input_num, output); } void setjrefs_connected(){ refs_connected = TRUE; } BOOLEANarejrefs_connected(){ return refs_connected; } bIock*get_blockjpointer(int i) ! return instances[i]->get_block_pointer();} instance* get jnstancejpointer(int i) ! return instances[i]->getjnstancejpointer();} void addJ:oJnputs(int which ref, int which jnput) ! block Jnputs.add(which_ref, which Jnput); } void inputs JterJnitO ! block Jnputs.iterJnitO; } BOOLEANnext_input( int* which jref, int* whichjnput) ! return block jnputs.next(which jref, whichjnput); } void bump_wire_use_count(inti) ! wϊre_use_count[i]++; } int get_wire_use_count(int i) ! return wire_use_count[i]; } void bumpJnput_use_count(inti) { inputjιse_count[i]++; } " int getJnput_use_count(int i) { return input_use_count[ϊ]; } blockjref* get_childJ)lock_ref(int i) ! return instances^]; } BOOLEANsequence_children(BOOLEAN* newjratejptr); void markJoops(inp_list& remaining, int_array& pending_blocks, BOOLEAN* newjratejptr); BOOLEAN pass_through_fully_marked_blocks(inp Jist& remaining, int_array& pending_blocks, BOOLEAN* newjratejptr); void set_childrenjsequencedO { children _sequenced = TRUE; } BOOLEANare_children_sequenced() { return children jsequenced; } void set 5equenced_and_call_children(int blkjndex, BOOLEAN* new_rate ptr); void pass_through(int, inpjist&, int_array&, BOOLEAN* newjratejptr); int sequenced_child(int i) { return sequence[i]; } }; class seq_bloc : public hierj lock{ public: seq_block(); ~seq_block(); }; class gsp_block : public seq_block{ public: gsρ_block(); ~gsρ_block(); void add_new_asm_section(block* section); }; // other functions void value_goof_msg(int eval_status, expr* exprjptr, char* name, char* msg); extern "C" intyylex(); // bref _arr.cxx // derived class for block_ref array // Terry Montlick // 10/10/89 /* source code control: */ static char SccsID[] = "@(#)bref_arr.cxxl.56 10/7/91"; #include "bref_arr.hxx" bref_array : : bref_array () { } bref_array::bref_array(int i) { } // bref_arr.hxx // header for derived blockjref array class // T. Montlick // 10/10/89 /* source code control: @(#)bref_arr.hxxl.56 10/7/91 */ #define BLOCK_REF_ARRAY_DEF #ifndef ARRAYjDEF #include "array.hxx" ■ #endϊf ■ fndef BLOCK_REFJDEF #include "blck ref.hxx" #endif class bref array : public array! public: bref_array(); bref_array(inti); block_ref*&operator □ (inti) ! return (block_ref*&) array: :operator[] (i); } int find lock ref* ptr) { return array::find(ρtr); } void append(block_ref* ptr)! array::append(ptr); } bref_aπray&operator+(bref_array& a) ! return (bref_array&) array::operator+((array&) a); } bref_array&operator+=(bref_array& a) !a = *this + a; return *this; } }; * * Command line functions * * Terry Montlick 3/20/90 * /* source code control: */ static char SccsIDQ = "@ (#)cmdline.cl.56 10/7/91"; ■ ffiuiclude <ctype.h> • Mfdef OWC extern "C" ! #endif * * getjSIenames * * Parse a command line into file names, ignoring command switches. * Valid for either DOS or unix. * Passed "argc" and "argv" from the main program, this function fills * in a caller-supplied array to hold file names. * * int max_files- max # of file names the user's array will hold. * int* n ϊles jptr- ptr to # of file names founds * char* files - array of ptrs to file name strings * ***** *$**#:):*********:):*:(:*********** ********** ****************************** ***/ void get_filenames(argc, argv, max_files, n_filesjptr, files) int argc; char*argv[]; int max_files; int* n_filesjptr; char* filesπ;{ int n_files = 0; int i; for (i=l; i<argc; i++){ /* accept unix-style switch */ if (*argv[i] == '-') #ifndef UNIX /* "/" would be confusing with unix directories */ else if (*argv[i] == V) #endif else { /* a non-switch is assumed to be a file name */ if (n jBles < max Jϊles) { /* first character of file name is 1st */ files[n ϊles] = argv[i]; n_files++; } } } *n_filesjptr = n_files;} * * find_switch * * Function used by do_switches to search for a particular switch character * in an array. * M-1 03 '448 ****************************************************************************/ int find_switch(n 5witches, switches, sw, which_switchjptr, no_valjptr) int n_switches; /* # of switches in search array */ char switchesQ; /* array of switches */ char sw; /* switch to search for */ int* which _switchjptr;/* if found a match, matching switch position */ int* no_val ptr; /* set TRUE if switch should not have a value */{ int j; char upper_sw; int found; char match _sw; int no_value; /* convert switch to upper case for compare */ if (islower(sw)) upper_sw = toupper(sw); else upper_sw = sw; found = 0; for (j=0; j<n_switches; j++){ /* get potential matching switch character, converting * to upper case if necessary (which signifies that switch * does not have an argument immediately following it) */ match _sw = switchesQ]; if (no value = islower(match_sw)) match_sw = toupper(match_sw); if (upperjsw = match _sw) { found = 1; *whϊch_switchjptr = j; *no valjptr = no_value; break; }} return found;} /************#**#***#*:M:*************************#*********^ * * do_switches * * Parse a command line for switches and execute action routines for them. -104 4 O * Valid for either DOS or unix. * Passed "argc" and "argv" from the main program. * * Switches in array must be upper case if the corresponding function can * take an argument immediately following the switch, and lower case if not. * * int* n ^ switches- # of different switches * char switchesQ- array of single-character switches * int (*switch Juncs[])() - array of ptrs to action routines * * If an unknown switch was encountered, return non-zero and bad switch * character in "bad_sw". * If an action routine failed, return its return value and set * "bad_sw" to 0; * int do_switches(argc, argv, n_switches, switches, switch Junes, bad_sw) int argc; char*argv[]; int n jwitches; char switchesQ; #ifdef OWC int (*switch uncs[]) (char*); #else int (*switchJuncsQ) (); #endif char* bad _sw;{ /* switch character is second */ sw = argv[ιj[l]; if (find 5witch(n swϊtches, switches, sw, &j, &no_value)) { /* found the switch, so see if it can take a value */ if (no_value) { /* no value for switch, so any remaining characters * must be more switches */ if (status = (*switch_funcsQ]) ("")) return (status); /* check for remaimng non- valued switches following */ for (k=2; ((sw=argv[ιj[k]) != '\0'); k++) { if (find 5witch(n 3wϊtches, switches, sw, &j, &no_value)) { if (status = (*switch_funcs[j]) ("")) return (status); } else { *bad_sw = sw; return -1; } } } else { /* first character of value is 3rd */ sw_val = argv[i] + 2; if (status = (*swϊtchJuncsQ]) (sw_val)) return (status); } else M-106 { 451 *bad_sw = sw; return -1; } } } return 0;} #ifdef OWC} #endif * * Command line functions * * Terry Montlick 3/20/90 * /* source code control: @(#)cmdline.hl.56 10/7/91 */ void get_filenames(int, char*[], int, int*, char*[]); typedef int (*PTIFSQ) (char*); int do_switches(int, char*[], int, charQ, PTIFS, char*); // defines.cxx // Routines to handle #define directive // T. Montlick // 10/31/89 /* source code control: */ static char SccsIDQ = "@(#)defines.cxxl.56 10/7/91"; #ifndef DEFINES_DEF #include "defines.hxx" #endif // hash table for defines strg_hashdefine_table(SZ); #ifdef V6 extern "C" ! #endif #ifdef OWC extern "C" ! #endif II enter_define // Set the given define name and value in the define name table. // This is triggered from a "#define" macro. void enter _define(string* new_name, string* value)! string*old_yal; // if name already present, don't override it if (!define_table.find(*new_name, &old_val)) define_table.add(*new_name, value);} II find_define // See if the given identifier is a define name, and if so, return //its value. // Returns FALSE if no such define name. BOOLEANfind_define(string* name, char** value)! string* defined_as; if (define_table.find(*name, &defined_as))! * value = &(*defined_as)[0]; return TRUE;} else return FALSE;} #ifdefV6} #endϊf ffifdefOWC} #endif // defines.hxx // Routines to handle #define directive //T. Montlick // 10/31/89 /* source code control: @(#)defines.hxxl.56 10/7/91 */ #define DEFINES_DEF #ifndefSTRING_DEF #include "string.hxx" #endif ffifndef STRG HASHJOEF ■ ffinclude "strghash.hxx" #endif #ifdefSZ #undef SZ #endif #defineSZ 20 /* default array and hash table size */ extern "C" { extern voidenter_define(string* newjiame, string* value); extern BOOLEANfind_define(string* name, char** value);} #define ERR STR.DEF /* source code control: @(#)err_str.hl.56 10/7/91 */ /* error and warning msg strings */ #defineERR_STRING"ERROR - " #defineWARN_STRING"WARNING - " #defineERR DELIM":\n " // expr.cxx // expression class functions // T. Montlick // 10/2/89 /* source code control: */ static char SccsIDQ = "@(#)expr.cxxl.56 10/7/91"; #ifndef EXPRJDEF #include "expr.hxx" #endif #ifdef DEBUG #undef DEBUG #endif II expr _element: :expr_element(double) // Constructor for an expr_element real value. expr_element::expr_element(double d, expr_element* p=0, expr_element* n=0, int rt=ABSOLUTE){ contents.real_value = d; type = REAL_VALUE; if (prev = p) p->next = this; if (next = n) n->prev = this; relocjype = rt; relocjevel = 0;} II expr _element: :expr_element(long) // Constructor for an expr_element integer value. exprjelement::expr_element(long d, exprjelement* p=0, exprjelement* n=0, intrt=ABSOLUTE){ contents.int_value = d; type =INT_VALUE; if (prev = p) p->next = this; if (next = n) n->prev = this; reloc_type = rt; relocjevel = 0;} // expr 5lement::expr element(string*) // Constructor for an expr_elεment string. iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiriiiiffiiiniiiiniifiiiii expr 3lement::expr ilement(string* s, exprjelement* p=0, expr_element* n=0)! contents.symbol = s; type = SYMBOLJVALUE; if (prev = p) p->next = this; if (next = n) n->prev = this; reloc_type = ABSOLUTE; relocjevel = 0;} //expr_element::expr_element(char) // Constructor for an expr_element character operator. expr 3lement::expr_element(charc, expr_element* p=0, exprjelement* n=0)! contents.oper = c; type = OPER; if (prev = p) p->next = this; if (next =n) n->prev = this; reloc_type = ABSOLUTE; relocjevel = 0;} II exprjelement: :expr_element() // Constructor for an expr_element with no contents. exprjelement: :expr_element() ! contents.oper = 0; type = OPER; prev = next = 0; relocjrype = ABSOLUTE; relocjevel = 0;} II expr_element: :expr _element(expr _element) // Constructor for an expr_element called with an expr _element exprjelement: :expr_element(expr_element& e, exprjelement* p=0, expr_element* n=0){ // copy contents except for pointers type = e.type; switch (type)! case SYMBOLJVALUE: contents.symbol = e.contents.symbol; break; case INT_VALUE: case EVAL_ERROR: contents.int_value = e.contents.int_value; break; case REAL.VALUE: contents.real_value = e.contents.rea value; break; case OPER: contents.oper = e.contents.oper; break;} if (prev = p) p->next = this; if (next = n) n->prev = this; reloc_type = e.reloc_type; relocjevel = crelocjevel;} // expr_element::~expr_element0 // Destructor. // Delete this element plus all succeeding elements. expr_element::~expr_element()! if (prev) prev->next = next; if (next) next->prev = prev; } II expr_element::operator=0 // Assignment operator from another expression element // Creates a copy of this element. void expr_element::operator=(expr_element& e)! if(this == &e) return; // don't assign to self type = e.type; switch (e.type)! case SYMBOL.VALUE: contents.symbol = e.contents.symbol; break; case INT_VALUE: case EVAL_ERROR: contentsint value = e.contents.int_value; break; case REALJVALUE: contents.real_vaIue = e.contents.real_value; break; case OPER: contents.oper = e.contents.oper; break;} relocjype = e.relocjype; relocjevel = e.relocJeveI;} II expr_element::real_value() //Return real value of expression element. doubleexpr_element::real_value() ! if (type == REALJVALUE) return contents.real_value; else if (type == INT_VALUE) return (double) contents. in t_value; else cerr « "error: trying to take real value of non-valued expression elemenfm"; return 0.0; } II expr_element::int_value() // Return integer value of expression element. long exprjelement: :int_value(){ if (type == INT_VALUE) return contents.int value; else if (type == REALJVALUE) return (round(contents.int_value)); else cerr « "error: trying to take int value of non- valued expression elementm"; return 0;} II exprjelement: :symbol() // Return symbol value of expression element. string*expr _element: :symbol() { if (type == S YMBOLJVALUE) return contents.symbol; else cerr « "error: trying get symbol from non-symbol element \n"; return 0;} II expr_element::error_code() // Return error code for EVAL_ERROR expression element. int expr_element::error_code(){ if (type == EVAL_ERROR) return (int) contents.int_value; else cerr « " error: trying to get error code from non-error expr. elementm"; return 0;} II exprjelement: :appendO // Append an exprjelement to this one. void expr_element::append(expr_element* his){ next = his; his->prev = this; // link in backward pointer} II get 3perator_string // Get a string version of the operator argument iiiiiiiiiiiiiiiiiiiiiifiiiriiiiifiriiiiiiiifiiiifirifiiiiiiiiiiiiifiiiiiiifiiii void get_operator_string(char c, string& op)! switch(c){ case 'U: op = "log"; break; case Ε': op = "exp"; break; case € Q': op = "is equal to"; break; case N * : op = "is not equal to"; break; case '<': op = "is less than"; break; case V: op = "is greater than"; break; case T: op = "is less than or equal to"; break; case * g': op = "is greater than or equal to"; break; case 'r': op ="»"; M-114 break; 459 break; default: op = chr(c); } } II output stream operator for expr_element list // Called originally for the last element of the (postfix) list, // this operator will recursively call itself for an operator's arguments // so that infix output is generated. // NOTE: the expression element pointer argument is changed to point to // the element before the result of this output. ostream& operator « (ostream& s, expr_element*& e){ string op(""); expr_element*us; #defineMAX_CHRS100 // if there is no previous element, this is the listhead, so just exit. if (!e->prev) 5 return s; // save pointer this element, and set argument to point at previous // which is correct for a non-operator. us^=e; e = e->prev; switch(us->type) ! case SYMBOLJVALUE: s « *(us->contents.symbol); break; case INT_VALUE: • s « us->contents.int_value; break; caseEVAL_ERROR: s « "error:" « us->contents.int_value; break; case REALJVALUE: s « us->contents.real_value; // make sure to add a ".0" if necessary to signal a real int int part = (int) us->contents.real_value; if ((us->contents.real_value - intjpart) == 0.0) s « ".0"; break; case OPER: get_operator_string(us->contents.oper, op); // check for unary or binary operator if (unary_operator(us->contents.oper)) { // output this operator, followed by our argument s « op « " " « e; } else { // binary operator, so must get and save 2nd argument // create an output stream to hold this argument char arg_2_text[M4AX_CHRS]; ostream arg_2(MAX_CHRS, arg_2_text); // initialize text array with nulls, so string gets terminated M-116 for (int i=0; i<MAX_CHRS; i++) arg_2_text[i] = '\0'; // call previous element to get its value arg_2 « e; // e now points to 1st argument, so we can output all s « e « " " « op « " " « arg_2_text; } break; } return s;} II negate ^ operator // Turn this operator into its negation, if possible. Returns TRUE if // we must negate arguments to this operator. // Some operators get a "NOT' inserted after them by this function. BOOLEAN expr_element::negate _operator() { expr_element*e; BOOLEAN negate args = TRUE; if (type == OPER){ switch(contents.oper) { case 'Q': contents.oper = 'N';// == becomes != negate_args = FALSE; break; case 'N': contents.oper = 'Q'-JI != becomes == negate_args = FALSE; break; case '<': contents.oper = 'gV/ < becomes >= negate_args = FALSE; break; case '>': contents.oper = Υ-JI > becomes <= negate args = FALSE; break; M-117 case T: contents.oper = ;// <= becomes > negate_args = FALSE; break; case contents.oper = '<';// >= becomes < negate_args = FALSE; break; case 'a': contents.oper = 'o'J' I and becomes or break; case 'o': contents.oper = 'a';// or becomes and break; case 'n': // "not" does not negate args, and gets detected and deleted by caller negate_args = FALSE; break; default: // default is to modify this operator with a "NOT' operator e = new expr_element('n\ this, this->next); // negate has been performed, so args don't get changed negate_args = FALSE; }} return negate _args;} II negateO // Called originally for the last element of the (postfix) list, // this function will recursively call itself to negate this list, // modifying it with a list which is the negation of the original. // It negates only if the argument is TRUE. // Returns a pointer to the element remaining right before the negation, // whether on not negation was called for. // That is, if we are negating an argument, we return a pointer to the // element right before the argument. expr_element* expr_element::negate(BOOLEAN negate Jt)! expr_element*previous; expr_elemeήt*e; BOOLEAN negate _args; char op; BOOLEAN delete_this_element = FALSE; // if there is no previous element, this is the listhead, so just exit. if (!prev) return this; // save previous element, because this previous = prev; // for an atomic type, simply insert a "NOT' after it switch(type){ case SYMBOLJVALUE: case INTJVALUE: case EVAL_ERROR: case REALJVALUE: if (negate jt) e = new expr_element('n', this, this->next); break; case OPER: // try to negate operator. if (negate jt) { // if this operator is "NOT', set flag to delete in before exit if (contents.oper == 'n') delete_this_element = TRUE; negate_args = negate _operator(); } else negate_args = FALSE; op = contents.oper; // negate previous argument, if required previous = previous->negate(negate_args); // if binary operator, there is a second argument to process if (!unary operator(op)) previous = previous->negate(negate_args); break;} // if this was "not" operator, need to delete this element if (delete_this_element) delete this; -119 // return the next most previous element return previous;} imiπimtiiiiiiiππiiiiiπππiiiiiπmimiiiiiiπiimπiiiiiiiiiiiiiπi if expr_element::last0 // Return the last element of a list nimm H tuiiiiuimmuimiiiummiiπtiMiiiiiiiiuiimmmuiu expr j element* exprjelement: :last() ! expr_element*p; p = this; while (p->next) p = p->next; return p;} II expr::expr(long) // Constructor for an expression consisting of a single integer value. expr::expr(long d, int r)! exρr_element*elem; elem = new expr_element(d, &listhead, 0, r); relocjevel = 0;} II expπ:expr(double) // Constructor for an expression consisting of a single real value. expr::expr(double d, intr)! expr_element*elem; elem = new expr_element(d, &listhead, 0, r); relocjevel = 0;} II expr::expr(string*) // Constructor for an expression consisting of a single symbol string. expr::expr(string* s){ expr_element*elem; elem = new exprjelement(s, &listhead); relocjevel = 0;} II expr::expr(char) // Constructor for an expression consisting of a single character operator. -120 expr::expr(char c){ expr_element*elem; elem = new expr_element( (char) c, &listhead); relocjevel = 0;} // expr::expr(expr) // Constructor for an expr called with an expr. // Copies the entire expression. expr::expr(expr& e){ expr_element*srcjptr; expr_element*destjptr; expr_element*prev_destjptr; srcjptr = &e.listhead; destjptr = &this->listhead; prev_destjptr = (expr_element*) NULL; while (srcjptr)! if (!dest_ptr) destjptr = new expr_element(*srcjptr, pre v_dest jptr); else *destjptr = *src_ptr; // advance to next element prevjjest ptr = destjptr; destjptr = destjptr->next; srcjptr = srcjptr->next;} // DOS-16M version crashes on this copy if called with null expression, // so check first if (&e) reloc Jevel = e.reloc Jevel; else relocjevel = 0;} II expr::expr(expr_element) // Constructor for an expr called with an expr_element expr::expr(expr_element& e)! expr_element*destjptr; destjptr = new expr_element(e, &this->listhead); M-121 relocjevel = 0;} II exprπexprO // Constructor for an expression with nothing in it expr::expr(){ expr_element*elem; elem =ne expr_element( (char) 0, &listhead); relocjevel = 0;} //expr::~exprO //Destructor. expr::~expr(){ // iteratively delete the first element of the expression while (lisfhead.next) delete listhead.next; } II expπ:operator=() // Assignment operator from another expression. // Creates a copy of this expression. iπiiiiiiiiiiiiiiiiiiiiiiπiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiimiiiiiiiiiiiititr void expr::operator=(expr& e){ expr_element*src_ptr; expr_element*destjptr; expr_element*prev_destjptr; ϊf(thϊs = &e) return; // don't assign to self srcjptr = &e.listhead; destjptr = &this->listhead; prev_dest_ptr = (exprjelement*) NULL; while (src_ptr)! if (!dest_ptr) destjptr = new expr_element(*src_ptr, prev estjptr); else *dest ptr = *srcjptr; // advance to next element prev_destjptr = destjptr; dest_ptr = dest_ptr->next; -122 srcjptr = srcjptr->next; }} II expr::concat(expr*) // Concatenate an expression to the end of this one. void expr::concat(expr* e)! expr_element*ourJast; expr_element*his_first; // find the last element of our expression, and point to it our Jast = listhead.next; while (ourJast->next) our Jast = our Jast->next; his_first = e->listhead.next; // put his list following this one ourJast->append(his jrst); // delete him, but null him out first! e->listhead.next = (expr_element*) NULL; delete e;} II opjrequires JntegersO // Returns TRUE if operator requires integers. BOOLEAN opjrequires jntegers(char op){ switch(op){ case '&': case 'I': case ' Λ ': case 'r': case 's': return TRUE; default: return FALSE; } } II expr-eval Jntegers DpO // Evaluate the binary operator which is in the expression element pointed to. // This operator requires two integers. // The arguments are in the previous expression elements, and all M-123 // are replaced by the result void expr::eval jntegers_op(expr_element* e)! long int_argl, int_arg2; //integer arguments int argl jreloc, arg2_reloc;// relocation types for arguments int argl Jevel, arg2 Jevel; if (e->ρrev->type = INTJVALUE) { ϊnt_arg2 = e->prev->int_value(); e->type = INTJVALUE; } else if (e->prev->type = EVAL_ERROR) *e = *e->prev; else{ e->type = EVAL_ERROR; e->contents.int_value = rNT_REQUIRED; } arg2 jreloc = e->prev->what reloc_type(); arg2 Jevel = e->prev->what jreloc Jevel(); delete e->prev; // check 1st argument only if 2nd is ok if (e->type !=EVAL_ERROR)! if (e->prev->type = INT_VALUE) { int_argl = e->prev->int_value(); e->type = INT_VALUE; } else if (e->prev->type == E VALJERROR) *e = *e->prev; else { e->type = EVAL_ERROR; e->contents.int_value = INT_REQUIRED; } argl_reloc = e->prev->whatjre!oc_type(); argl Jevel = e->prev->whatjrelocJevel(); delete e->prev; } if (e->type != EVAL_ERR.OR){ switch(e->contents.oper) { M-124 case '&': e->contents.int_value = intjargl & int_arg2; break; case : e->contents.int_value = intjargl I int_arg2; break; case ' Λ ': e->contents.int_value = int_argl Λ int ιrg2; break; case Y: e->contents.int_value = intjargl » int_arg2; break; case 's': e->contents.int_value = intjargl « int arg2; break; } // take whichever reloc type is nonzero if (argl_reloc != ABSOLUTE) { e->reloc_type = argl j-eloc; e->reloc Jevel = argl Jevel; } else { e->reloc_type = arg2 jreloc; e->relocJevel = arg2 Jevel; } } } II expr::eval_reals_op() // Evaluate the binary operator which is in the expression element pointed to. // This operator uses two reals, integers being converted to reals. // The arguments are in the previous expression elements, and all // are replaced by the result. void expr::eval_reals_op(expr_element* e){ doubleargl, arg2; // binary arguments int argl jreloc, arg2 jreloc;// relocation types for arguments int argl Jevel, arg2 Jevel;// relocation levels for arguments 25 if (e->prev->type = REAL_VALUE)! arg2 = e->prev->real_valueO; e->type = REALJVALUE; } else if (e->prev->type = INTJVALUE) ! * arg2 = e->prev->real_value(); e->type = INTJVALUE; } else if (e->prev->type = EVAL_ERROR) *e = *e->prev; else! e->type = EVALJERROR; e->contents.int_value = NUM_VALUE OT_KNOWN; } arg2 reloc = e->prev->what_reloc_type(); arg2 Jevel = e->prev->what_relocJevel(); delete e->prev; // check 1st argument only if 2nd is ok if (e->type != EVAL_ERROR) ! if (e->prev->type = REAL_VALUE) { argl = e->prev->real_valueO; e->type = REALJVALUE; } else if (e->ρrev->type == INT_VALUE) argl =e->prev->real_value(); else if (e->prev->tyρe == EVAL_ERROR) *e = *e->prev; else { e->tyρe = EVAL_ERROR; e->contents.int_value = NUM_VALUE_NOT_KNOWN; } argl jreloc = e->prev->what reloc_type(); argl Jevel = e->prev->what_relocJevel(); delete e->prev;} if (e->type != EVAL_ERROR){ // assume relocation type of first argument e->reloc_type = argl jreloc; e->relocJevel = argl Jevel; switch(e->contents.oper) { case + : e->contents.reaLvalue = argl + arg2; // take whichever reloc type is nonzero if (argl _reloc = ABSOLUTE) { e->reloc_type = arg2_reloc; e->relocJevel = arg2 Jevel; } break; case '-': e->contents.real_value = argl - arg2; // subtracting same reloc type yields ABSOLUTE (0) if (argl jreloc == arg2_reloc) e->reloc_typc = ABSOLUTE; break; case <*'. e->contents.real_value = argl * arg2; break; case V: e->contents.real_value = divide(argl, arg2); break; case ' : e->contents.real_value = logn(argl, arg2); break; case Ε': e->contents.real_value = expn(argl, arg2); break; case 'Q': e->contents.real_value = (double) (argl == arg2); e->type = 1OTJVALUE; break; case 'N': e->contents.real_value = (double) (argl != arg2); e->type = INT_VALUE; break; case T: e->contents.real_value = (double) (argl <= arg2); e->type = INT_VALUE; break; M-127 case 'g': e->contents.real_value = (double) (argl >= arg2); e->type = INT_VALUE; break; case '<': e->contents.real_vaIue = (double) (argl < arg2); e->type = INTJVALUE; break; case V: e->contents.real_value = (double) (argl > arg2); e->type = INT_VALUE; break; case 'a': e->contents.real_value = (double) (round(argl) && round(arg2)); e->tyρe = ESTTJVALUE; break; case 'o': e->contents.real_vaIue = (double) (round(argl) II round(arg2)); e->type = INT_VALUE; break; } // see if contents should be changed to an integer if (e->type == INTJVALUE) e->contents.int_vaIue = round(e->contents.real_value); }} // Returns TRUE if operator can take two strings (comparison operator). immiimmimmniiumiiiiuimiimimuiimiiiimiiitiuiiiiuti BOOLEAN op_can_take 5trings(char op)! if( op = 'Q' II op = 'N' ) return TRUE; else return FALSE;} utiiiiimuuimtiiimmmiimuuiimuuiiiiuimiiiimniiiuiπu II expr::eval_strings_op() // Evaluate the binary operator which is in the expression element pointed to. // This operator can take two strings. If both are present, then evaluate it. M-128 // If only one argument is a string, its an error. // If neither argument is a string, leave arguments and operator alone. void expr::eval_strings_op(expr_element* e)! string*sl; string* s2; if ( (e->prev->type == SYMBOLJVALUE) II (e->prev->prev->type == SYMBOLJVALUE) ){ if (e->prev->type == e->prev->prev->type) { // get ptrs to strings si = e->prev->contents.symbol; s2 = e->prev->prev->contents.symbol; if (e->contents.oper == 'Q') // test if strings are equal e->contents.int_value = (long) (*sl == *s2); else // test if strings are unequal // comparison yields an integer e->type = INT_VALUE; e->reloc_type = ABSOLUTE; // delete both arguments delete e->prev; delete e->prev; } else { // comparison operator with just one string! e->type = EVALJERROR; e->contents.int_value = NOT_BOTH_NUMBERS OR_STRINGS; delete e->prev; delete e->prev; } } } M-129 4 ^74 ^ // unary _operator0 // Returns TRUE if operator is unary. ttiumiimmiimuπiuiiimmnimiinitinumunmiiiiumiiiiii BOOLEAN unary_operator(char op)! switch(op)! case 'M': case T: case 'F': case '-': case 'n': return TRUE; default: return FALSE; umiiuinmiiiimimimuiniumuiimiuumuiiiiiHmiuiiiimi II expr::eval_unary_opO // Evaluate the unary operator which is in the expression element pointed to. // The argument is in the previous expression element, and both elements // are replaced by the result void expr::eval_unary_op(expr element* e)! char op; // get operator op = e->contents.oper; // replace this element with its operand *e = *e->prev; switch (op)! case 'M': // unary minus, so replace operator with negative value if (e->type == INTJVALUE) e->contents.int_vaIue = - e->contents.int_value; else if (e->type = REAL.VALUE) e->contents.real_value = - e->contents.real_value; else if (e->type != EVAL_ERROR) { e->type = EVAL_ERROR; e->contents.int_value = NUM_VALUE_NOT_KNOWN; } break; 4 ? 5 case T: // integer conversion operator if (e->type == REALJVALUE) { e->contents.int_value = round(e->contents.real_value); e->type = INT_VALUE; e->reloc_type = ABSOLUTE; } else if (e->type == INT_VALUE) else if (e->type != EVAL_ERROR) { e->type = EVAL_ERROR; e->contents.int_value = NUM_VALUE_NOT_KNOWN; } break; case 'F': // fixed point conversion operator if (e->type == INTJVALUE) { e->contents.real_value = e->real_value(); e->type = REALJVALUE; e->reloc_type = ABSOLUTE; } else if (e->type = REAL_VALUE) else if (e->type != EVAL_ERROR) { e->type = EVAL_ERROR; e->contents.int_value = NUM_VALUE_NOT_KNOWN; } break; case '-': // bitwise negate operator if (e->type == INT_VALUE) e->contents.int_value = ~(e->contents.int_value); else if (!EVAL_ERROR) { e->type = EVAL_ERROR; M-131 e->contents.int_value = rNTJ EQUIRED; } break; case 'n': // logical negate operator if (e->type == INTJVALUE) e->contents.int_value = !(e->contents.int_value); else if (e->type = REAL_VALUE) { e->contents.ϊnt_value = !(round(e->contents.real_value)); e->type = INT_VALUE; } else if (lEVALJSRROR) { e->type = EVAL_ERROR; e->contents.int_value = NUM_VALUE_NOT NOWN; } break;} // delete the operand delete e->prev;} II expr::eval() // Evaluate the expression and return the value as an expr_element // The value is of the type appropriate for the result of the expression. // Returns FALSE if error evaluating expression. In this case, the value // is of type EVALJERROR and an error code is in contents.int_value. BOOLEAN expr::eval(expr_element* e)! expr_element*elem; expr_element*last_elem ; expr* symbol expr; int trans jreloc Jevel; #ifdefDEBUG cerr « "evaluating: " « *this « "\n"; #endif // order is Reverse Polish, so scan for an operator // translate any symbols encountered along the way to values // operate on a copy of our expression, so evaluation is non-destructive! expr copy = *this; elem = copy.listhead.next; // if nothing to evaluate, return "value not known" if (!elem){ elem = e-JI don't create a new element, but just use caller's! elem->type = EVAL_ERROR; elem->contents.int_value = NUM_VALUE_NOT_KNOWN; } while (elem){ if (elem->type == SYMBOLJVALUE) { // symbol is an expr, which must be evaluated symbol_expr = translation(elem->contents.symbol); if (symbol_expr) { string* symjiame; BOOLEANrecurse = TRUE; // symbol has a value, so evaluate it, and set in elem // but first make sure it doesn't evaluate to itself if (symbol_expr->eval_to_symbol(&sym_name)) { if (*sym jiame == *elem->contents.symbol) recurse = FALSE; } // first save relocation level from translation transjreloc Jevel = symbol_expr->what jreloc Jevel(); // recursively evaluate new translated symbol value if (recurse) symbol_expr->eval(elem) ; // if relocation level from translation, set it in element if (transjreloc Jevel) elem->set_relocJevel(transj"eloc Jevel); } } else if (elem->type == OPER) { // first check for unary operators if (unary_operator(elem->contents.oper)) evaljjnary jp(elem) ; else { M-133 // binary operator // first check if operator is "=" or "!=", which // can take strings (unvalued symbols) if (op :an_take 5trings(elem->contents.oper)) eval 3trings rjp(elem) ; // check if operator requires integer else if (opjrequiresJntegers(elem->contents.oper)) eval ntegers_op(elem); // continue, if we haven't already processed the operator if (elem->tyρe — OPER) // operator must be for real operands evaljreals_op(elem); } } last_elem = elem; elem = elem->next;} // after all operations, value is in last_elem *e = *last_elem; return Gast 3lem->type != EVALJERROR);} II expπ:eval :o_symboIO //Try to evaluate the expression to a symbol, and return the string // for that symbol, ff the evaluation doesn't yield a symbol, return FALSE. BOOLEAN expr::eval_to 5ymbol(string** s)! expr_element*elem; expr_elementtestjelem; expr_element*Iast_elem; #ifdef DEBUG cerr « "evaluating: " « *this « "\n"; #endif // order is Reverse Polish, so scan for an operator // translate any symbols encountered along the way to values // operate on a copy of our expression, so evaluation is non-destructive! expr copy = *this; elem = copy.listhead.next; // if nothing to evaluate, return "value not known" if (!elem)! elem = new expr_element((long) 0); elem->type = EVAL_ERROR; elem->contents.int_value = NUM_VALUE_NOT_KNOWN;} while (elem){ if (elem->type == OPER) { // first check for unary operators if (unary _operator(elem->contents.oper)) eval_unary_op(elem); else { // binary operator // first check if operator is "==" or "!=", which // can take strings (unvalued symbols) if (op_can_take _strings(elern->contents. oper)) eval_strings_op(elem); // check if operator requires integer else if (op_requires jntegers(elem->contents.oper)) eval Jntegers_op(elem) ; // continue, if we haven't already processed the operator if (elem->type = OPER) // operator must be for real operands e val_reals _op(elem) ; } } last_elem = elem; elem = elem->next;} // after all operations, value is in last_elem if (last 3lem->type == SYMBOLJVALUE)! // return symbol string to user *s = last_elem->symbol(); return TRUE;} else return FALSE;} II expr::real_value() // Evaluate the expression and return a real value. // The expression may consist of any combination of operators, reals, ints, // and symbols which are evaluated to reals. // Also evaluates the relocation level of the expression. -135 niin πiπin πmiuππiiiiiiiiii iimiπiiiiiiπiiiiii iiiiii double expr::real_value(int* relocjype, int* reloc Jevel)! expr elementelem; doublefinal value; // evaluate this expression eval(&elem); // it may be an integer, however, so convert to real in this case if (elem.type = INT.VALUE) final_value = (double) elem.contents.int_value; else if (elem.type == REAL_VALUE) final_value = elem.contents.real_value; else // evaluated to symbol or some evaluation error, so return value of 0 final_value = 0.0; //return computed relocation type and level *reloc_type = elem.reloc_type; *relocJevel = elem.relocJeveI; return final_value;} II expr::int_value0 // Evaluate the expression and return an integer value. // The expression may consist of any combination of operators, ints, // and symbols which are evaluated to ints. long expr-int_value(int* relocjype, ϊnt* relocjevel)! // simply evaluate as real and convert to integer return round(real_value(reloc_type, relocjevel));} II expr::what relocJype() // Evaluate the expression and returns its relocation type. int expr::what reloc_type(){ doubleval; int relocjype, r Jevel; // simply evaluate as real val =real_value(&reloc_type, &rjevel); return relocjype; } II expr::what_reIocJevel() M-136 // Evaluate the expression and returns its relocation level. // If non-zero level is set as override level, then use this instead. int expr::what_reloc JevelO! // doubleval; // int relocjype, r Jevel; if (relocjevel) return relocjevel; else{ // // simply evaluate as real // val = real_value(&reloc_type, &r Jevel); // return r Jevel; // don't do above, because can result in infinite call loop! return 0; } } II expr::unknown_symbol() // Returns a point to the first symbol in the expression whose value // is not known. // If no unknown values, then it returns NULL. string* expr::unknown_symbol(){ expr_element*elem; elem = listhead.next; while (elem)! if (elem->type = SYMBOLJ ALUE) { if (!translation_known(elem->contents.symbol)) return elem->contents.symbol; else { // translation from symbol found, but is it just another symbol? return ( translation(elem->contents.symbol)->unknown_symbol()); } } elem = elen»next;} return NULL;} M-137 4 g // output stream operator for expr ostream& operator « (ostream& s, expr& e){ expr_element*last_elem; // go to the last element and call output stream operator for this. Iast_elem = e.listhead.lastO; return s « last_elem;} II expr::hasjnt_value // Tests if expression can result in a valid integer. BOOLEANexpr::hasjnt_value()! expr elementelem; //evaluate this expression eval(&elem); if (elem.type = INTJVALUE II elem.type = REALJVALUE) return TRUE; else return FALSE;} II expπ:ϊs_real_valued // Tests if expression results in area! value. BOOLEANexpr::is real_valued() { expr_elementelem; // evaluate this expression eval(&elem); return (elem.type —REALJVALUE);} niiiπiiiiiiπiiiiππiiiiiiiuiuiHiπiiπiinπuπiiiiiiii πriiiiiiii II expr::isjnt_valued // Tests if expression results in an int value. BOOLEANexpr::isJnt_valued0 { expr_elementelem; // evaluate this expression eval(&elem); return (elem.type = INT_VALUE);} II negateO // Creates and returns a new expression list which is the logical // negation of this list. expr* expr::negate(){ expr_element*last_elem ; expr _element*first_elem ; expr* newjist; // make a copy of this list newjist = new expr(*this); // go to the last element, and call negate for this. last_elem = newjist->listhead.last(); first_elem = last_elem->negate(TRUE); // we don't need first_elem, because we still have the pointer to the start return newjist; } // expr.hxx // header for expression class // T. Montlick // 10/2/89 /* source code control: @(#)expr.hxχl.56 10/7/91 */ #define EXPR JDEF #ifndef STAND ARD_DEF #include "standard.hxx" #endif #ifndef STRING_DEF #include "string.hxx" #endif extern "C" ! #ifndef UΗLΓTY_DEF #include "utihty.h" #endif #ifndef INTRFACE_DEF #include "intrface.h" #endif} /* Define the expr class, which embodies a numeric expression. This expression can be simply a single number, or any combination of numbers, symbols, and operators. Expressions are given in Reverse Polish order. */ // types of expression element contents: enumcontentsjtype [ INT_VALUE, REALJVALUE, SYMBOLJVALUE, OPER, EVAL_ERROR }; // if contents is EVALJERROR type, error codes contained as int_valued: enum { VALUE_OK, NUM_VALUE_NOT_KNOWN, REALJDUT_OF_RANGE, OVERFLOW, NULL_EXPR, NOT_BOTHjNUMBERS_OR 3TRINGS, COULD OTJEVAL, OPERAND OVER- FLOW, INT_REQUIRED, INITJFILE SYNTAX.ERR, ADDRESSES_CODE_SPACE}; /* The exprjelement class forms the building blocks of an expr. The expr class is a friend class and manipulates it directly, however it is made a class rather than a struct so that it can have a few convenient functions, such as output stream operator and destructor for deleting an expr element */ class exprjelement! friend class expr; union { // contents of expression element which may be one of: double real_yalue; long int_value; string* symbol; char oper; } contents; contentsjypetype;// identifies type of above element int relocjype;// non-zero for relocatable storage loc int relocjevel;// rel. level of block defined in expr_element*next;// pointer to next element in expression expr_element*prev / pointer to prev element in expression public: expr 3lement(long, exprjelement* p, exprjelement* n, int r); expr_eIement(double, exprjelement* p, exprjelement* n, int r); expr_element(char, expr_element* p, exprjelement* n); expr_element(string*, exprjelement* p, expr_element* n); expr element(expr_element&, exprjelement* p, exprjelement* n); expr_element(); ~expr_element();// destructor void operator=(expr_element&); long int_value();// return integer value of element doublereal_value();// return real value of element string*symbol(); // return symbol of symbol-valued element int error_code();// return error code for EVALJΞRROR element int what jreloc ype(){ return reloc_type; } int what j-eloc Jevel(){ return relocjevel; } void setj-eloc Jevel(int i) { relocjevel = i; } int whatjypeO ! return type; } void append(expr_element* his); // append element to end of this one BOOLE ANnegate_operator() ; expr_element*negate(BOOLEAN negate jt); expr_element*last() ; friendostream&operator«(ostream&, exprjelement* &); }; class expr! expr_elementlisfhead;// dummy - ptr to first element of expression int relocjevel;// what level expr defined in nested blocks public: exprQong, int r=0);// create expr. consisting of just an int val expr(double, int r=0);// create expr. consisting of just a real val expr(char); // create expr. consisting of just operator expr(string*); // create expression consisting of just symbol expr(expr&); // create an expression from another expression expr(expr_element&);// create an expression from an expr element expr(); // create expr. with nothing in it ~expr(); // destructor void operator=(expr&); void concat(expr*);// concatenate expr to end of this one doublereal_value(int*, int*);// evaluate real value of expression long int_value(int*, int*);// evaluate integer value of expression BOOLEANeval(expr_element*);// evaluate and return expression value BOOLEAN eval_to_symbol(string** s); void eval_unary_op(expr_element*); void evaMntegers_op(expr_element*); void eval_reals_op(expr_element*); void eval_strings_op(expr_element*); 48 S int what reloc ypeO;// returns relocation type of expression int what relocJevelO; void set_relocJevel(inti) ! relocjevel = i; } string*unknown_symbol();// returns ptr to symbol whose value not known friendostream&operator«(ostream&, expr&) ; BOOLEANhas Jnt_value() ; BOOLEANis_reaI_valued(); BOOLEANis Jnt_valued(); expr*negate(); // returns another expr which is this' negation }; BOOLEAN opjrequiresJntegers(char op); BOOLEAN op_can_take_strings(char op); BOOLEAN unary_operator(char op); // expr_arr.cxx // derived class for expression array * // Terry Montlick // 10/10/89 /* source code control: */ static char SccsTDQ = "@(#)expr arr.cxxl.56 10/7/91"; #include "exprjarr.hxx" expr_aπray::expr_array() {} expr array::expr_array(int i) 0 II expr_array::expr_array // Constructor with expr array as argument. iiHiimii i mu πimnπnnimi m iii i nnimi expr array::expr_array(expr_array& a)! for (int i=0; i<a.size0; i++){ // create a copy of each source expression expr* s = new expr(*a[i]); (*this)[i] = s; }} II expr array-operator = // Assigment of array. void expr array::operator = (expr array& a)! for (int i=0; i<a.size(); i++){ // create a copy of each source expression expr* s = new expr(*a[i]); (*this)[i] = s; } } // header for derived expression array classes II Υ. Montlick // 10/10/89 /* source code control: @(#)expr jarr.hxx 1.56 10/7/91 */ #define EXPR_ARRAY_DEF #ifndef ARRAY _DEF #include "array.hxx" #endif #ifndef EXPR_DEF #include "expr.hxx" #endif class expr_array : public array! public: expr arrayO; expr array (int i); expr array(expr array&);// constructor from another expr array void operator=(expr_array&)^/ assignment op from other expr_array expr*& operator []~(inti) { .return (expr*&) array: :operator[] (i); } int find(expr* ptr) { return array: :find(ptr); } void append(expr* ptr){ array::append(ptr); } exprjarray &operator+(expr array & a) { return (exprjarray &) array: :operator+((array&) a); } exprjarray &operator+=(expr array & a) {a = *this + a; return *this; } }; // exprhash.cxx // functions for expression hash table class // T. Montlick // 9/12/89 /* source code control: */ static char SccsIDQ = "@(#)exprhash.cxxl.56 10/7/91"; #ifndef EXPR_HASH_DEF #include "exprhash.hxx" M -143 48 S #endif // bring in hash functions, customized from our defines #ϊnclude "hash.cxx" // exprhash Jixx // header- for expression hash table class //T. Montlick // 9/12/89 /* source code control: @(#)exprhash.hxxl.56 10/7/91 */ #define EXPR_HASH_DEF #ifndefEXPR_DEF #include"expr.hxx" #endif // define symbols which make a custom hash table class #ifdefHASH #undefHASH #endif #define HASH exprjiash #ifdefHASH_ELEM #undefHASH_ELEM #endif #define HASH_ELEM exρr_hash_elem #ifdefHASH_LIST #undefHASH IST #endif #define HASH_LIST exprjiash Jist #ifdefVAL_TYPE #undefVAL_TYPE #endif #define VAL_TYPE expr // use expr*, not expr #ifdefUSE ^OTNTER #undef USE.POINTER #endif #define USE_POTNTER #include"hash.hxx" /* SHeader: /home/solus/users4/release/CVS/star/Iib/f_find.c,v 1.7 1991/09/0520:31:07 ed Exp $ $Id: f_find.c,v 1.7 1991/09/0520:31:07 edExp $ $Log: f_find.c,v $ -144 4 gg * Revision 1.7 1991/09/05 20:31:07 ed * for debug in codeview * */ /* must define C library routines as extern C or names get mangled to C++ - TM*/ #ifdef cplusplus #ifdef sun extern "C-" { #else extern "C" { #endif #endif #include <stdlib.h> #include <string.h> #include <stdio.h> #include <malloc.h> /* don't need these - TM */ /* #include <directh> */ /* #include <conio.h> */ /* #include <io.h> */ #include <time.h> #include <sys/types.h> #include <sys/stath> #include <errno.h> #ifdef cplusplus } #endif #ifdef DOS extern "C" ! #endif #include "starstd.h" #include "f_find.h" no_end_slash() -This function will check if there is a back slash at the end of an input string if in DOS, or a forward slash if in UNIX. If so, the slash will be eliminated. -This function serves file_find() by checking each directory set up along a environment string does not end with a slash. The purpose is to make inputs consistent */ void no_end_sIash( char *string )/* assume string is * \0' terminated */{ ushortlen; /* length of the input string */ /* ** function prototype ** no paramter declaration for library function ** to avoid warning */ /* C++ needs this declared as "extern C - TM" extern size_t stirlenO; * /* get string length not include '\0' */ /* ** get the size of the input string */ len = (ushort)strlen( string ); ffifdef DEBUG printf( "\nlength of string = %hu\n", len ); #endif /* ** check if the last char, of the string ** is a slash */ if ( SLASH != string[Ien-l] ){ return; /* don't touch the string */} else! /* ** replace the slash by '\0' */ strϊng[len-l] = * \0'; return;} } fileJϊndO -This function searches for a target file in each path along the STAR environment string. -However, in order to save SPROClab user convectional memory, the STAR environment variable will contain only the root dir. of sproc software. This function is designed to be able to find programs inside major subdirectories under the root. M-146 -The sequence of area that file_find() looks fSiM&cget file is as follows: l)current directory 2)root directory of first path along STAR environment string 3)/exe directory under the current root 4)/lib directory under the current root 5)/sprocfil directory under the current root if file not found, get next path along STAR environment string and goto step 3) It stops searching when the first target file is found. -It returns OK if it succeeds NO if it fails NFG if drastic situation occurs, -inputs l)char*filename; -file to be found 2)char*filepath; -buffer ptr input from caller; path of target file would be copied to this buffer */ int file_find( char *filename, /* file to be found */ char *filepath) /* buffer ptr input from caller; path of target file would be copied to this buffer */{ char *varname; /* environment variable that specifies a list of directory paths */ /* character array made static so it doesn't get inited every time */ static char star[5] = "STAR"; char pathbufLMAX_PATH];/* buffer to store the path of the target file */ char *retv_sptr; int i; char *seps; char filepathptrLMAX ?ATH]; char *dir_token; FILE *file; /* used fopen and fclose now - TM */ /* rewritten as static array, had flaky assignment to pointers - TM */ static char *sproc_subdir[] = { /* sproc major subdir. under star environment strings */ M-147 ^ C SLASH STRTNG, SLASHJSTRTNG "exe" SLASHjSTRTNG, SLASH_STRING "fib" SLASHjSTRTNG, SLASHjSTRTNG "sprocfil" SLASHjSTRTNG }; /* ** set up current major sproc subdircectory in DOS ** assume each subdir. set up in environment ** does not have 'V follows. */ int filejfound = FALSE; /* flag signal for file exist */ /* ** function prototype ** no paramter declaration for library functions ** to avoid warning */ /* C++ needs these declared as "extern C" - TM extern char *strcpy(); extern char *getenv(); extern char *strtok(); */ void no_end_slash( char *string ); /* ++forcodeview */ varname =star; #ϊfdefDEBUG printf( "\n" ); printf( "sproc_subdir[0] = %s\n", sproc_subdir[0] ); printf( "sproc_subdir[l] = %s\n", sproc _subdir[l] ); printf( "sprocj5ubdir[2] = s\n", sproc_subdir[2] ); printf( "sproc_subdir[3] = s\n", sproc_subdir[3] ); #endif /* ** firstly, look for the target file in current dir. */ if ((file = fopen(filename, "r")) != 0) { #ifdef DEBUG printf( "file found in local dir.\n" ); #endif file ound = TRUE; fclose(file);} /* ** copy the file path to buffer input from caller ** if target file exists. */ if ( file ound ){ if ( filepath != strcpy( filepath, filename ) ) { #ifdef DEBUG printf ( "\nstrcpyO failed !\n" ); #endif return( NFG ); } return( OK );} /* ** get the string value of the input environment variable */ retv sptr = getenv( varname ); if ( NULL == retv_sptr )! #ifdef DEBUG printf( "\n%s does not have environment stringΛn", varname ); #endif - - . return( NO );} else /* environment string OK */{ if ( NULL == strcpy( pathbuf , retvjsptr ) ) { #ifdef DEBUG printf( "\nstrcpyO failed " ); #endif return( NFG ); } #ifdef DEBUG printf ( "\n%s = %s\n", varname, pathbuf ); #endif /* ** Break environment string into differnent directories M-149 434 */ seps =";"; if ((dir_token = strtok( pathbuf, seps )) != NULL) { /* Find first directory */ no_end_slash( dirjroken ); /* take the slash at the end of of token out, if it exists */ strcpy( filepathptr, dirjroken ); } /* file_found = FALSE; */ while( (dirjroken !=NULL) && ϊfile bund ) { for ( i=0; i<SPROCjSUBDTRj O; i++ ) { /* ** append sproc subdir. and filename to this dir. */ strcat( filepathptr, sproc_subdir[i] ); strcat( filepathptr, filename ); #ifdef DEBUG ρrintf( ' nfilepafhptr = %s\n", filepathptr ); #endif /* ** check for the existence of file in ** current sproc directory */ if ((file = fopen(filepathptr, "r")) != 0) file rbund =TRUE; fclose(file); break; } if ( i == (SPROC SUBDΓRJSΓO-1) ) break; strcpy ( filepathptr, dirjroken ); #ϊfdef DEBUG printf( "\nfilepathptr = %s\n", filepathptr ); #endif } /* for end */ if ( file bund ) break; if ((dhjtoken = strtok( (char*) NULL, seps )) != NULL) { /* Find next directory */ no_end_slash( dir_token ); strcpy ( filepathptr, dirjroken ); } } /* while end */ } /* else end */ /* ** copy the file path to buffer input from caller */ if ( file ound )! if ( filepath != strcpy( filepath, filepathptr ) ) { * #ifdef DEBUG printf ( "\nstrcpyO failed !\n" ); #endif return( NFG ); } return( OK );} else{ #ifdef DEBUG printfC "\nfile not found ! ! ! ! !\n" ); #endif return ( NO ); . } } #ifdef DOS} #endif /* SHeader: /home/solus/users4/release/CVS/star/lib/f_find.h,v 1.2 1991/09/03 18:11:47 ed Exp $ $Id: f_find.h,v 1.2 1991/09/03 18:11:47 ed Exp $ $Log: f_find.h,v $ * Revision 1.2 1991/09/03 18:11:47 ed * constant SPROC jSUBDTRjNO changed from 3 to 4 to accomodate the parent * directory in addition to "exe", "lib", "sprocfil" subdirectories. * */ F_FIND.H -private header file forf_find.c */ #ϊfdefsun #defineSLASH 7 * #define SLASH_STRTNG"/" #else #defineSLASH 'W #define SLASH STRTNG'W" #endif #defineFILE_EXIST0 #define SPROC SUBDTR_NO 4/* including parent dir. */ /* ** function prototype */ void no_end_slash( char *strin ); int filejϊnd( char *filename, char *filepath ); /* fields.h */ /* source code control: @(#)fields.hl.5610/7/91 */ #defineFTELDS_DEF /* SDL assembler constants */ #define OP SHTFTl 8/* # bits left to shift opcode field (24-6 bits) */ #define MODE_SHTFT15/* # bits left to shift addr mode field (24-6-3)*/ #define OPERMASK0X7FFF/* mask defining operand field */ /* here are the opcodes: */ #defineADD_OP0X04 #defineADC_OP0X05 #define AND OP 0X08 #defineASL_OP0X00 #defineASR_OP0X01 #defineCLC_OP0X19 #define CMP_OP 0X1C #define DJNE_OP 0X3F #defineEOR_OP0X0B #define JMP _OP 0X31 #defineJCC OP0X32 #defineJCS_OP0X33 #defineJNE_OP 0X34 #defineJLF_OP0X35 #define JMF_OP 0X36 #define JOV.OP 0X37 #define JSI DP 0X38 #define JZE OP 0X39 #define JEQ_OP JZE OP #define JLE OP 0X3A #define JLT OP 0X3B #define JGE OP 0X3C #define JGT OP 0X3D #define LBSJ_OP0X30 #define LDA _OP 0X0C #define LDB _OP 0X0D #define LDCC OP 0X0E #define LDD OP 0X0F #defineLDF_OP0X18 #define LDWS DP 0X12 #define LDL _OP 0X11 #define LDX_OP 0X13 #defineMAC_OP0X16 #define MPY OP 0X17 #define LDY OPMPY OP #define NOP OP 0X1D #define NOT_OP 0X09 #define ORA OP 0X0A #define ROL.OP 0X02 #define ROR_OP 0X03 #define SEC OP 0X1A #define STA OP 0X24 #define STB OP 0X21 #defineSTBS_OP0XlF #define STD_OP 0X22 #define STF.OP 0X20 #define STL_OP 0X23 #define STML OP 0X28 #define STMH_OP 0X29 #define STMG.OP 0X2A #define STMLI OP 0X2C #define STMHI.OP 0X2D #define STMGI OP 0X2E #define STWS_OP 0X27 #define STX_OP 0X2B #define STY_OP 0X2F #define SUB _OP 0X06 #define SUBC_OP 0X07 #defineJWF_OP 0X3E #defineXLD_OP 0X15 /* addressing modes */ #define ABSOLUTE MODEOXO #define TMMED_LjMODE 0X2 /* left justified immediate operand */ #define TMMED JRJMODE 0X3 /* right justified immediate operand */ #define REG MODE 0X1 #defineTND_LOOP MODE0X4 #define TND_MODE0X5 #define IO_TND_LOOP_MODE 0X6 #defineIO_TND_MODE0X7 #define TMMEDIATE_MODE0X8/* for intermediate code only, justif. unknown */ /* register definitions */ #define A_REG 0x0E #define B_REG 0x09 #define D JREG OxOA #define F_REG 0x0B #define L_REG 0x08 #define BS_REG OxOC #define WS_REG OxOF #defineX_REG 0x03 #define Y_REG 0x07 #define ML_REG 0x00 #define MH_REG Ox01 #define MGJREG 0x02 #define MLI_REG 0x04 #define MHI_REG 0x05 #define MGI_REG 0x06 FILE FUNCTION DEFINITIONS Tony Curran 11-22-89 Function prototypes: int splitname( char *cname, char *pl, char *p2 ); -154 ^99 int mergename( char *cname, char *pl, char *p2 ); char *strtoup( char *string ); int checkjDpen _rf( FILE *rfile, char *rpath ) /* source code control: */ static char SccsID[] = "@(#)filefunc.cl.56 10/7/91"; #include <stdio.h> #include <ctype.h> /*#include <stdlib.h> */ #include <string.h> /* splitname - separate filename into name and extension strings. cname points to the combined filename string pi points to the name string p2 points to the extension string all strings are null terminated returns 0 */ int splitname (cname, pi, p2) char* cname; char* pi; char*p2;[ int i=0,j=0; char e; while (1) { c=cname[i]; if ( c=='.' ll c='\0') { pl[i] = '\0'; i++; break; } pl[i] = c; i++; } if ( c='\0') p2[j]='\0'; else { p2 ] =c; j++; while (c!='\0' ) { c = cname[ιj; p2Q] = c; i++; } } return(0);} /* mergename - combine name and extension strings into filename string. cname points to the combined filename string pi points to the name string p2 points to the extension string all strings are null terminated returns 0 */ int mergename(cname, pi, p2) char* cname; char* pi; char*p2;{ cname[0] = '\0'; strcat(cname, pi); strcat(cname, p2); return(0);} /* strtoup - convert a string to uppercase, string points to the null terminated string to be converted returns a pointer to string */ char *strtoup( string ) /* convert string to uppercase */ char* string;! inti=0; while (string[i] != '\0') { stringp] = (char)toupper((int)string[fJ); i++; } return ( strin ); M-156 50.1 } /* check_open_rf - check and open a read file, exit on failure rfile points to the file structure inpath is the filename returns 0 if successful returns 1 if failed */ int check_open_rf( rfile, rpath ) FILE*rfile; char* rpath;! if( ( rfile = fopen( rpath, "r" )) == NULL ) { printf ( "ERROR - cannot open %s\n", rpath ); return(l); } else retum(O);} function prototypes /* source code control: @(#)filefunc.hl.56 10/7/91 */ externint splitname( char *cname, char *pl, char *p2 ); externint mergename( char *cname, char *pl, char *p2 ); externchar *strtoup( char *str ); externint check rjpenjrf ( FILE *infile, char *inpath ); // filestakcxx // file stack class functions // Terry Montlick // 3/23/90 /* source code control: */ static char SccsIDf] = "@(#)filestak.cxxl.56 10/7/91"; #include "filestakhxx" void file_stack::push(string* s, FILE* f, int 1){ names.push(s); FTLEs.push(f); lines.push(l);} string*file 5tack::pop(FILE** fjptr, int* ljptr)! *f ptr = FILEs.popO; *l ptr = lines.popO; return names.popO;} // filestak.hxx // header for file stack class //T. Montlick // 3/23/90 /* source code control: @(#)filestak.hxxl.56 10/7/91 */ #define FTLE STACK_DEF #ifndef STACK_DEF #include "stackhxx" #endif class string; class int stack : public stack! public: void push(inti) { stack::push( (elem) i); } int pop() ! return (int) stack: :pop(); } int nth(intn) ! return (int) stack::nth(n); } }; class string_stack : public stack! public: void push(string* s) ! stack::push(s); } string*popO { return (string*) stack::pop(); } }; class F stack : public stack! public: void push(FTLE* s) ! stack::push(s); } FILE*pop() ! return (FILE*) stack::pop0; } }; class file_stack{ string stacknames; intjstack lines; F stack FILEs; public: void push(string* s, FILE* f, int 1); string*pop(FTLE** f jptr, int* ljptr); int size() ! return names.sizeO; } int line at_file_level(inti) ! return fines.nth(lines.size() - i); } }; * * Get environment variable functions * * Terry Montlick 3/20/90 * ********************************************************************** /* built into DOS Microsoft C (believe it or not!), this function needs only * the be available in UNIX. */ /* source code control: */ static char SccsID[] = "@(#)getenv.cl.56 10/7/91"; /* only compile if not DOS */ #ifndef DOS /* max size for this environment variable name */ #define MAX_NAME100 * * getenv * * Look for the given environment variable name and return its value as * the value of the function. * Returns NULL if not found. * char* getenv(varname) char* varname;! extern char** environ; char* p; char* valjptr; char* return_val = 0L; int i; char name_buf[MAX_NAME]; externchar *strpbrk() ; for (i=0; ((p = environ[i]) != 0); i++){ /* find delimiter for name */ if ((valjptr = strpbrk(environ[i], "=")) == 0L) break; /* copy name to buffer */ strncpy(name_buf, p, (valjptr-p)); name uf[valjptr-p] = '\0'; if (strcmp(varname, namejr f) = 0) { /* found name, so advance past end ptr to start of value */ valjptr++; return_val = valjptr; break; }} return return val;} #endif ****************************************************************************** * * Get environment variable function * * Terry Montlick 3/22/90 * *****************************************************************************/ /* source code control: @(#)getenv.hl.56 10/7/91 */ char *getenv(char*); //hash.cxx // functions for hash table class //T. Montlick // 9/12/89 /* source code control: @(#)hash.cxxl.56 10/7/91 */ #ifndef HASH_DEF #include "hash.hxx" #endif II hash_elem::hash elem // Constructor. HASH_ELEM::HASH_ELEM()[ val = 0; next = 0;} πniiii inuHiiiiiiuiiπuπuπuiuiiuiuiiπu iπiiiiiiiiiiii II hash_elem::~hash_elem // Destructor. imi i uimiimm nmiu ii m nnmim iiiu mπ HASH_ELEM::~HASH_ELEM()! M-160 // if value is a pointer, deallocate object pointed to #ifdef USE_POINTER if (val) delete val; #endif} II hashjist::hashjist // Constructor. HASH JST::HASH JJSTO { listhead.next = 0;} II hashjist::hashjist // Constructor from other hash list. HASH_LIST::HASH_LIST(HASH_LIST& h)! HASH_ELEM*srcjptr; HASH_ELEM*dest ptr; HASH_ELEM*last_destjptr; // first clear out any list which already exists iterjnit(); while (next()) removeO; // delete first element srcjptr = h.listhead.next; last_destjptr = &listhead; while (srcjptr)! // create a new hash element and copy source contents to it destjptr = new HASHJELEM; destjptr->s = srcjptr->s; // if we are using pointers, create a new copy of value #ifdef USE JOINTER if (srcjptr->val) destjptr->val = new VAL_TYPE(*srcjptr->val); else destjptr->val = ( VALUE_TYPE ) NULL; #else destjptr->val = srcjptr->val; #endif destjptr->next = 0; -161 . 506 // advance pointers last_destjptr->next = destjptr; last_destjptr= destjptr; srcjptr = srcjptr->next; }} II hashjist::~hash_list // Destructor. Delete all hash list elements. HASH_LIST::~HASH_LIST() { iterJnϊtO; while (nextO) removeO; // delete first element} II hashJist::operator = // Assignment from other hash list. void HASH_LIST::operator=(HASH_LIST& h){ HASH_ELEM*srcjptr; HASH_ELEM*dest ptr; HASH_ELEM*last_dest ptr; // first clear out any list which already exists iterjnit(); while (next()) removeO; // delete first element srcjptr = h.listhead.next; last_destjptr = &listhead; while (srcjptr)! // create a new hash element and copy source contents to it destjptr = new HASHJELEM; dest_ptr->s = srcjpti»s; // if we are using pointers, create a new copy of value #ifdefUSE_POTNTER if (src_ptr->val) dest_ptr->val =new VALJTYPE(*src_ptr->val); else destjptr->val = ( VALUEJTYPE ) NULL; #else destjptr->val = srcjptr->val; M-162 #endif destjptr->next = 0; // advance pointers last_destjptr->next = destjptr; last_destjptr = destjptr; srcjptr = src jptr->next; } } II hashjist::iterjnit // Initialize to iterate through list void HASH_LIST::iterJnit(){ current = &listhead; last = 0;} ' II hashjist::next // Iterator. HASHJΞLEM* HASH_LIST::next(){ if (last = current) current = last->next; return current;} II hashjist::find // Find the given name in the hash hst, returning TRUE if the // name was found and leaving this entry as the current value. BOOLEAN HASH_LIST::find(const string& name)! iterjnit(); while (next()){ if (name == current- >s) return TRUE;} return FALSE;} //hashjist::add // Add a new name and value to the front of the hash list. // If the name is already in the list, set the new value. void HASH_LIST::add(string& name, VALUE_TYPE& value)! M-163 HASH_ELEM*ptr; if (!find(name))! ptr = new HASH.ELEM; pti»s = name; // if we are using pointers, create a new copy of value #ifdefUSE_POINTER if (value) ptr->val = new VAL_TYPE(*value); else ptr->val = ( VALUEJTYPE ) NULL; #else ptr->val = value; #endif ptr->next = Iisfheadmext; listhead ext = ptr;} else{ // if pointers, deallocate prev value #ifdef USE JOINTER if (cuπrent->val) delete current->val; #endif current->val = value; }} II hash Jist::remove // Delete the current iteration element from the hash list void HASHJ ST::removeO{ if (current && last) { Iast->next= current->next; delete current; current = last->next; }} //hash::hash // Constructor. Create a hash table of the given size. HASH::HASH(int size)! p = new HASH ST [sz = size];} M-164 II hash::hash // Constructor from another hash table. HASH::HASH(HASH& h){ // create new hash table of same size p = new HASHJ IST [sz = h.sz]; // copy each hash list in array for (int i=0; i<sz; i++) p[i] = h.p[i];} // hash:: -hash // Destructor. Deallocate hash table. HASH::~HASH(){ delete [sz] p;} II hash::hash_key // Return hash key for the given name string. int HASH::hash_key(const string & name)! int key = 0; char*p; p = (char*) &name[0]; for (int i=0; i<M AX_HASH_CH AR; i++) { key = (key + *p) % sz; if (*p != '\0') p++; // don't advance beyond end of string} return key;} II hash::find // Find the given name in the hash table, returning the value. // Returns TRUE if the name was found. BOOLEAN HASH::find(const string& name, VALUEJTYPE* valptr){ HASH_LIST*whichJist; which Jist = &p[hash_key(name)]; if (which Jist->find(name)){ *valptr = *whichjist->value(); M-165 return TRUE;} else return FALSE;} mnuiimuuimimmiiiuiiiiniiiiπiimiiiitiummiMumiiiMi II hash-present // Find the given name in the hash table. // Returns TRUE if the name was found. nummumutiu iim nmiiπinwu um uuπmmnwii BOOLEAN HASH::present(const string& name)! HASH_LIST*which_list; which Jist = &p[hashjcey(name)]; return which Jist->find(name);} ifiiiiiiiiiiiiiiiiiiiiriiifiiirififiiiiiiiifiifiifiiiiiiiiiiiimiiiiiiiiiiiiii II hash-remove // Find the given name in the hash table, and delete the entry. BOOLEAN HASH::remove(string& name)! HASH_LIST*whichJist; whichjist = &p[hashj ey(name)]; if (which Jist->find(name)) ! whichJist->remove(); return TRUE;} return FALSE;} II hash::add // Add the given name and value to the hash table. If the name is // not present, add a new entry. void HASH::add(string& name, VALUE_TYPE& value)! HASHJ ST*whichJist; whichjist = &p[hashjcey(name)]; which Jist->add(name, value);} //hash::add_new // Add the given name and value to the hash table. If the name is // already present, return FALSE; M-166 BOOLEAN HASH::add_new(string& name, VALUE_TYPE& value)! HASH_LIST*whichJist; whichjist = &p[hash_key(name)]; if (which Jist->find(name)) return FALSE; add(name, value); return TRUE;} II hash::iterjnit // Init the iterator to selected each element of hash table in turn. void HASH::iterJnit(){ HASH_LIST*whichJist; iter Jndex = iter_count = 0; whichjist = &p [iter Jndex]; which Jist->iter Jnit(); } II hash-next // Get the next hash entry. Returns FALSE if no more. BOOLEAN HASH: :next(string** namejptr, VALUEJTYPE* value)! HASH_LIST*whichJist; HASH_ELEM*which_elem ; whichjist = &p[iter Jndex]; which_elem = whichjist- >next(); while (!which_elem){ iterjndex++; // if at end of hash array, all done if (iterjndex >= sz) return FALSE; else { whichjist = &p[iter Jndex]; whichjist->iterjnit(); which_elem = which Jist->next(); } } *name_ptr = &which_elem->s; #ifdef USE JOINTER if (which_elem->val) M-167 *value = new VAL_TYPE(*which_elem->val); else *value =( VALUE_TYPE ) NULL; #else *value = which_elem->val; #endif iter_count++; return TRUE;} #ifndef NO_OUTSTREAM iiiiiiiiiiiiiiiiiiiiriiiiiiiiiiiiiiiiiiiiiniiiiiiiiiiimiiiiiiiiiiiiiiiiiiiii II ostream& operator«(ostream&, HASH&) // Output stream operator. ostream& operator«(ostream& strm, HASH& h)! hiterJnitO; //just call our output iterator function return strm «=h;} iriifiiiiiiifiiiiiiiiiiiiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifiirriiiiiuiiiiiiif II ostream& operator«=(ostream&, HASH&) // Output stream iterator function. // Get the next hash element, output it and call ourself again. // If no more elements, just return output stream. ostream& operator«=(ostream& strm, HASH& h){ string* name; VALUEJIYPEval; quoter name_q; quoter val_q; int count; // save to test for first time iterating count = h.iterjcount; if (h.next(&name, &val)){ name q.inO « *name; #IfdefUSE_POTNTER val_q.inO « *val; #else val_q.in0 « val; #endif // if not first iterator, output separator M-168 if (count) return (strm « ", " « name_q.out() « "=" « val_q.out()) «= h; else return (strm « name_q.out() « "=" « val_q.out()) «= h;} else return strm;} #endif // hash.hxx // header for hash table class 111. Montlick // 9/12/89 /* source code control: @(#)hash.hxxl.56 10/7/91 */ #define HASH_DEF #ifndef STAND ARD_DEF #include"standard.hxx" #endif #ifndef STRING_DEF #include"string.hxx" #endif #ifndef POST_STREAM_DEF #include"poststrm.hxx" #endif // The following are used to create a custom hash list. // The custom hash class must include "hash.cxx", but first must define // various symbols. // Derived classes are not used because they are not flexible enough! // HASH is defined as the name of the hash table class #ifndef HASH #define HASH hash #endif // HASH JUST is defined as the name of the hash list class #ifndef HASH_LIST #define HASH_LIST hash Jist #endif // HASH JΞLEM is defined as the name of the hash element class #ifndef HASH_ELEM #define HASH_ELEM hashjslem #endif // VAL_TYPE is the type contained in the val field of each hash element M-169 #ifndefVAL_TYPE #define VALJTYPE elem #endif // USEJΌΓNTER is defined if we are to store a pointer to value type, // not the type itself. #ifdef VALUEJTYPE #undef VALUEJTYPE #endif #ifdefUSEj?OTNTER #define VALUEJTYPE VAL_TYPE* #else #define VALUE_TYPE VAL_TYPE #endif // Hash element, which is used to build a linked list of entries class HASH_ELEM! public: string s; // this string VALUE JTYPEval;// value associated with this string HASH_ELEM*next;// next string in list public: HASHJELEMO; // constructor ~HASH_ELEM();// destructor }; // Hash list, used to build a hash table class HASHJ TST! HASHJELEMlisthead;// dummy, points to first hash element HASHJELEM*current / current element HASH_ELEM*last;// previous element public: HASHJLTSTO; // constructor HASH_LIST(HASH_LIST&);// construction from other hash list ~HASH_LIST(); void operator=(HASH_LIST&); void iterJnitO; HASHJELEM*next(); void removeQ; BOOLEAN find(const string& name); void add(string& name, VALUEJTYPE& value); string* name() ! return &current->s; } -170 VALUE_TYPE*value(){ return &current->val; } }; #define MAX_HASH_CHAR8/* max characters to generate hash key */ // The hash table class HASH{ HASH_LIST*p; // pointer to array of hash lists int sz; // size of hash table array int iter Jndex; // which hash list currently iterating int iter_count; // # of iterations public: HASH(int size); // create hash table of given size HASH(HASH&); // constructor from other hash table -HASH0; void operator=(HASH&);// assignment open from other hash table int hash_key(const sιring& name);// return the hash key for name BOOLEANfind(const string& name, VALUEJTYPE* valptr);// return val from name BOOLE ANpresent(const string& name);// just see if name present BOOLEANremove(string& name);// delete the given entry void add(string& name, VALUE JTYPE& value) -JI add value or entry BOOLEANadd_new(string& name, VALUEJTYPE& value);// add new entry void iterJnitO; BOOLEANnext(string** name, VALUEJTYPE* valptr); friend ostream& operator«=(ostream&, HASH&); friend ostream& operator«(ostream&, HASH&); }; // inp Jistcxx // input list class //T. Montlick // 11/30/89 /* source code control: */ static char SccsID[] = "@(#)inpjistcxxl.56 10/7/91"; #ifndef TNP_LIST_DEF #include "inpjisthxx" #endif II inpjist::inpjist // Constructor. inpjist::inpjist() M-171 {} II inp Jist::inp Jist(inp_list&) // Constructor from other inp Jist inpjist::inpjist(inpjist& 1)! blck = l.blck; inp = l.inp; iterjndex = Liter Jndex;} II inp Jist::~inp Jist //Destructor. inpjist::~inpjist() {} If inpJist::operator = (inp Jist&) // Assignment operator from other inp Jist void inpJist::operator = (inpjist& I)! blck = l.blck; inp = l.inp; iterjndex = Liter Jndex;} //inpjist::add // Add a block and input pair. void inpjist::add(int which Jblck, int whichjnput)! int i; i = blcksizeO; blck[ϊ] = which jblck; ϊnp[i] = whichjnput; } iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiniiiiiiiiiiiiiiuiiiiintiiiiiiiii II inp Jist::remove // Remove last input pair gotten with nextO- void inpJist::remove()! int i; i = —iterjndex;// make sure we back up iter index to point to current M-172 // make sure we were really pointing to something if (i >= 0){ blck.remove(i); inp.remove(i);} else iterjndex++;} II inp Jist: :next // Get next pair. BOOLE ANinp Jist: :next(int* which_blck, int* whichjnput)! if (iterjndex < blck.size()){ *which >lck = blckfiter Jndex]; *which Jnput = inp[iterjndex]; iterjndex++; return TRUE;} else return FALSE;} II inp Jist: :get // Get pair at given index, bypassing iterator. BOOLEANinρJist::get(int i, int* which rtck, int* whichjnput)! if (i < blck.size()){ *which jblck = blck[i]; *which Jnput = inp[i]; return TRUE;} else return FALSE; } // inp Jisthxx // input list class // T. Montlick // 2/11/90 /* source code control: @(#)inp Jisthxx 1.56 10/7/91 */ #define TNP_LIST_DEF #ifndef INT_ARRAY DEF #include "intjarr.hxx" #endif // This class maintains an input list, which consists of pairs of block indices // and input index numbers. Input lists are used for tracing through sets of // block inputs for sequencing, class inp Jist! iπt arrayblck; int arrayinp; int * iterjndex; public: inpJistO; inpjist(inpjist& 1); ~inpjist(); void operator = (inp Jist& 1); void add(int whichjblck, int whichjnput); void removeO; BOOLEANemptyO { return (blck.size() = 0); } void iterJnϊtO { iterjndex = 0; } BOOLEANnextrint* whichjblck, int* whichjnput); int size() ! return blcksize(); } BOOLEANget nti, int* whichjblck, int* whichjnput); }; // ϊnst arr.cxx // derived class for instance array //Terry Montlick // 11/30/89 /* source code control: */ static char SccsTDQ = "@(#)inst_arr.cxxl.56 10/7/91"; #include "inst aixhxx" //inst_arr.hxx // header for derived instance array class //T. Montlick // 11/30/89 /* source code control: @(#)inst arr.hxxl.56 10/7/91 */ #define TNST_ARRAY_DEF #ifndefARRAY_DEF #include "array.hxx" #endif class instance; class inst array : public array! public: instance*&operatorD(int i) { return (instance*&) array::operator[] (i); } int find(instance* ptr) [ return array::find(ptr); } -174 void append(instance* ptr){ array: :append(ptr); } inst array&operator+(instjarray& a) { return (inst array &) array: :operator+((array&) a); } instjarray&operator+=(inst array& a) {a = *this + a; return *this; } }; // instancl.cxx // instance class // T. Montlick // 11/30/89 /* source code control: */ static char SccsID[] = "@(#)instancl.cxxl.56 10/7/91"; #ifndef INSTANCE JDEF #include "instance.hxx" #endif // instance_rate_change::instance_rate_change // Constructor. instance jrate_change: instance jrate_change() [ new ratejblock = FALSE; } // instance_rate_change::~instancejrate_change // Destructor. instance_rate_change::~instance_rate_change() { } II instance-instance // Constructor. instance::instance(block* proto, string& inst_name, instance* parent, int index): instance jphantoms(proto){ pro to type jptr = proto; instancejiame = instjiame; parent .instance = parent; our Jndex = index; overrides = NULL; our_n_storageJocs = ,„ Λ 520 M-175 storageJ)ase = n storagejocs = 0; instructionjbase = NO NSTRJ3 ASE; linejium = 0; instjs_variant = is_serialjport = is_serial_output = connections_set = sequenced = overridesjprocessed = init = FALSE; // last nsertjpos = -1; // initialize zones to none for (int i=0; i<proto->storage_tabIe_size(); i++)! zone_for_wire[i] = NO_TIME_ZONE; }} If instance::~instance //Destructor. instance: :~instance() {} //push_context // Set this instance's block as current block, and set instance info. void instance::push_contextO{ // set this block's prototype as the current block push block(prototype_ptr); // set the override symbol table for this instance prototypejptr->set_override_symbols(overrides); // also set this instance pointer in the prototype block so it can // translate storage expressions prototype jptr->setjnstance(this) ; } imiiHiuutt ummmiiimmm mumummimmuitumuiu II pop_context //Clears instance info in block and restores previous current block. iiiiuiiiuiiiπiiii iiiimumπimiiiiiiiriiπi iiiiπmπiii i M-176 void instance: :pop_context(){ // allow for possible multple push of same block, so don't clear block info! // we're no longer the current block pop_Wock();} II instance: :build_tree // Called for the top level instance, this function builds the instance tree by // instantiating all child blocks. // Returns a pointer to the instance which caused the tree build // to failed because of infinite hierarchy, else returns NULL. instance*instance::build_tree(){ int i; block* blk; block* childjblock; string* childjblk jiame; string* child jiame; arg_set*child_vals; arg_set*child jports ; int line_num_called_at; instance*new_child; instance*badjnstance; block_ref*child_ref; blk = prototypejptr; // first make sure we have not been instantiated in hierarchy if (blk->is JnjbierarchyO) return this; // it's not, so mark it blk->set Jn .hierarchy (TRUE) ; blk->refs Jter Jnit() ; // start reference/child instance index from 0 i = 0; // get each block name instantiated by this block while (blk->next_ref (&child jref)) { // get reference info, including line # for this instance child_ref->get_blockJnfo(&childjblk_name, &childjιame, &child_vals, &childjports, &line_num_called_at); // look for child block name in list of prototypes if (prototype_blocks.find(*child_blk_name, &childjblock)) -177 // if block has subroutine form, instantiate inline form for now and // count # times it's called if (childjblock->has_subrjform()) chfldjblock->mcrement_call_count() ; // create a new child instance new child = new instance(childjblock, *child_name, this, i); // give the block reference a pointer to him chMjref->setJnstancejpointer(new_child); // set in child line # we called him from new_child->line_num = line_num_called at; // add to our children child Jnstances[i] = new_child; // store pointer to block ref child jrefsft] = childjref ; // and recursively call our child if (badjnstance = new child->build_tree()) return badjnstance; i++; // advance child index }} // unmark this block in instance hierarchy blk->setJnJιierarchy(FALSE); return NULL;} If instance: :process_subroutines // Called for the top level instance, this function processes subroutines // by seeing if the inline or call form should be used. It then instantiates // the correct form, and if a subroutine call, makes sure that the subroutine // body is at the top level of the instance tree. iiiitiiimiiiiiiiiiiiiiiimiiMiiiiiiuiiiiiiiiiiiiπniiiiiiiiiM int instance-process subroutinesO { int i; block* blk; block* child jblock; string* childjblk iame; string* child_name; arg_set*child_vals; arg_set*child jports ; int linejιum_called_at; instance*child; blQck_ref*child_ref; int status = 0; // make override symbols available push_context(); blk = prototype jptr; // first make sure we have not been instantiated in hierarchy if (blk->isjn_hierarchy()){ out_err_header("INS092"); cerr « "Subroutine block '" « *prototype()->getjblock_name() « "' eventually includes itself !\n"; status = 1;} // it's not, so mark it blk->set jn .hierarchy (TRUE) ; blk->refsjterjnit(); // start reference/child instance index from 0 i = 0; // get each block name instantiated by this block while (blk->next jref (&child _ref)){ // get reference info, including line # for this instance child_ref->get_blockJnfo(&child_blk jiame, &child_name, &child_vals, &childjports, &line_numj alled_at); // look for child block name in list of prototypes if (prototype_blocks.find(*child jblkj ame, &child jblock)) { // get instance pointer child = child Jnstancesp]; // see if this is a possible subroutine if (child_block->has_subr orm()) { // this is a possible subroutine, so see if call or inline if (check_if_subr_call(childjblock, child)) { exprjιash*parameters; // subr call, so use call form of name M-179 stringsubr_call_name; subr_call_name = subr_call_name + *childjblkjιame + CALL.SUFFTX; if (!prototype_blocks.find(subr_call_name, &childjblock)) { out_error("TNS085", cerr, TRUE); cerr « "Unable to find subr call block for "' « *childjblk_name « .\n ; status = 1; } // make sure subroutine body is at top level if (!child_block->ϊs_subrJnst_made()) { stringsubr jiame; block*subr_block; instance*subr_ϊnst; block_ref*block_ref_ptr; intj; subrjiame = subrjiame + *child_blk_name + SUBR.SUFFIX; if (!prototype_blocks.find(subr_name, &subr_block)) { out_error('TNS086", cerr, TRUE); cerr « "Unable to find subr block for '" « *child_blk_name « "'.\n"; status = 1; } // create the subr instance as next child of top inst j = topJnstance->get_n_children(); subrjnst=new instance(subrjblock, *child_blk_name, top.instance.j); top Jnstance->childjnstances[j] = subr Jnst; // add a new block reference for top instance // so block gets auto-sequenced block jref.ptr = new block_ref(subr_name, *chfldjblk_name, 0); ((hϊerjblock*) top_instance->prototype() )-> add_block_ref(block_refjptr); M-180 // give the block reference a pointer to subroutine inst block jref jptr->setJnstancejpointer(subrJnst); child_block->set_subrJnst_made(subrJnst); } // kill previous child instance // but first get parameters parameters = child->get_overrides(); delete child; // and create a new child instance with subr call block child = new instance(childjblock, *child jiame, this, i); // give him old parameters child->set_overrides(parameters) ; // give the block reference a pointer to him child_ref->setJnstancejpointer(child); // set in child line # we called him from child->line_num = linejιum_called_at; // add to our children child_instances[i] = child; // store pointer to block ref ' child jrefs[i] = child_ref; } } // and recursively call our child if (status = 0) status l= child->process_subroutines(); i++; // advance child index } } // unmark this block in instance hierarchy blk->setJn_hierarchy(FALSE); pop_context(); return status;} II instance-check Jf_subr_call // Returns TRUE if this child should be called as subroutine rather than // remain inline. BOOLEAN instance: :checkJf_subr_call(block* child jblock, instance* child Jnst) { BOOLEANstatus = FALSE; BOOLEANdont_know_status = TRUE; expr* exprjptr; static string subr_param 5tring(SUBR_EARAM 3TR); int param Jndex; long value; int dummyl, dummy2; // push to child context so parameter values available child Jnst->push_contextO; if (child J Iock->look_upjparam_name(subrjparam_string, &param Jndex))! // get and evaluate parameter expression exprjptr = childjbIock->param 3Xpr_atJndex(param Jndex); value = exprjptr->int_value(&dummyl, &dummy2); // check condition values (defined in our header) if (value USE SUBR ONDITION) { status = TRUE; dont_know_status = FALSE; } else if (value DONT_USE_SUBR_COND) { status = FALSE; dontJαιow_status = FALSE; } } if (dont_know_status){ // use default, which can be specified from command line if (chπd block->get _times_called() >= deflt_subr_count) status = TRUE;} child Jnst->pop_contextO; return status;} II get_declaration // Get the strings for the next export declaration in the remaining // portion of the declarations string. BOOLEAN get_declaration(string* declarations, string** symboljiame, string** symbol_val){ char* startjptr; char* endjptr; char* temp jptr; int n_chars; -182 char name[MAX_HT£R_NAME 3IZE]; int i; start jptr = &declarations->operator[](0); // skip any white space start jptr = start jptr + strspn(start_ptr, " "); // search for the next "=" or space in the declaration if (!(endjptr = strpbrk(start ptr, "= "))) return FALSE; // there is name between startjptr and endjptr // copy it into our character array n_chars = endjptr - startjptr; // make sure that there's no separator character in name if ((temp jptr = strpbrk(startjptr, ", ")) < endjptr)! if (temp jptr != (char*) NULL) return FALSE;} // limit name to max size if (n_chars > MAX HTER JSTAME_SIZE) n_chars = MAX_HIER_NAME SIZE; strncpy(name, startjptr, n_chars); // don't forget terminal null name[n_chars] = '\0'; // make sure name is a legal identifier if ( (name[0] >='a' && name[0] <= 'z') II (name[0] >='A' &&name[0] <= 'Z') II name[0] = '$' II name[0] == ' ' II name[0] == ' ) else return FALSE; for (i=l; i<n_chars; i++){ if ( (name[i] >='a' && name[i] <= 'z') II (name[i] >='A' && name[i] <= 'Z') II (name[i] >='0' && namefi] <= '9') II namefi] == '$' II name[i] == '%' II namefi] == J' M-183 ) else return FALSE;} // make a symbol string from it ♦ symbol iame = new string(name); // if not already there, go to the next "=" if (end_ptr[0] != '='){ if (!(end ptr = strpbrk(end_ptr, "="))) return FALSE;} endjptr++;// go past "=" // skip any white space endjptr = endjptr + strspn(endjptr, " "); // now set startjptr to search from start of value startjptr = endjptr; if (.(endjptr = strρbrk(start_ρtr, ", "))) endjptr = startjptr + strlen(startjptr); n chars = end_ρtr - startjptr; // skip past separators for next name/value pair end_ptr = endjptr + strspn(end ptr, ", "); // limit name to max size if (n_chars > MAXJHffiR_NAME_SIZE) n_chars = MAX HTER AME SIZE; strncpy(name, start_ptr, njchars); // don't forget terminal null name[n_chars] = 'W; II make a symbol string from it *symbol_val = new string(name); // and make a new declarations string which is remainder of string n_chars = strlen(end ptr); strncpy(name, endjptr, njchars); -- name[n chars] = '\0'; „ ♦ declarations = name; return TRUE;} II instance::process_exports // Sees if this instance and children have export symbols declared in its // parameter list // Returns non-zero if error. M-184 int instance: :process_exports()! int status = 0; expr* exprjptr; static string exports_param 5tring(EXPORTS ?ARAM STR); int paramjndex; string* declarations; int i; string* symboljiame; string* symbol_val; string* inst_symbol_val; expr* symbo val_expr; int temp; // push to child context so parameter values available push_context(); if (prototype()->look_up jparam jιame(exports jparam _string, &param Jndex)) { // get and evaluate parameter expression exprjptr = prototype()->param_expr atJndex(param Jndex); if (exprjptr->eval_to_symbol(&declarations)) { // exports parameter has a string value // so get each declaration while (get_declaration(declarations, &symbol_name, &symbol_val)) { // make sure the symbol value is one of our names if (!prototype()->look_up_storagejιame(symbol_val, &temp) && !prototype()->lookjjp_symboljιanιe(symbol val, &symbol_val_expr) ) { outj3rror('TNS075", cerr, TRUE); cerr « "The name to be exported, '" « *symbol_val « "', is not present in the blockΛn"; status = 1; } // make a string expression from symbol val string // starting with this instance name inst_symbol_val = new string(""); *inst_symboLval = *inst_symbol_val + instancejiame + "." + *symbol_val; symbol_val_expr = new expr(inst_symbol_val); // add expression to parent if (!parentO->prototype()-> add_expression_name(symbol_name, symbol_val_expr)) { out_eiror("TNS073", cerr, TRUE); cerr « "The export name '" « *symbol jiame « "' is already definedΛn"; states = 1; } if (!parent()->prototype()-> add_symbol_name(symbol jiame, &temp, FALSE)) { out 3iror("TNS074", cerr, TRUE); cerr « "The export name '" « *symbol_name « '" already existsΛn"; status = 1; } } // should be no more declarations left if successful if (*decIarations != "") { out_error("TNS072", cerr, TRUE); cerr « "Illegal exports parameter declaration of '" « *declaratιons « "'.\n"; status = 1; } } else { out_error("INS071", cerr, TRUE); cerr « 'Εxports parameter declaration has an illegal value of '" « '".\n"; status = 1; } } for (i=0; i<childjnstances.size(); i++) status 1= child Jnstances[i]->process_exports(); pop_context(); return status;} II instance: :evaluate_overrides // Called for the top level instance, this function hierarchically // evaluates all symbols to be passed to child instances. // It creates the table of evaluated override symbols and places them // as the hash table "overrides" in the child instance. // Note: this function can now be called repeatedly for added children // as it now checks if child instances have aheady been evaluated. /////////////////////////////////////////////////////////////////////////////// int instance: :evaluate_overrides() { int status = 0; block* child jpro to type;// prototype block for child blockj-ef *child jref ; // our reference to child string* childjblkjiame; // info from reference ... string* childjiame; arg_set*child_vals; arg_set*childjports; expr jarray *childj3xprs ; expr_hash*child_overrides; string* param iame; int i; int dummy Jndex; expr* dummy_expr; int linejium; instance *child; // save current block context and set instance info in block push_context(); // create a symbol table for each child for (i=0; i<childjnstances.size(); i++)! // only process child if not done before if ( ichild Jnstances[i]->arejDverridesjprocessed()) { childJnstances[i]->set_overrides_processed(); child jprototype = child Jnstances[i]->pro to type jpu * ; child ref = childjrefsfi] ; if (childjref != (blockjref*) NULL) { // set context as child so error msgs get referred to child child_instances[i]->push_context(); // get reference info for this child cMld ref->getjblockJnfo(&childjblk_name, &child_name, &child_vals, &childjports, &line_num); // For each child, create a hash table of override symbols // from the child values arg_set, provided it exists. // This hash table has unevaluated expressions, which // get evaluated by instance::compute_contents(). // // If this arg_set is by name: // Just create hash table of names and their expressions. // // If this arg_set is by position: // Get each successive name from param table of the child // block prototype, and create a hash table entry with the // corresponding expression. // if (child_vals) { if (child_vals->storedjby_name()) { // arg_set has a hash table, so just point to it child _oveπrides = child_vals->get_exprjιash(); // make sure all the names are child parameter names child 3verrides->iterjnit0 ; while (child_overrides->next(&param jiame, &dummy_expr)) { if (!childjprototype->look_upjparamjιame( *param jiame, &dummy Jndex)) { if (*param_name = SUBR > ARAM _STR) { child Jnstances[i]->out_error("INS20r\ cerr, TRUE); M-188 cerr « "This block has no subroutine form " « "availableΛn"; status = 1; break; } else { child_instances[i]->outj3rror("INS001", cerr, TRUE); cerr « "This block has no parameter named '" « *param jiame « '".\n"; status = 1; break; } } } } else { // stored by position, so find names in prototype // block create a fresh hash table, copy in entries childjDverrides = new exprJιash(SZ); child_exprs = child v'als->get_expr_array(); for(int j=0; j<child_exprs->size(); j++) { // use expression from block reference and // name from prototype parameter table paramjiame = childjprototype-> param _name_at Jndex (j ) ; if (paramjiame == (string*) NULL) { child jnstances[i]->outj3rror("INS002", cerr, TRUE); cerr « "This block has no parameter " « (j+l) « "Λn"; status = 1 ; break; 53^ M-189 } child_overrides->add(*paranι_name,(*child_exprs)[j]); } } if (status) break; // set this hash table as the override table for this child childJnstances[i]->set_overrides(childj3verrides); } // restore our context child Jnstances[i]->pop_context(); } // recursively call our children child = childjnstances[i]; if (child != (instance*) NULL) status l= child_instances[i]->evaluatej3verrides0; }} //restore previous block context pop_context0; return status;} //instance::check_verify_expressions // Check verify expression for our prototype, which must also have been // set as the current block. // Returns non-zero and outputs errors if any verify errors. int instance::check_verifyjexpressions() [ int status = 0; int i; expr* e; int n_verify; string* failed string; // check truth of any verify expressions if (n_verify = prototypejptr->n_verify_expressions()) { for (i=0; i<n_verify; i++) { e = prototypejptr->get_verify_expression(i); // expression must have integer value of non-zero to be true M-190 if (e->has _int_value()) { { // if user has specified a failed msg, get it failed_string = prototypejptr->get_verifyjnsg(i); // get negation of the error expression e = e->negate(); // and output this negated expression out_error("INS003", cerr, TRUE); // if user has given a string with verify, output it if (failed_string) cerr « *failed_string « "\n"; else // otherwise output negation of verify condition cerr « *e « "\n"; // done with negate string delete e; status = 1; } } else { // verify expression doesn't have integer value // if user has specified a failed msg, get it failed_string = prototype jptr- >get_verify_msg(i); outj3rror("INS004", cerr, TRUE); // if user has given a string with verify, output it if (failed_string) cerr « *failed_string « "\n"; else // otherwise output no value msg cerr « "No value for '" « *e « '"An"; status = 1 ; } } } return status;} M-191 // instance::is JnitO // Test if this is an init block. // Check prototype, too. ιιιιιi!UiιιιιιπιiHiιιπιιιιιιιπιιπ ιιιrιιιιιπι ιιιιmιuιιιιmιιιw BOOLEAN instance: :is Jnit() { if (init) return TRUE; else if (prototype ptr) return pro totypejptr->is JnitO; return FALSE;} II instance::check_asm block // If this is an asm block, get the # of instructions and // the duration. // Also, verify all operands. // Outputs errors as necessary, returning non-zero if any error. int instance: :checkjasmjblock()! int status = 0; expr* e; // if we are a leaf (ASM) block, get # of instructions if (prototypejptr->is Jeaf jblockO) ! njnstructjocs = ((asmjblock*) prototype jptr)->getjιJnstructions(); // if we are init, record # of init instr. separately if (is JnitO) n jnitjnstrjocs = njnstructjocs; else if (prototype_pti»isjphantom()) // else if just phantom, record # instructions separately set_njphantomJnstrJocs(n_instructJocs); // and set duration for asm block init_duration = 0; setjphantom_duration(0); e = ((asmjblock*) proto type jptr)->get_duration_expr(); if (e->hasjnt_value0) { duration = (int) int_value(e); // is phantom duration if block is phantom block if (is JnitO) init_duration = duration; else if (prototypejptr->isjphantom()) set jphantom_duration(duration) ; if (duration < 0) { outj3rror("INS005", cerr, TRUE); cerr « "This instance has an illegal duration value of " « duration « "Λn"; status = 1 ; } // check if this is a subroutine call block and there is a // subroutine available if (prototypejptr->is_subrJnst_made()) { block* subrjblock; int subr_dur; // get expression for subroutine duration subrjblock = prototypejptr->get_subrjnstanceO->prototype(); if (subr _block->is Jeaf _block()) { e = ((asmjblock*) subrjblock)->get_duration_expr(); if (e->hasjnt_value()) { subrjiur = (int) int_value(e); duration += subrjiur; if (subrjiur < 0) { . out_error("INS096", cerr, TRUE); cerr « "Subroutine body has an illegal duration" « " value of " « subr_dur« "Λn"; status = 1; } } else { out_error("TNS097", cerr, TRUE); cerr « "Subroutine body doesn't have a duration " « "definedΛn"; status = 1; -193 } else { out_error("TNS095", cerr, TRUE); cerr « "A subroutine body must be a primitive blockΛn"; status = 1; } else { out_error("TNS006", cerr, TRUE); cerr « 'This instance doesn't have a duration definedΛn"; status = 1; }} return status;} iπ iπi iiHπππiπ iiiuiiiiiπiunuiiiiiiiiiiiπniiiiiiiiii II instance: :compute_storage_sizes // Compute size of storage for this instance. // includes any phantom storage, which is referred back to us from prototype. // Outputs errors if storage sizes are now known and returns non-zero. int instance::compute_storage _sizes() [ // evaluate expressions which allocate sizes for storage and IO storage_entries = prototypejptr->storage_table_size(); first_phantom = storage_entries - phantom jstorage_table_size(); // will make the storage size array storage _sizes.clear() ; for (i=0; i<storage_entries; i++){ err = FALSE; e = prototypejptr->storage_entry_size(i); M-194 if (prototypejptr->is_storage irtual(i)) ; // ignore virtual storage else if (e->has Jnt_value()) { entry_size = (int) int_value(e); if (entry_size > 0) { storage_sizes[storage_sizes.size()] = entry_size; // update tally of storage location allocation n_storageJocs += entry size; // if in phantom storage range, tally it if (i >= firstjphantom) add_njphantom_storJocs(entry_size); // also save our own individual storage Iocs, not incl. childs our_n_storage Joes = n_storage Joes; } else err = TRUE; } else err = TRUE; if (err) { prototype jptr->storage_error("INS007", i, "Unknown vector size."); status = 1; } } return status;} II instance: :computeJo_sizes // Compute size of I O for this instance. // Outputs errors if I/O sizes are now known and returns non-zero. int instance: :computeJo_sizes(){ int status = 0; int i; int io_entries; BOOLEANerr; expr* e; M-195 int entry_sϊze; string* bad_entry_name; io entries = prototype _ptr->io_tabIe_size(); // will make the io size array io_sizes.clearO; for (i=0; i<io_entries; i++){ err = FALSE; e = prototype ptr->ioj3ntry_size(i); if (e->hasjnt_value0) { entry_size = (int) int_value(e); if (entry_size > 0) io_sizes[io_sizes.size()] = entiy size; else err = TRUE; } else err = TRUE; if (err) { bad_entry_name = prototypejptr->iojιame_atJndex(i); out_error("TNS008", cerr, FALSE); cerr « " Unknown vector size for the I/O called '" « *bad_entry jiame « "'\n"; status = 1; }} return status;} II instance::compute_contents // Called for the top level instance, this function computes location // allocations and all other contents, instantiating all child blocks. // It evaluates operands for asm blocks to make sure they are good. // If errors, return non-zero. int instance::compute_contents()! int status = 0; int i; instance*child; // save current block context and set instance info in block 5^1 M-196 push_context(); n storagejocs = njnstructjocs = njnit Jnstr Joes = duration = initjiuration = our_n_storageJocs = 0; set_njphantom_storJocs(0); se tjijphantom jnstr Jocs(0); setjphantom_duration(0); // evaluate expressions which allocate sizes for storage and IO status l= compute_storage_sizes(); status l= compute Jo_sizes(); // check truth of any verify expressions status l= check_verify_expressions(); // check validity of asm block if (istatus) status l= check jasm_block(); if (!status){ // call ourself for all our children, which adds to our loc counts for (i=0; i<childjnstances.size(); i++) { child = childjnstances[i]; if (child != (instance*) NULL) status l= childJnstances[i]->compute_contents(); } // add to our parent's tallies if (parent Jnstance) { parent Jnstance- >n_storage Joes += n storagejocs; parentJnstance->add_njphantom_storJocs(get_njphantom_storJocs()); parentjnstance->n Jnstructjocs += njnstructjocs; parent Jnstance-> add_njphantom_instrJocs(get_njphantomJnstrJocs()); parent Jnstance->njnit Jnstr Joes += njnit Jnstr Joes; parent Jnstance->duration += duration; parent Jnstance->addjphantom_duration(getjphantom_duration()); parentJnstance->init_duration += initjiuration; } } // restore previous block context pop_context(); return status;} -197 5^ // ϊnstance::compute_codejocations // Called for the top level instance, this function computes actual // starting locations to use for instructions in // all child blocks. // Also set the relative addresses of any labels in this block, if // it is hierarchical. // This is called in turn for each time zone, and only blocks which are // in that time zone are used (unless timezone has the value of NO_TTME_ZONE, // in which case everything is used). // We must have been previously sequenced. // Returns TRUE of this instance not skipped because it is in a different // time zone. BOOLEAN instance::compute_codeJocations(int& nextjnstrjbase, zone* timezone) ( int i; // ignore this block if its not in the desired time zone if (!is ?:one orjsubzone present(timezone) && timezone != NOJTIME_ZONE) return FALSE; // If we were called with NOJTϊME_ZONE and we have multiple, // then we must compute code locations for each zone, in turn. // (unless we are a manual block, of course!) if ((timezone = NOjTTME_ZONE && how_many_zones() && !prototypeO->is_manual block()) && shouldjpartition_design()) for (i=0; i<the_zones->n_zonesO; i++) do_compute_codejocations(next_instr_base, the_zones->get_zone(i)); else do_compute_codeJocations(next nstr jbase, timezone) ; return TRUE;} If instance-do ompute_codeJocations // Guts of compute_codeJocations for a time zone. // This routine also sets the label offsets both for hierarchical and asm // blocks. void instance::do_compute_codeJocations(int& nextjnstrjbase, zone* timezone)! int i, i_seq; int rel address; block* child proto; BOOLE ANchild_computed; 5 1 * BOOLEANusejpartitioned_seq = FALSE; // save current block context and set instance info in block push_context(); // set our base locations from the caller, unless we have an absolute org if (instruction jbase == NOJNSTR_BASE){ if ( !prototypejptr->is absoluteO) instruction jbase = nextjnstrjbase; else instruction jbase = prototypejptr->org();} // if this is asm block, set label offsets from label sequence #s if (prototype jptr->is Jeaf blockO) ! for (int j=0; j<prototypejptr->label_table_size(); j++) { // make sure this label hasn't had offset set if ( ! prototype jptr->label_offset_at Jndex(j)) { // Since our instructions are each one memory location, // label sequence is simply relative address of label. // Set label sequence as label offset rel address = prototypejptr->label_seq atJndex(i); prototype ptr- >setJabel_offset(j , reljaddress) ; } } } // Call ourself for all our children, which sets bases. // if partitioned sequence available, use it if (getjpartitioned_size()) usejpartitioned_scq = TRUE; for (i=0; i<childjnstances.size(); i++){ // use sequenced order (partitioned if available) if (use jpartitioned seq) i_seq = get_part_sequence(i); else i seq = get_sequence(i); childjproto = child Jnstances[i_seq]->prototype(); child_computed = childJnstances[i_seq]-> compute_code Jocations(next Jnstrjbase, timezone) ; // If we have labels, then set their relative addresses. // Labels in hierarchical blocks are "attached" to the instance // which they directly preceed, so that if this instance is M-199 // reordered, the label moves with it if (prototypejptr->label_ ablejsizeO && child j:omputed) { // check if any label refers to this child index // Label sequence has child index. We now set the offset from //start of our block for (int j=0; j<prototype_ptr->labelJable_size(); j++) { // make sure this label hasn't had offset set if (!prototypejptr->label_offsetjatJndex(j)) { if (prototypejptr->label _seq_atjndex(j) == i_seq) { // compute relative addr of label from our start reljaddress = nextjnstrjbase - instruction jbase; // set this as label offset prototype _ptr->set Jabel _offset(j , rel address) ; } } } } // advance the next base location provide child was actually // computed if (!child_proto->isjabsoluteO && childjproto->is Jeaf jblock() && child_computed) nextjnstrjbase += childjnstances[ϊ_seq]->n Jnstructjocs; } // restore previous block context pop_context();} uiiiiimπiiiiiiiπmiimiiiiπniπiiiiiiiiiiiiiiiiniiiiiimiiiiiiπ //ϊnstance::compute_dataJocations // Called for the top level instance, this function computes actual // starting locations to use for data storage in // all child blocks. void instance::compute_dataJocations(int next_storejbase){ int i, i seq; BOOLEANusejpartitioned_seq = FALSE; // save current block context and set instance info in block push_context(); M-200 storage >ase = nextjstore jbase; // advance past our own storage next_store_base += our _n_storage Joes; // if partitioned sequence available, use it if (getjpartitioned size()) usejpartitioned seq = TRUE; // call ourself for all our children, which sets bases for (i=0; i<childjnstances.size(); i++)[ // use sequenced order (partitioned if available) if (use jpartitioned_seq) i_seq = getjpart_sequence(i); else i_seq = get_sequence(i); childJnstances[i_seq]->compute_dataJocations(next 5tore_base); // advance the next base locations for suceeding children next_store_base += child Jnstances[i_seq]->njstorage Joes;} // restore previous block context pop_context(); } II instance: :generate_code // Called for an instance, this function outputs code // for this block and all blocks beneath it. // This is called in turn for each time zone, and only blocks which are // in that time zone are output (unless timezone has the value of NO_TIME_ZONE, // in which case everything is output). int instance::generate_code(ostream& code_stream, zone* timezone)! int i; int status = 0; // ignore this block if its not in the desired time zone if (!is_zone_or_subzonejpresent(timezone) && timezone != NOJTIMEJZONE) return status; // If we were called with NOJTDVlE ZONE and we have multiple, // then we must compute code locations for each zone, in turn. // (unless we are a manual block, or partitioning suppressed, of course!) if ( (timezone == NO_ΗME_ZONE && howjnany ionesO && !prototype()->is_manualjblock()) && shouldjpartition_design()) for (i=0; i<the iones->n ones(); i++) { -201 6 if (Jstatus) status l= do_generate_code(code_stream, the_zones->get_zone(i)); } else status I= do jenerate_code(code_stream, timezone); return status;} II instance-do generate_code // Guts of generate code, called for each time zone. int instance: :do_generate_code(ostream& code _stream, zone* timezone)! int i, i_seq; hϊer_bIock*hierjptr; int status = 0; // save pointer to our prototype as a hier block pointer, if we need it hierjptr = (hierjblock*) prototypejptr; // save current block context and set instance info in block push_contextO; // if this is an asm block, re-evaluate operands so we can output code if (prototype_ptr->is Jeaf jblock()) ! // evaluate operands for this block using the full hierarchy if(istatus) status l= ((asmjblock*) prototypejptr)->eval_operands(TRUE); // output the assembly code if (Ϊstatus) status l= ((asmjblock*) cur_bIock)->out_asm(code_stream); check_ostream(code_stream); } if (!status){ // call ourself for all our children for (i=0; i<get partitioned_size(); i++) { // use partitioned sequenced order i seq = get_part_sequence(i); status l= child Jnstances[i seq]-> generatej-Ode(code_stream, timezone) ; if (status) break; }} M-202 ^ 7 // restore previous block context pop_context(); return status; } II instance: :generate_data // Called for an instance, this function outputs data initialization // for this block and all blocks beneath it. int instance: :generate_data(ostream& data_stream){ int i, i_seq; hier_block*hierjptr; int status = 0; // save pointer to our prototype as a hier block pointer, if we need it hierjptr = (hier jblock*) prototypejptr; // save current block context and set instance info in block push_context(); // output the storage info, which is done for any block type status 1= cur block->out_storage(data_stream); check jDstream (data_stream) ; if (.status) { // call ourself for all our children for (i=0; i<getjpartitioned_size(); i++) { // use partitioned sequenced order i_seq = getjpart_sequence(i); status 1= childjnstances[i_seq]->generate_data(dataj5tream); if (status) break; } } // restore previous block context pop_context(); return status; } II output_name_and_value // Output a name and a value to the given output stream. void output jiame _and_value(string* name, long value, ostream& out){ int pad_chars; 5^8 M-203 int j; unsigned long trimmed_value; // compute # of space pad characters to make a fixed-length field pad_chars = MAXJHER_NAME SIZE - name->IengthO + 1; // output the hierarchical name, followed by spaces, and then the value out « *name; for (j=0; j<pad_chars; j++) out« " "; trimmed_value = value; trimmed_value = trimmed_value & Oxffff; out«form("%041x\n", trimmed_value); check_ostream(out); } II output_name_vaIue_and_type // Output a name and a value to the given output stream. void outρut_name_value and_type(string* name, long value, char type, BOOLEAN isjnicro, ostream& out)! int pad_chars; int j; unsigned long trimmed_value; char micro_char; // set character for micro tag field if (is_micro) micro_char = MICRO HAR; else micro_char= ' '; // compute # of space pad characters to make a fixed-length field pad_chars = MAXJIIER_NAME SIZE - name->length() + 1; // output the hierarchical name, followed by spaces, and then the value out « *name; for (j=0; j<pad_chars; j++) out « " "; trimmed_value = value; trimmed_value = trimmed_value & Oxffff; out«form("%041x %c %c\n", trimmed_value, type, micro char); check_ostream(out);} 5^-9 -204 // output_name_value24_and Jype // Output a name, value (24 bit), and data type to the given output stream. void output_name_value24 and_type(string* name, long value, char type, ostream& out){ int pad_chars; int j; unsigned long trimmed_value; // compute # of space pad characters to make a fixed-length field pad_chars = MAX_HIER_NAME SIZE - name->length() + 1; // output the hierarchical name, followed by spaces, and then the value out « *name; for (j=0; j<pad_chars; j++) out « " "; trimmed_value = value; trimmed_value = trimmed_value & Oxffffff; out « form("%061x %c\n", trimmed_value, type);} II output_name alue_and_zone // Output a name, value, and zone to the given output stream. void output_name ^aluejand_zone(string* name, long value, zone* zone_ptr, ostream& out){ int pad_chars; int j; int zonejium; unsigned long trimmed_value; zonejium = the_zones->find_zone (zone jptr); // compute # of space pad characters to make a fixed-length field pad_chars = MAX_HIER_NAME 3IZE - name->length() + 1; // output the hierarchical name, followed by spaces, and then the value out « *name; for (j=0; j<pad_chars; j++) out « " "; trimmed_value = value; trimmed_value = trimmed_value & Oxffffff; out « form("%041x", trimmed_value) « form(" %4x\n", zonejium); check jDstream (out) ; } M-205 II output_name_value_zone_andjype // Output a name, value, zone, and data type to the given output stream. πmπiiiimπiiiiimiiiiiiumiiuiiiiiiiiuiiiiiiiiiiiiiiiiiiiiiiiiii void output_name_value ?;one and_type(string* name, long value, zone* zonejptr, char type, BOOLEAN isjnicro, ostream& out) { int pad chars; int j; int zonejium; unsigned long trimmed_value; char micro char; zonejium = the_zones->find_zone(zonejptr); // set character for micro tag field if (isjnicro) micro_char = MICRO_CHAR; else microjchar = ' '; // if no trigger mask, just output name and value if (zonejium < 0) output_name_value_andjype(name, value, type, isjnicro, out); else! // compute # of space pad characters to make a fixed-length field pad ±ars = MAX_HTER_NAME SIZE - name->length() + 1; // output the hierarchical name, followed by spaces, and then the value out « *name; for (j=0; j<pad_chars; j++) out«" "; trimmed_value = value; trimmed_yalue = trimmed_value & Oxffffff; out « form("%041x", trimmedjvalue) «form(" %4x %c %c\n", zone_num, type, micro_char);} check pstream(out); } mmumminiHuumiminmimniiiiiimiiimmmtniumiuui If output_zonejrecord // Output a name, value, zone, and data type to the given output stream. void output zonejrecord(int zonejium, ostream&out)! int padjchars; int j; M-206 long mask; int decim; zone* zonejptr; string* zonejiame; long fifojsize; zonejptr = the_zones->get_zone(zone_num); mask = the_zones->zonejnask(zonejptr); decim = the_zones->decimation(zonejptr); zonejiame = tiιe_zones->get_zonejιame(zone_num); // compute fifo size from zone repeat count fifo_size = compute jif o_size(zonejptr->getj-epeat_count()); // compute # of space pad characters to make a fixed-length field pad_chars = MAX_H1ERJNAMEJSIZE - zone_name->length() + 1; // output the name, followed by spaces, and then the value out « form("%4x", zonejium); out « " " « *zone_name; for (j=0; j<pad_chars; j++) out « " "; out « form(" %04x %061x %041x\n", decim, mask, fifo_size); checkjDstream(out); } II instance: :output_storage_symbols // Called for an instance, this function outputs storage symbols // for this block and all blocks beneath it. int instance::output_storage_symbols(ostream& out){ -207 storage_entries = prototype jptr->storage_tablejsize(); for (i=0; i<storage_entries; i++){ // find out if this is micro interface symbol isjnicro = prototypejptr->get_micro_var(i); * // get name and hierarchical name string for this index name = prototype jptr->storage_name atJndex(i); hierjiame = prototypejptr->hier_storage_name_atJndex(i); // get data type for storage, based on any initial value type = prototypejptr->get_storage_type(i); // get integer value of this name, which is storage location exprjptr = prototype jptr->translation(name); value = exprjptr->int_value(&relocjype, &reloc Jevel); // if this wire has a time zone, output zone info, too if ((zone_prr = get_zonejror_wire(i)) != NO_TTME_ZONE) output_name_vaIue_zonejand_type(hier jiame, value, zonejptr, type, isjnicro, out); else output_name_value andjype(hier_name, value, type, isjnicro, out);} // call ourself for all our children for (i=0; i<getjpartitioned_sizeO; i++){ // use partitioned sequenced order i_seq = get_part_sequence(i); child Jnstances[i_seq]->output storage 3ymbols(out) ; } // restore previous block context pop_context(); return status;} II ϊnstance::output_io_symbols // Called for an instance, this function outputs io symbols // for this block and all blocks beneath it int instance: :output Jo symbols(ostream& out) { 8 zone* zonejptr; instance*inst; int wire; char type; BOOLEANisjnicro; BOOLEANis j5torage; instance*symbolJnst; int storage Jndex; string* xlatedjiame; // save current block context and set instance info in block push_context(); for (i=0; i<prototypejptr->io_table_size(); i++){ // find out if this is micro interface symbol isjnicro = prototype jptr->getjnicroJo(i); // get name and hierarchical name string for this index name = prototype jptr->io_namejatJndex(i); hierjiame = prototypejptr->hierJo_namejatJndex(i); // get integer value of this name, which is storage location exprjptr = prototypejptr->translation(name); value = exprjptr->int_value(&reloc_type, &reloc Jevel); // if this wire has a time zone, output zone info, too get_wireJorJo(i, 0, &inst, &wire); // get data type for storage, based on any initial value type = inst->prototype()->get_storage_type(wire); if ((zonejptr = inst->get_zone or #ire(wire)) != NO_TIME_ZONE) output jιame_value_zone_and_type(hier jiame, value, zonejptr, type, isjnicro, out); else output_name_value_andjype(hier_name, value, type, isjnicro, out); } // now check the symbols for any which are storage "aliases", // since SDI/SMI considers this section to be a storage alias section // rather than an I/O section for (i=0; i<prototypejptr->param_table_size(); i++){ isjstorage = FALSE; // get name and hierarchical name string for this index name = prototype jptr->param_name ιt Jndex (i); hierjiame = prototypejptr->hierjparam_name_atJndex(i); // get value expression for this name exprjptr = prototypejptr->param_exprjatJndex(i); 55^ 09 if (translates jro storagefname, &symbolJnst, &xlated ιame)) { if (symbol Jnst->prototype()-> look_upj5torage_name(xlated iame, &storag Jndex)) { isjstorage =TRUE; // get expression for storage location in final instance exprjptr = symbol Jnst->prototype()->translation(xIated_name); // its a storage name, so get zone zonejptr = symbol Jnst-> get ϊoneJor_wire(storage Jndex); // get data type for storage type = symbol Jnst->ρrototype()-> get_storagejype(storage Jndex) ; // find out if this is micro interface symbol isjnicro = prototype()->getjnϊcro_symbol(i); 1 } if (isjstorage) { // set context to that of symbol so it can be evaluated symbol Jnst->push_context(); value = expr ptr->int_value(&relocjype, &relocJevel); symbol nst->pop_contextO; // if this wire has a time zone, output zone info, too if (zonejptr != NO_TTME_ZONE) output_name_value_zone_and_type(hier_name, value, zonejptr, type, isjnicro, out); else output_name_value_and_type(hier _name, value, type,is_micro, out); }} // call ourself for all our children for (i=0; i<getjpartiύoned_size(); i++)! // use partitioned sequenced order i_seq = getjpart_sequence(i); chiIdJnstances[i_seq]->outputJo _symbols(out) ; } // restore previous block context pop_context(); M-210 return status;} II instance: :outputJabels // Called for an instance, this function outputs labels // for this block and all blocks beneath it. // This is called in turn for each time zone, and only blocks which are // in that time zone are output (unless timezone has the value of NO_TIME_ZONE, // in which case everything is output). int instance: :outputJabels(ostream& out, zone* timezone)! int i; int status = 0; // ignore this block if its not in the desired time zone if (!isjLonejor_subzonejpresent(timezone) && timezone != NO_TIME_ZONE) return status; // If we were called with NO JTIME_ZONE and we have multiple, // then we must output labels for each zone, in turn. // (unless we are a manual block, or partitioning suppressed, of course!) if ( (timezone == NO_TTME_ZONE && how_many_zones() && !prototype()->is_manual_block()) && shouldjpartition_design()) for (i=0; i<the_zones->n_zones(); i++) { if Ostatus) status l= do_outputJabels(out, the δones->get_zone(i)); } else status l= do_outputJabels(out, timezone); return status;} II instance::do_outputJabels // Called for an instance, this function outputs labels // for this block and all blocks beneath it. int instance::do_outputJabels(ostream& out, zone* timezone)! int i, i_seq; int status = 0; string* hierjiame; string* name; long value; M-211 // save current block context and set instance info in block push_context(); // output labels only if the block is not empty if (get_nJnstructJocs())! if (!areJabeIs_output()) { for (i=0; i<prototypejptr->label_table_size(); i++) { // get name and hierarchical name string for this index name = prototype jptr->label_name atjndex(i); hierjiame = prototype jptr->hierjabel_name_at Jndex® ; // get address for this index value = prototypejptr->label_address(i); // only output if there's a real address if (value != NO_ADDRESS) output_name_and_value(hier jiame, value, out); } set Jabels _output() ; } // call ourself for all our children for (i=0; i<getjpartitϊoned_size(); i++) { // use partitioned sequenced order ϊ_seq = get_part_sequence(i); child Jnstances[i seq]->outputJabels(out, timezone); }} // restore previous block context pop contextO; return status;} II instance::output_symbols // Called for an instance, this function outputs symbols // for this block and all blocks beneath it. int instance::output_symbols(ostream& out)! 2 expr* val; long int_val; int relocjype, relocjevel; char datajype; BOOLEANis real; instance*symbolJnst; // save current block context and set instance info in block push_context(); // get the block symbols for (i=0; i<prototypejptr->paramJ:able_size(); i++){ // get name and hierarchical name string for this index name = pro totypejptr->param_namejat Jndex (i); hierjiame = prototypejptr->hierjparamjιame_atJndex(i); // get value expression for this name val = prototypejptr->param_expr_atJndex(i); // flag if it translates to storage, don't output if (!translatesJ:o_storage(name, &symbolJnst, &name)) { if (!eval_24_bit_value(val, &int_val, &reloc_type, &reloc Jevel, &is_real)) { // if relocation type is "relative", then this is an address, // so signal this with a hex data type if (reloc ype == RELATIVE) datajype = 'h'; else if (fisjreal) datajype = 'i'; else datajype = T; output_name ^alue24 and_type(hier_name, int_val, datajype, out); } } } // call ourself for all our children for (i=0; i<getjpartitioned_size(); i++){ // use partitioned sequenced order i_seq = getjpart_sequence(i); childJnstances[i_seq]->output_symbols(out);} // restore previous block context M-213 pop_context(); return status;} If instance::translates_to_storage // See if the given name can be (recursively) translated to storage. // If yes, return TRUE and the storage name and instance context for // this name in which the storage exists. BOOLEAN instance: :translates_to_storage(string* name, instance** inst, string** storage jiame) ! int storage Jndex; int paramjndex; instance*pathjnst; instance*symbolJnst; expr* exprjptr; // see if storage by this name exists here if (prototype()->lookjjp storage_name(name, &storage Jndex))! *inst = this; *storage_name = name; return TRUE;} // otherwise try to get expression for name else if (prototypeO->lookjjpjparam_name(*name, &param Jndex))! exprjptr = prototype()->param_expr at_index(param_index); if (exprjptr->eval_to symbol(&name)) { // it evaluates to a symbol, so see of xlation exprjptr = prototype()->transIate_withJnstances(name, &path Jnst, &symbol_inst); if (exprjptr != (expr*) NULL) { // get name with path stripped off symbol Jnst = path Jnst->get .instance jf_name(name, &name); if (symbol Jnst != (instance*) NULL && symboljnst != this) { // have new name in the context of a new instance // so recursively translate to storage return symbolJnst->translates_to_storage(name, inst, storage_name); M-214 } } } } return FALSE;} // instanc2.cxx // instance class // T. Montlick // 11/30/89 /* source code control: */ static char SccsID[] = "@(#)instanc2.cxxl.56 10/7/91"; #ifndef INSTANCE_DEF #include "instance.hxx" #endif II instance: :connect_childjport // Make sure our "name" is a valid signal for us to connect to port j // of the given child instance and child prototype. // Set the "wirejnjparent" for port j of this child to our wire or VO. II If any errors, output them and return nonzero. int instance::connect_childjport(string* name, int j, instance* child Jnstance, block* childjprototype,intjarray& n_outputsj;o_wire, int_array& n_outputs_to_output){ int status = 0; int index; instance *another Jnst; // child VO can be connected to either our wire or one of our I/Os, // so see which it is if (prototype jptr->look_up Jo jιame(name, &index)) { // child I/O is connected to one of our I Os // so set which of our I/Os in child child Jnstance->wirejnjparent[j] = index; child Jnstance- >wire_reallyJo[j] = TRUE; // make sure vector sizes match if (io_sizes[index] != childJnstance->io_sizes[j]) { child Jnstance->outj3rror("INS009", cerr, TRUE); cerr « " You can't connect I/O '" 56θ 15 « *name « "' of width " « ϊojsizes [index] « " to an I/O of width " « childJnstance->io_sizes[j] « "\n"; status = 1; } if (childjprototype->ioJsj3utput(j)) { // child I/O is an output // make sure it doesn't connect to our input if (!prototypejptr->ioJs 3utput(index)) { childJnstance->out_error("TNS010", cerr, TRUE); cerr « "You can't connect the input '" « *name « "' to an output in the called block\n"; status = 1; } else { // child output connects to one of our outputs // output can only have one output onto it n _outputs_to_output[index] ++; if (n_outputs :o 3Utput[index]>l) { child_instance->out_error("INS011", cerr, TRUE); cerr « "Output "' « *name « '" already has an output connected " « "to it\n"; status = 1; } } } } else if (prototypejptr->lookjjp_storagejιame(name, &index)) { // it is connected to one of our wires, so set which in child childjnstance->wirejnjparent[j] = index; // make sure vector sizes match if (storage_sizes[index] != child Jnstance->io_sizes[j]) { child Jnstance->outj3rror("INS012", cerr, TRUE); cerr « " You can't connect wire '" « *name « "' of width " « storage_sizes[index] « " to an VO of width " « child Jnstance->io_sizes[j] « "\n"; status = 1; } // if child I/O is an output, mark this in our wire if (childjprototype->ioJs_output(j)) { // wire can only have one output onto it njDutputs_to_wire[index]++; if (nj3utputs_to Λ'ire[index]>l) { childJnstance->outj3rror("INS013", cerr, TRUE); cerr « "You are trying to connect more than one " « "output to wire '" « *name « '"\n"; status = 1; } } } else if (find_wire_name(name, &index, &anotherJnst)){ // wire is actually in a higher level instance than our parent // so set this as the "bypass parent" instance childjnstance->wirejnjparent[j] = index; childjnstance->bypassjparent[j] = another Jnst; // if not top level IO, make sure the user knows what he's done if ( ianother Jnst->is_top Jevel()) { childJnstance->out_warning("TNS014", cerr, TRUE); cerr « " Do you know you connected to wire '" « *name « '" in the hi '6gh' er\n level instance '" « another Jnst->instance_name « "'?\n"; }} else! child_instance->outj3rror("TNS015", cerr, TRUE); cerr « "You tried to connect '" « *name « '", which is not an VO or wire name\n"; status = 1;} return status;} uiiiπiiiiiπiiiπiππiuiiiniiiiuiππiiiiπuiiiiiiiiiiiiiiiiπiiiiπiHi ff instance::wire_connections // Create the connections between this instance and its child instances. // Called for the top level block, this function recursively calls itself // for all child blocks. // Wiring info is established both for instances and blocks. Instances know // about the connections to their parents, while hierarchical blocks know // about the connections with their children. // Outputs errors if mismatch in VO sizes, or multiple outputs onto 1 wire, // and returns non-zero. int instance: :wire_connections()! int status = 0; block* childjprototype;// prototype block for child blockjref *child jref ; // our reference to child string* child jblk_name; // info from reference ... string* chϊldjiame; arg_set*child_vals ; arg_set*childjports; int linejium; int i; string* name; instance*child Jnstance; expr* our iame _expr; int childjports_size; int_arrayn_outputs_to_wire- / # outputs onto wire from our children intjarrayn Dutputs _to DUtput;// # outputs onto VO from our children // save current block context and set instance info in block push_contextO; // create connections for each child for (i=0; i<childjnstances.size(); i++){ childjprototype = child Jnstances[i]->prototypejptr; child Jnstance = child Jnstances[i]; child jref = child_refs[i]; if (child ref != (block_ref*) NULL) { // get reference info for this child childj-ef->get_blockJnfo(&child_blkjιame, &childj ame, &child_vals, &childjports, &line_num); if (childjports) { childjports_size = childjports- >size(); if (childjports_size != childjprototype->io_table_size()) { childJnstance->outj3rror("INS016", cerr, TRUE); cerr « " You tried to call this block with " « child jports jsize « "I/O ports specified, but it has " « childjprototype->ioj:able_size() « " I O ports\n"; status = 1; } else { for (int j=0; j<childjports_size; j++) { if (childjports->stored_byjιame()) { // stored by name, so look up child's name for I O name = childjprototype->io ιame_atJndex(i); // now look up that name in our hash table if (!childjports-> expr_atjιame(*name, &our_namej3xpr)) { child_instance->out_error("INS017", cerr, TRUE); cerr « "You haven't specified the I/O " « "port named '" 56 19 « *name « '"\n"; status = 1; } } else { // just look up our name expr in stored-by-pos array our_name_expr = child jports->expr_atjposition(j); } // we now have an expression which should evaluate to // one of our wire or VO names if (!our_name_expr) { child Jnstance->out 3rror("TNS018", cerr, TRUE); cerr « " No VO or wire name for por Xn"; status = 1; } else if (!our_name_expr->eval_to_symbol(&name)) { child_instance->out_error("INS019", cerr, TRUE); cerr« ""' « *our_name _expr « "' is not one of our VO or wire names\n"; status = 1; } else // connect this VO port of child status 1= connect_childjport(name, j, child Jnstance, childjprototype, n_outputs_to_wire, n _outputs_to jDutput) ; } } } } // recursively call our children status [= child_instances[i]->wire_connections();} //make sure that all our outputs are connected to child outputs if (child Jnstances.size())! for (i=0; i<prototype ptr->io_table_size(); i++) M-220 if (prototypejptr->ioJsjDutput(i)) { // no connected output only legal if a non-autosequenced if (!n_outputs_to )utput[i] && prototypejptr->is_autosequence()) { outj3rror("INS020", cerr, FALSE); cerr « "There is no connection to the output " « "port named '" « *prototypejptr->io_name αtJndex(i) « '"\n"; status = 1; } } } } // Have established connections between this instance and its child // instances, so we must now establish connections between our // prototype block and its child block refs, provided they have // not previously been determined, if ( iprototype jptr->is Jeaf _block()) make_prototype_connections(); // mark this instance's child connections as set connections_set = TRUE; // restore previous block context pop_context(); return status;} // instance::makejprototype_connections // Establish connections between our // prototype block and its child block refs, provided they have // not previously been determined. void instance: :makejprototype_connections() { hier_block*hierjptr; block* child jpro to type;// prototype block for child int i; instance*child Jnstance; int parent_wire; int_arraywirejιas 3utputy/ TRUE if wire has output int arraywhichjDutput;// which output of child wire int arraywhϊchjblock;// which child block outputs to wire // save pointer to our prototype as a hier block pointer hier ptr = (hierjblock*) prototypejptr; // do only if prototype not previously done if (!hier_ptr->are refs_connected()) { // initialize array of which of our wires have outputs for (i=0; i<storage_sizes.size(); i++) wire_has_output[i] = FALSE; // find which children output to which of our wires for (i=0; i<child_instances.sizeO; i++) { childjprototype = child_instances[i]->prototypejptr; child Jnstance = child Jnstances[i]; for (int j=0; j<childjprototype->io_table_size(); j++) { // if this child VO an output onto one of wires, // record for this wire what child and child I O // this is if (child_prototype->ioJs Dutput(j)) { parent_wire = child jnstance-> wire Jnjparent[j]; // make sure its our wire, not our FO if (!childjnstance->wirejreally Jo[j]) { which _output[parent_wire] = j; which _block[parent_wire] = i; wireJιas_output[parent_wire] = TRUE; } else { // output is VO, so set connection between // this child and the output of this block, // which has special negative pseudo-block // index hier ptr->add_connection(i, -1, parent_wire, j); } } } } // now find which children input from our wires for (i=0; i<childjnstances.size(); i++) { // only consider other children which have block references if (child_refs[i] != (blockjref*) NULL) { child jprototype = child Jnstances[i]->pro to type jptr; child Jnstance = childjnstances[i]; for (int j=0; j<childjprototype->ioj:able_size(); j++) { // if this child wire an input, add a connection // from the child output on the wire to this child input if (!childjprototype->ioJs 3utput(j)) { parent_wire = child Jnstance->wirejnjparent[j]; // If our wire really I/O, add to the list of // input connections for this block; that is, // what child blocks and child block inputs are // at the front of this block. // HOWEVER: Just because this an input for our // child, do not assume it is an input for us! if (child Jnstance- >wire_reallyJo[j]) { if ( [prototype jptr->io Js joutput(parenLwire)) { hierjptr->add_toJnputs(i, j); // tally # of inputs from this input hierjptr->bumpJnput_use_count(paren ire); } } else { // connects to our wire, so just add // connection from output block to this // block's input hierjptr->add_connection( which jblock[parent λ'ire] , ϊ, j, which 3utput[parent_wire]); // also tally # of inputs from this wire hierjptr->bump_wirejJse_count(parent_wire); } } } } } // make sure all wires have at least one input and output // skip if this is top level phantom block if (parentO) { for (i=0; i<storage_sizes.size(); i++) { if (!wireJιas_output[i]) { // skip warning if user-created phantom // or if a variable, as opposed to a wire if ( !phantom_name(*prototype ptr-> storage jιamejat_index(i)) ) if ( !prototypejptr->is_a_variable(i) ) { out_warning("INS021", cerr, FALSE); cerr « "There is no signal to the wire named '" «*prototypejpti»storagejiame_atJndex(i) « Λn ; } if (!hierjptr->get_wire_use_count(i)) { // skip warning if user-created phantom // or if a variable, as opposed to a wire if ( !phantom_name(*prototypejptr-> storage_name atJndex(i)) ) if ( !prototype ptr->is a_variable(i) ) { out_waming("INS022", cerr, FALSE); cerr « "The signal from the wire named '" « *prototypejptr->storage jiame _atjndex(i) -224 « '" doesn't go anywhereΛn"; } } } } } // we've connects the refs in the prototype, so remember this hier jptr->set_ref s_connected() ; } II instance::add_topJevelJnputs // Called for the top level block, this function scans its child block refs // for input port blocks, and adds these to this block prototype's block // inputs list. This is so that the top level block may be sequenced from // its inputs just like any other block. // Returns nonzero if block is input port and not at top level. int instance: :add_top Jevel JnputsO { int i; hierjblock*hierjptr; block* blk jptr; int status = 0; // save pointer to our prototype as a hier block pointer hierjptr = (hierjblock*) prototypejptr; for (i=0; i<get_n_children(); i++){ // get pointer to child block prototype blk jptr = hierjptr->get_blockjpointer(i); if (blk_ptr == NULL) blk jptr = blk jptr; // test if block is an input to the SPROC if (blkjptr->is_sproc JnputO) // II (childJnstances[i]->add_topJevelJnputs()) ) { status = 1; // add child block's input // to our list (input port # doesn't matter) hierjptr->addj:oJnputs(i, 0); // if top level, always return 0 if (is_top JevelO) status = 0; M-225 } child Jnstances[i]->add_top Jevel Jnputs();} return status;} II instance::get_addr_of_storage // Given a storage index for this block, return the address of the actual // storage which this should use. iπiiiinπiiiiiπiinπiui iiπ iiiiiπiiiiniimiπiriimiiiiriiπii int instance-get jaddr_of_storage(int index)! int address; string* virtualjpath; instance*pathjnst; expr* storage_expr; long expr_value; int relocjype, relocjevel; BOOLEANis_real; // if address already computed, just return it if (address = storage_addresses[index]) return address; if (prototypejpti»isj?torage_virtuaI(index)) ! // virtual storage, so get string for where to find it virtualjpath = prototypejptr->get_virt_storagejpath(index, &pathjnst); // path string is respect to path instance, so set as context pathJnst->push_context(); // translate string to an expression storagejexpr = pathJnst->prototypeO->translation(virtualjpath); // evaluate the expression from here eval_24_bit_value(storage_expr, &expr_value, &reloc_type, &reloc Jevel, &is_real); pathJnst->pop_context(); address = (int) expr_value;} else! // for ordinary storage, just compute offset from base address = prototypejptr->storagej3ffset atJndex(index); address += storage jbase;} p q // newly computed address, so save for later reference storage _addresses[index] = address; return address;} M-226 II insiancc::gcι_wirc orjo // Given an I/O index for this block, return the instance and the wire in // this instance that the I/O is actually connected lo. // Supports a phantom level for the given wire, supplying the particular // phantom wire requested. // Also supports a parent bypass instance for phantom blocks which need // access to any wire in an ancestor. // Returns FALSE as the value of the function if wc ran out of ancestors. BOOLEAN instance::gc wircJorJo(int index, int phantomjevel, instance** which Jnstance, int* which_wirc){ int parentjndcx; // get which wire this is in our parent, which may actually be an I/O parentjndcx = wirejnjparcnt[index]; // test for a parent bypass (instance given directly) if (bypass jparent[indexl){ // have been given instance thai wire is in, so return in o // first translate the index into the wire appropriate lor this level // of phantom wire *which Jnstance = bypass jparent[indcx]; *which Λ'ire = bypass_parcnt[index]->get_phantom(ρarenιjndcx, phantomjevel); } // if it's really a parent I/O, then call us for parent else if (wircj"eallyjo[index]){ if (parcntjnstancc) return ρarcntJnsiancc->gc wircj " orJo(parcniJndcx, phantomjevel, which Jnstance, which_wirc); else return FALSE;} clsc{ // really a wire, so return its info // first translate the index into the wire appropriate for this level // of phantom wire *whichjnslance = parcntjnstancc; *which A'ire = parcntJnsiancc->geijphaniom(pareniJndex, phantomjevel); ] return TRUE;} II instance::getJo Jor_wirc SUBSTITUTE SHEET 1VI-227 // Inverse of "get_wireJorJo". // Given an instance and a wire in that instance, return the I/O index in the //current instance which points to this wire. // Returns FALSE as the value of the function if could not find. BOOLEAN instance::getJoJor_wirc(instance* which Jnstance, int which_wirc, int* io Jndex){ int njos; int i; instance*testjnstance; int test_wire; // scan each I/O, seeing if it matches the wire n Jos = prototype_ptr->io_table_sizc(); for (i=0; i<nJos; i++){ get_wircJorJo(ϊ, 0, &tcstjnslancc, &tesi_wire); if (testjnstance == which Jnstance && test_wirc == which _wire) { *ioJndcx = i; return TRUE;} } return FALSE;} II ϊnslance::fmd vire_name // Find the given wire by name in one of our ancestors. // Returns the index in ancestor, plus a pointer lo the ancestor instance. //This is used lo create a bypass to an arbitrary ancestor wire, not // using the ordinary I/O mechanism. Used for phantom blocks which need // I/O from arbitrary wires. // Returns FALSE as the value of the function if could not find the name. BOOLEAN instance-find _wircjιame(slring* name, int* which_wire, instance** which Jnst) { int index; instance*parentjpir; if (parcntjplr = parcn jnstancc) { if (parentjptr->protolypcjptr->lookj.ιp_sloragejιame(name, &index)) { // found storage in parent *which «vire = index; *which Jnst = parentjptr; return TRUE;! M-228 else if (parent jptr = parent jnstance)! if (parentjptr->prototypejptr->look_up_storagejιame(name, &index)) { // found storage in parent *which_wire = index; *which Jnst = parentjptr; return TRUE; } else { // try parent's parent, etc. return parentjptr- >find_wire_name(name, which_wire, whichjnst); } } else return FALSE;// no parent, so can't find} II instance: :getjaddr_of Jo // Given an VO index for this block, return the address of the actual // storage which this VO should use. int instance-get jaddrj3fJo(int index)! instance * which Jnstance ; int which wire; int address = 0; int phantomjevel; // get phantom level recorded for this I/O phantomjevel = getjphantomJoJevel(index); // get wire for this I/O, at the given phantom level if (!get_wireJorJo(index, phantomjevel, &which nstance, &which_wire)){ out_error("INS024", cerr, FALSE); cerr « "The top level block can't have any I/O declared for it!\n"; return 0;} else address = which Jnstance->get_addr_of_storage(which_wire); return address;} II instance: :getjaddr_of Jabel // Given a label index for this block, return the address // which this should use. 57k M-229 int ϊnstance::get_addr_of _label(int index)! int address; address = prototype ptr->label Dffset at_index(index); // if rel address is really a signal that there's no address, leave alone! if (address != NO.ADDRESS) address += struction base;// else add our base to form abs. addr. return address;} II hier_name 5tring() // Returns a string for the hierarchical name. strmg*instance::hierjιame 5tring() ! char nameIMAX HER_NAME 3IZE]; // init name array to nulls, so chars we stream in will have // a null delimiter for (int i=0; i<MAX_HT£Rj AME 3IZE; i++) namefi] = '\0'; // create an output stream which uses our character array ostreamname >tream(MAXJHIERJ AME SIZE, name); // stream our hierarchical name into our array name_stream « *this; // create a new string from this return (new string(name));} //instanc3.cxx // instance class //T. Montlick // 11/30/89 /* source code control: */ static char SccsTDD 10/7/91"; #ifndefINSTANCE_DEF include "instance.hxx" #endif #undef DEBUG II getJnstance_of_name() . // Treating the name string as a pathname in the hierarchy from where we are, M-230 // Get a pointer to the instance which this name would be in. // Returns NULL if no such instance. instance*instance::get Jnstance j3f_name(string* name, string** remainder)! char* startjptr; char* endjptr; instance*currentjnst; char inst_name[MAX_HIER_NAME SIZE]; int i; BOOLEANfound_the_name; int n_chars; currentjnst = this; startjptr = &name->operator[](0); while (currentjnst)! // search for the next "." in the name string if (end_ptr = strpbrk(startjptr, ".")) { // there is an instance name between startjptr and endjptr // copy it into our character array n_chars = endjptr - startjptr; // limit name to max size if (n_chars > MAX_HIER_NAME 5IZE) n_chars = MAX_HIER_NAME SIZE; strncpy(inst_name, start_ptr, n_chars); // don't forget terminal null inst_name[n_chars] = '\0'; // look for a child instance with this name foundjhejiame = FALSE; for (i=0; i<currentjnst->childjnstances.size(); i++) { if (current Jnst->childjnstances[i]->instancejιame == inst jiame) { currentjnst = current Jnst->childjnstances[i]; foundjhejiame = TRUE; break; M-231 // if we didn't find the name, no current instance so get out if (!found_the_name) currentjnst = NULL; // advance place in hierarchical name past the next "." startjptr = endjptr + 1; } else break; } if (currentjnst)! // there should be no hierarchy left // if there is, then we haven't got the instance if (strpbrk(start_ptr, ".")) currentjnst = NULL; else { // create the remainder name string and return it strcpy(inst ιame, startjptr); Remainder = new stringrinstjiame); }} return currentjnst;} II out_error() // Output the error line for this instance. // If parent is true, output message referenced to parent file, else // output message referenced to our file. // Returns TRUE if OK to output rest of error msg. void instance::outjerror(char* msg_code, ostream& e, BOOLEAN parent)! if (icheck_error_count()) ; // will exit here if too many errors u q q o o re «ERR_STRTNG « msg_code«" "; iffpar , en?&& fιsio leve ι i ) 4 m Q Q f if (nθ_fileJnfθ) παu u qqqq oooo ff e « "Instance "' « *this « '" contained in block "^ « *parentJnstance->prototypejptr->getjblock_name() «""'; else e « "Instance '" « *this « "' called from '" -232 « *parentJnstance->prototype ptr->get_block_name() « "' in '" « *parent Jnstance- >prototypejptr->get_filenameO « "', line " « linejium; } else! if (no _file Jnfo) e « "Instance '" « *this « "' contained in block '" « *prototypejptr->getjblock jiame () « "'"; else { e « "Instance '" « *this « " ' of block "' « *prototypejptr->get_blockjιame() « '" in '" « *prototypejptr->get_filename() « "'"; // if caller set "instr Jine", use this if (instr Jine) e « ", line " « instr Jine; } } e « ERR_DELTM;} II out_warning() // Same as out_error, but displays a warning and does not return a value. void instance::out warning(char* msg_code, ostream& e, BOOLEAN parent)! e « WARN STRING « msg_code « " "; if (parent && !is_topjevel0){ if (no_file Jnfo) e « "Instance '" « *this « "' contained in block '" « *parentJnstance->prototypejptr->get_block_name() « ""'; else e « "Instance '" « *this « "' called from '" « *parentJnstance->prototypejptr->get_block_name() « '" in '" « *parent_instance->prototypejptr->get_filename() « "', line " « linejium;} else{ if (no_file Jnfo) e « "Instance '" « *this « "' contained in block '" « *prototypejptr->get_block_name() « M-233 else { e « "Instance "' « *this « '" of block '" « *prototype pti»get block_nameO « "' in "' « *prototyρe ptr->get_filename() « "'"; // if caller set "mstrjine", use this if (instr Jine) e « ", line " « mstr Jine; }} e «ERR_DEL1M;} m mnimHiuiiu iiiiiiinmmiimuimumiimin iHHii II operator« // Output the instance name hierarchically. iu m n miiiuuiHu imuH inu uuuuni ii ostream& operator«(ostream& s, instance& i){ if ( parentjnstance) // call our parent, so its output comes first // but suppress top-level parent instance, 'cause its redundent if (!i.parentJnstance->ϊs_topJevel()) { s « *(i.parentjnstance); // output a dot as a separator s « "."; }} // after output of any parents, output our name return s « instance iame;} //is_topjevel0 // Returns TRUE if this is a top level instance. BOOLEAN instance::is_top Jevel(){ // Either very top (phantom top level) or 2nd from top (user top level) // is considered a top level instance, if (parent Jnstance) ! if (parent Jnstance->parent nstance) return FALSE;} return TRUE;} M-234 II instance: :copyJn_sequence // Called for the top level instance, this function copies into each // instance the block sequence generated by the block prototype. // Our prototype block must have been previously sequenced. int instance: :copyJn_sequence()! int i; hier_block*hierjptr; // save pointer to our prototype as a hier block pointer, if we need it hier jptr = (hierjblock*) prototypejptr; // call ourself for all our children, which sets bases for (i=0; i<childjnstances.size(); i++)! // copy sequence from prototype sequence[i] = hierjptr->sequenced_child(i); // call for our child child Jnstances[i] ->copy Jn_sequence() ; } return 0;} II set_zone or _wire // Set the given wire as existing within a particular timezone. // Also, duplicate any timezone for the wire to all its phantoms. void instance::set_zoneJor_wire(int index, zone* timezone)! int wirejevels; int i; #ifdef DEBUG string* wire jiame; wirejiame = this->prototype()->hier_storage_namejatJndex(index); cerr « "setting wire " « *wirejιame « " to zone " « *timezone->get_zonejιame() « 'Λn"; #endif wirejevels = getjphantom_wireJevel(index) + 1; for (i=0; i<wirejevels; i++) zone or_wire [get jphantom (index, i)] = timezone; } M-235 // set_wire_zones // Called for a sequenced block which has zones set for its input wires, // this function sets the zones for all output wires. // NOTE: the top level FO wire zones got set from zones::identify_zones(). // It calls itself recursively to set the wire zones // for all children. // Included is processing of a rate change block, which creates a new // upsampled or downsampled sub-zone. // Returns FALSE if error. BOOLEAN instance::set_wire_zones()! int i, ijseq,j, k; hier_block*hier_ptr; BOOLEANstatus = TRUE; instance*wire_inst; int wire; zone* zonejptr; zone* new_zonejptr; int storage_entries; // save pointer to our prototype as a hier block pointer, if we need it hier jptr = (hierjblock*) prototypejptr; // save current block context and set instance info in block push_contextO; // if this is an asm block, find a zone for an input wire // and set zones for outputs if (prototype ptr->is JeafjblockO) { zone_ptr = NO_TTME_ZONE; // scan all inputs to get zones for (j=0; j<prototype pti»io_tablejsizeO; j++) { if (!prototypejptr->iojs output(j)) { if (!get_wire_forJo(j, 0, &wirejnst, &wire)) { out_error("TNS903", cerr, TRUE); cerr « "INTERNAL ERROR ~ No wire for input in " « "set_wire_zones.\n"; status = FALSE; break; } // get zone for input // All inputs must be in compatible zones, but they // all may not be in the same zone. Take the latest ι // of the input zones as the zone to label for outputs. // This assures that output wire value is generated only // when we have reached this timezone. new_zonejptr = wire Jnst->get_zone or Λ'ire(wire); if (new_zone_ptr != NO_TIME_ZONE) { if (zonejptr == NO_TTME_ZONE) zonejptr = new_zonejptr; else { // got a different zone, so save latest if (the_zones->later_zone(new_zonejptr, zone_ptr)) zonejptr = new_zonejptr; } } } } if (status) { if (zone ptr == NO_TTME_ZONE) { // No zone for input, so this instance should // already have a zone if it is an input instance. // If zone present in instance, than get it and use it if (single_zoned()) zonejptr = get_zone(0); } if (zonejptr != NO_TIME_ZONE) { // Check if instance of a rate change block, // in which case we must create a new timezone. // This zone is the one to use for output wires if (prototypejptr->is_rate_change_block()) status = setjιew_output_zone(zone_ptr, &zone_ptr); M-237 } if (zone_ptr !=NO TIME_ZONE) { // scan all outputs and set the zone // for their wires for (k=0; k<prototype ptr->io_table_sIze(); k++) { if (prototypejptr->io Js 3utput(k)) { if (!get_wireJor Jo(k, 0, &wirejnst, &wire)) { out_error("TNS904", cerr, TRUE); cerr « "INTERNAL ERROR - No wire for output" « " in set_wire_zones.\n"; status = FALSE; break; } wireJnst->set_zone_for_wire(wire, zonejptr); } } // also scan all wires in this block and set their zone storagejentiies = prototype _ptr->storage_tablejsize(); for (k=0; k<storage_entries; k++) set_zoneJor_wire(k, zonejptr); } else { // error unless this is phantom block, which need not be in // a zone // virtual FO will get set later when we set instance zones if ( 'prototype ptr->isjphantomO && !prototypejptr->isjblock_virtualJo() ) { .out_warning("INS025", cerr, TRUE); cerr « "Unable to determine a timezone for FO' « " in this blockΛn"; }} if (status)! // call ourself for all our children for (i=0; i<child_instances.size(); i++) { // use sequenced order i_seq = sequence[i]; status = childJnstances[ seq]->set Λ'ire_zones(); if (istatus) break; } } // restore previous block context pop_context(); return status; } II set_new_output_zone // A rate change block instance has been encountered in the process of // setting wire zones, so create a new time sub-zone. // Passed the zone for the inputs to the block, and returns the // newly created zone for the outputs from the block. // Returns FALSE if error. BOOLEAN instance::set_new_output_zone(zone* in_zone, zone** out_zone ptr){ expr* ratio_exprjptr; long ratio; BOOLEANstatus = TRUE; BOOLEANdecimating; zone* new_zonejptr; // evaluate the rate change factor ratio_exprjptr = prototype_ptr->get_changejratio(); decimating = prototype jptr->is_decimating(); if (ratio _exprjptr->has Jnt value()) { ratio = int_value(ratio_exprjptr); if (ratio <= 0) { out_error("TNS031", cerr, TRUE); cerr « "Illegal decimation/interpolation ratio of " « ratio « "Λn"; status = FALSE; M-239 }} else! out 3rror("TNS032", cerr, TRUE); cerr « "Decimation/ύiterpolation ratio expression " « *ratio_expr ptr « " not an integerΛn"; status = FALSE;} // ask the zones class the create the time sub-zone if (status)! new _zonejptr = the_zones-> makejsub_zone(in_zone, ratio, decimating); //make sure it was successful if (new_zonejptr != NO QME_ZONE) *out_zonejptr = newjzone ptr; else status = FALSE;} // if error, return no time zone just to be safe if ('status) *out_zonejptr = NO TIME_ZONE; return status;} II set_vύtuaIJo // Called after blocks have been connected, this function detects any // virtual blocks and sets the wires connected to them as vύtual storage. // It calls itself recursively for all children. // Returns non-zero if error. int instance::set_vύrtualJoO{ int i; hier jblock*hier ptr; int status = 0; expr* exprjptr; string* path; instance*wirejnst; int wire; instance*pathjnst; instance*symbol_mst; // save pointer to our prototype as a hier block poύiter, if we need it hierjptr = (hier block*) prototypejptir; // save current block context and set instance info in block push_context(); if (prototype jptr->isjblock_vrr alJo()) ! // block is vύtual, so get translation for "connect", which is the // path for the true location of the virtual storage string connect_name(CONNECT); if (exprjptr = prototypejptr->translate_tojparam_val(&connect_name)) { // translated name, so see if it results in a string if (exprjptr->eval_to_symbol(&path)) { // now have acmal storage name as path from somewhere above // get translation of this path, which will supply the // instance for the top of the path if (prototypejptr->translate ^ithJnstances(path, &path_mst, &symbolJnst)) { // set the block for the instance at the top of the // path as indivisible, since virtual FO must be in // same zone and segment as its physical location pathJnst->prototype()->setjasJndivisible(); for (i=0; i<prototypejptr->io_table_size(); i++) { if (!get_wireJor_io(i, 0, &w ejnst, &wire)) { outj3iror("INS905", cerr, TRUE); cerr « "INTERNAL ERROR ~ No wire" « " in set_vrrtualJo.\n"; status = 1; break; } else { // set storage as vύtual in prototype wireJnst->prototype()-> set_vύtual_storage(wire, path, path Jnst); } } M-241 else { // no translation for path from here out_error('TNS026", cerr, TRUE); cerr « "Virtual FO location '" « *path « '" doesn't make sense hereΛn"; status = 1; } else { out_error("TNS027", cerr, TRUE); cerr « "Vύtual connection parameter is not a string.Vn"; status = 1; } } else { out_error('TNS028", cerr, TRUE); cerr « "Can't find vύtual connection parameter with the" « " required name of "' « CONNECT «"'Λn"; status = 1; }} if (.status)! // call ourself for all our children for (i=0; i<childJnstances.sizeO; i++) { status = child Jnstances[i]->set_virtualJoO; if (status) break; }} // restore previous block context pop_context(); return status; } II set pseudo sampledjnit M-242 // Called after blocks have been connected, this function looks for any // pseudo-sampled outputs, which have initialization values, and // sets these init values for the wires they connect to. // It calls itself recursively for all children. // Returns non-zero if error. int instance: :setjpseudo_sampled Jnit() { int i; hierjblock*hierjptr; int status = 0; expr* exprjptr; instance*wrre_ύιst; int wire; string* storage_name; string* pathjstring; instance*path_ύιst; // save pointer to our prototype as a hier block pointer, if we need it hier jptr = (hierjblock*) prototypejptr; // save current block context and set instance info in block push_context(); for (i=0; i<prototype ptr->io_table_size(); i++)! { // have non-null expression for i/o init value if (!get_wύreJorJo(i, 0, &wύrejnst, &wire)) { out_error("INS906",cerr, TRUE); cerr « "INTERNAL ERROR ~ No wire" « " in setjpseudo_sampledJnit\n"; status = 1; break; } // set the init expression for the connected wire // but make sure we use real, not vύtual wire! // so first get full path for real wire if this wire is vύtual if (wύreJnst->prototype()->is_storage_vύtual(wύ-e)) { pathjstring = wύreJnst->prototype()-> get_vύt_storage _path(wire, &path Jnst) ; -243 // next, get the instance which this path refers to wύre nst = pathJnst->get_ύιstance_of ιame(path string, &storage _name); // finally, look up the wύre name in the instance's prototype wύre_ύιst->prototype()-> look_up_storage_name(storage_name, &wύre); } // set the overide expression wύre Jnst->set_storagejDverrideJnit(wύre, exprjptr); }} if (.status)! // call ourself for all our children for (ϊ=0; i<childjnstances.size0; i++) { sta s = chπdJnstances[i]->set_pseudo sampledJnit(); if (status) break; } } // restore previous block context pop_context(); return status; } iiimimuummuuumimni uuuii umimiuuiuuunuu ff rύιherit_wύre_zone_from jparent // This is a virtual FO block, so ύiherit zone from parent // Get parent zone and set all Fo wires to this zone. // Returns FALSE if error. BOOLEAN instance::ύιherit_wύre zoneJromjparent(){ int j; instance*wύrejnst; int wύre; zone* zonejptr; for ( j=0; j<prototypejptr->io_table_sizeO; j++){ if (!get_wύreJbrJo(j, 0, &wύre_mst, &wire)) { out_error("TNS907", cerr, TRUE); cerr « 'INTERNAL ERROR ~ No wire for input in " << "ύιherit_wύre -;one_from parent\n"; M-244 return FALSE; } zonejptr = parent()->get_zone(0); wύre_rnst->set_zone or_wύre(wύre, zonejptr); } return TRUE;} II set_zone rom Jo // Given a wire Fo number for this instance, look up the zone for the wύre // and it this zone to the instance. // Returns any new zone found, plus updates the count of time zones // for the instance. // Returns FALSE if error. BOOLEAN instance: :set_zone Jrom Jo(int iojiumber, zone** zone ptr ptr, zone* last_zonejptr, int* n_time_zones_ptr){ instance*wirejnst; int wire; zone* zonejptr; block* wύre block; int i; if (!get_wire orJo(io_number, 0, &wύrejnst, &wύre))! outj3rror("TNS908", cerr, TRUE); cerr « "INTERNAL ERROR ~ No wύre for input in " « "set_zone romJo.\n"; return FALSE;} zonejptr = wireJnst->get_zone Jor vvire(wire); if (zonejptr = NO_TTME_ZONE)! // error unless this is phantom block, which need not be in // a zone if ( [prototype jptr->isjphantom()) { out 3rror("INS029", cerr, TRUE); cerr « "Wύre '" « *wύ-e_mst->prototype()->storage_name atJndex(wire) « "' goes to the first block of your design and " « "therefore\n must be connected to a " « "signal source.Xn"; return FALSE; }} -245 if (last_zone ptr = NO_TTME_ZONE) last_zone ptr = zone_ptr; (*nj±ne_zonesjptr)++; ffif ef DEBUG cerr « "adding zone " « *zonejptr->get_zonejιame() « " to instance " « *this->Mer_name_stringO « "Vn"; #endif //record zone in this instance add_zone(zone_ptr);} else if (last_zonejptr != zone_ptr)! (*njlhιe_zonesjptr)++; ffifdef DEBUG cerr « "adding zone " « *zonejptr->get_zone_name() « " to instance " « *this->hier_name_stringO « "\n"; =#endif // record zone in instance add_zone(zone_ptr); // Multiple zones for indivisible block is illegal // unless the zones are really on exactly the same clock // due to a combination of decimation and ύiterpolation. if ( prototype ptr->is_mdivisible_blockO) { if (the_zones->zones_at_same_rate(last_zone ptr, zonejptr)) { // II true, force block to have one zone, taking the most // derivative zone (last added). // This effectively performs zone splitting, placing this // and later blocks into the split zone so that this zone // may be scheduled later than the zone it was split from. // // The one exception is when the block has a feedback input // Check the wires for each input // If wύre is a loop feedback wύre, ignore its zone because this // can be a decύnated/ύiterpolated zone which would otherwise be // set for the block and cause too-late instantiation zone* zone υ Jelete = (/.one*) NULL; for (i=(); i<pn)l()typejptr->io_tiibIe_si/.e(); i++) { if (!prototypejptr->ioJsj3utput(i)) { gc wireJorJo(iojιumber, 0, &wirejnst, &wire); wirejblock = wireJnst->prototype(); if (wirc_block->does_block_haveJoops()) { if (wirejblock->isJoop_wire(wire)) // yes! this is a feedback io, so delete its zone . zonej;o_delete = wuejnst->get_zoneJor_wire(wire); } } } if (zone o_delete == (zone*) NULL) { if (the_zoncs->later ^one(last_zonejptr, zonejptr)) { zonejro_delete = zonejptr; zonejptr = last_zone jptr;// take zone # from last } else zonej.o_delete = last_zone_ptr; } delete £one(zonej:o_delete); } else { // one zone not derived from another and at same rate, // so we must check to make sure one zone is not acmally // a user-specified zone which should be collapsed with // a decimated/interpolated zone if (!the ;ones->try_to_collapse_zones(last_zonejptr, zonejptr)) { out_crror("INS030", cerr, TRUE); cerr « "This instance can't be in both zone '" « *last zonc_ptr->gct_zonejιame() « '" and zone '" M-247 << *zoιιe_pur->gel_zυne_name « Λn ; return FALSE; } } } } // give all our ancestors this zone add_zoneJn_ancestors(zonejptr); // return new zone ptr to user *zonejptrjptr = zonejptr; return TRUE;} II add_zone_connections // This is a rate change instance, so look up the zones for its Fo wires // (wliidi iiui.sf h.-ivr on in o .sri) ;ιικl st'i coniu'clions Ivlwivn I lie zones lo // establish the zone topology. This is required by the scheduler. // Returns FALSE if error. BOOLEAN inslance::add_zone onneciions() ! int ϊ, j; instancc*wirejnst; int wiic; zone* in_zonejptr; zone* out_zonejptr; //scan all inputs- fur (i=0; ϊ<protoiype_plr->io_table_size(); i++) { if (!prototypejptr->ioJsj3utput(i)) { // found an input, so get its zone if (!gct_wireJorJo(i, 0, &wirejnst, &wire)) { out_crror("INS960", cerr, TRUE); cerr « "INTERNAL ERROR ~ No wire for input in ' « "add_zone_connections.\n"; i cl ui ii FΛLSli; } in_zonejptr = wireJnst->gct £one 7or_wire(wire); if (in_zonejplr != N ( )_T1ME_Z0NE) M-248 // .sun .ill outputs loi llns input for (j=0; j<prυtυlype_pu->iυj.ablc_size(); j++) { if (prototypcjplr->ioJs_output(j)) { // set connections between input and output zones if (!gcι_wire orjo(j, 0, &wirejnst, &wire)) { outj3rror("INS961", cerr, TRUE); cerr « "INTERNAL ERROR - No wire for output in ' « "add_zone_connections.\n"; return FALSE; } out_zonejptr = wirejnst->get_zone or_wire(wire); if (υut_zυnc_plr != NOJNMEJZONE && in -onejptr != out zonejptr) { // now have in and out zone ptrs, so set forward // and backward pointers if (!in_zonejptr->next zonejpresent(out_zone_ptr)) in '.onejptr->atld_ncxt_/.one(out_/.onejptr); if ( !oιi '/.oικ'_plr->|)iv.v /.oιιe_pιescnl(iιι_/.()nejplr)) ()ul_ one_ptr->add_pr v_y.one(in_zone_ptr); } } } } return TRUE;} II sctJnstance_zones // Called for a sequenced block which has zone for wires set by // se ire_zoncs, this function sets the zone for all instances. // It calls itself recursively to set the instance zones // for all children. // If our ancestor had just a single lime zone, then pass it in and use it // if no other zone info can be found. // Returns FALSE if error. 59k -249 BOOLEAN instance::setJnstance_zones(zone* parent_zonejptr){ int i, Lseq.j; hier_block*hicr_ptr; BOOLEANstatus = TRUE; zone* zonejptr; zone* last_zonejptr; int n_time_zones; BOOLEAN»ot_a_zoncJo; // save pointer to our prototype as a hier block pointer, if we need it hier jptr = (hierjblock*) prototypejptr; // save current block context and set instance info in block push_context(); // if this is an asm block, verify that we are single time zone // and set zones for outputs n_time_zones = 0; last_zonejptr = zonejptr = NO_TIME_ZONE; // if this is a virtual FO block, set wire zones from parent if (proiotypejptr->is_block_virtualJo()) status = inherit_wire_zoneJrom jparent(); // if this is a rate change block, take this opportunity to set the // zone links to establish zone topology, which the scheduler needs if (status)! if ( prototype jptr->is_rate_change_block()) status = add / .one_connections();} // scan all inputs to get zones if (status)! for (j=( ) ; j<prolotype_ptr->io Jable_size(); j++) { //The zone(s) for an instance is, in general, gotten from // the zone of each input. The exception is a rate change block, // (either downsampler or upsampler), // which is in the same zone as its OUTPUTS. // Thus a decimator runs at the lower of the two rates at // a rate boundary, and an interpolator runs at the higher. got_a_zoneJo = FALSE; if ( prototype_plr->is jrate_change jblock()) { M-250 if (prototypejptr->ioJsjrutput(j)) got_a_zoneJo = TRUE; } else if (!prototypejptr->ioJs_output(j)) gotja_zoneJo = TRUE; if (got_a_zoneJo) { if (!(status = &zonejplr, last_zone ptr, &njime_zones))) break; else . . last_zonejptr = zonejptr; ) } } if (status)! if (n_time_zones == 0 && how_many_zones() == 0) { // no zone, so see if parent passed us a zone if (parent_zonejptr != NO TTME.ZONE) { n_time_zones = 1; zonejptr = parent ionejptr; #ifdef DEBUG cerr « "adding zone " « *zonejptr->get_zυne_name() « " from parent to instance " « *this->hier_name_string() « "\n"; #endif // record zone in instance add ionc(zoncjptr); } } // call ourself for all our children, passing them the time zone // if there is just a single one if (n_time_zones != 1) zonejptr = NO_TIME_ZONE; for (i=0; i<childjnstances.size(); i++) { // use sequenced order i_seq = sequence[i]; status = child Jnstances[i_seq]->setJnstance_zones(zone jptr); if (istatus) break; } // make sure this instance has a zone if (status) { if (how_many_zones() = 0 && should jpartition_designO) { Qut_error("INS033", cerr, TRUE); cerr « "Could not determine time zone for this instanceΛn"; status = FALSE; } } } // restore previous block context pop_context(); return status; } iiiiiifiiiiiiiiiiiiiiiiiiifiiiifiiiiiifiiiiiiiiiiiiriiiiiiirrifiiiiiifiiiiiiii II validjparentjo //Returns TRUE if this instance has valid parent IO, that is, if our // parent exists and has had its child connections set. BOOLEANinstance::vaIϊdjparentJo(){ BOOLEANstatus = FALSE; if (parentjnslance) { if (parentJnstance->are_conneclions_set()) status = TRUE;} return status;} II add_zone // Add a zone to the zone list, provided its not already there. void instance-add 2one(zone* zonejptr)! int i; if ((i = zonejptrs.find(zonejptr)) >=0) return; M-252 i = zonejptrs.sizeO; zoncjptrsfi] = zonejptr; segjiumber = UNKNOWN SEGMENT.) II dclete_zone // Delete a zone from the zone list. void instance::delete ionc(zone* zonejptr)! int i; if ((i = zonejptrs.find(zonejptr)) < 0) return; zonejptrs.remove(i); } II change done // Change all references to one zone to another zone. // Performed recursively for all children. void instance: :change ;one(zone* old_zone, zone* new_zone){ int i; // change our zone pointer if (is ionejpresent(old_zone)){ delete ione(old_zone); add ionc(ncw_zone); #ifdef DEBUG cciT « "changing zone " « *old ione->get_zone_name() « " lo " « *new onc->gct /.onc_name() « " in instance " « *this->hier_name_string() « "\n"; #endif} // change zones for our wires for (i=0; i<zonc_for 'ire.size(); i++){ if (zone Jor_wire[i] == old ione) zone or Λ'ireti] = new_zone;} // recursively call children for (i=0; i<childjnstances.size(); i++) child Jnstances[i]->change_zonc(old_zone, new_zone); ; // add_zoneJn ancestors // Add a zone in ancestor (just go up lo user top). void instance::add_zoneJn_anccstors(zone* zonejptr)! if(!is_topJevel()){ ρarentjnstance->add_zone(zonejpur); parentjnstance->add_zonejn_anceslors(zonejptr); } } II ϊs_zone or_subzonc_present // Returns TRUE if the given zone is present in our zone. // Calls the zone class to. u§e original zones in case any of zones are // derived zones. BOOLEANinstance::is_zonej3r_subzonejpresent(zone* z) { int i; zone*orig; if (z != (zone*) NULL)! orig = z->original_zone(); for (i=0; i<zonejptrs.sizeO; i++) { if (orig = zonejptrs[i]->original_zone()) return TRUE; } } return FALSE;} II opcrator«= // Output the instance, wiih its prototype name, instance name, parameters. // and FO, exactly as if it were a line in the parent block .sdl file. osiream& operator«=(oslream& s, instance& inst) { int i; string* name; instance*whichjnst; int index; // output prototype name and instance name s « *instprototype_name() « " " « instinstancejiame « " "; // if overrides hash table present, it is parameters for instance if (instoverrides != (exprjiash*) NULL) s « "{" « *inst.overrides « "} "; // output I/O for instance s « "("; for (i=0; i<inst.prototypejptr->io_table_size(); i++){ // get name string for this index instget_wireJorJo(i, instgetjphantomjojevel(i), &whichjnst, &index); name = whichJnst->prototypejpLr->storagejιame_atJndex(index); // output FO name separated from any previous name in list if (i>0) s « s « *name; } s « ");\n"; return s; } II outjnstancejblock // Output this instance as a block. void instance: :out Jnstance jblock(ostream& s){ linebreaker*ljbreak; char storage _type; // only output if hierarchical block, because this function need // only be used for outpulting instances which have had phantom blocks // added to them if (prototype()->is Jeaf _block()) return; // make a linebreaker object to break lines neatly Ijbreak = new linebreaker(" ", 80, 0); // output header for this block // first output block name l_break->in() « "manblock " « *prototype_name(); // output parameters definitions lor block 255 6θO I_break->in() «" {"; for (i=0; i<prototypejptr->get_njparams(); i++)! if (i > 0) 1 _break->in() « ", "; name = prototypejptr->param_name_atJndex(i); l_break->in() « *name; exprjptr = prototypejptr->param_exprjatJndex(i); // if parameter value present, then output it if (expr_ρtr != (expr*) NULL) ljbreak->in() « "=" « *exprjptr;} l_break->in() « "}■("; // output the I/O declaration for (i=0; i<proιotypcjpιr->io able_size(); i++){ // get name siring for this index name = prototypejptr->iojιame_atJndex(i); if(i > 0) l_break->in() « "; "; if (prototypcjptr->ϊoJsj3ulput(i)) 1 _break->in() « "output "; else l_break->in() « "input"; ljbreak->in() « *name; // if size is greater than one, declare it as a vector expijilt - pιuLυlypcjpti " -^iυjmUy_sr/χ(i); if (expr_ptr != (expr*) NULL) { size = (int) cxρrjptr->int_value(&dummyl, &dummy2); if (size > 1) l_brcak->in() « "[" « size « "]"; } } l_break->in() « ")\n"; // send the line break output to the output stream s « ljbreak->out(); delete ljbreak; // now output the remaining parameters, which are actually symbols for (i=prototypcjptr->get_njparams(); i<ρrototypejptr->param_table_sizeO; i++){ name = proiotype_ptr->param_namc atJndex(i); s « "symbol " « *name; exprjptr = prolotypc_plr->param_expr_atjndex(i); // if paiaincler value piesenl, llien output it if (exprjptr != (expr*) NULL) s « "=" « *exprjptr; s « ";\n";} // output the wires and any initial values for (i=0; i<prototypejptr->storagej:able_sizeO; i++){ // get name string for this index name = prototypejptr->storage_name_atJndex(i); s « "wire "; // output storage type storage jype = prototype_ptr->get 5toragej.ype(i); switch (storage _type) { case 1 : s « "fixed "; break; case : s « "integer "; break; case 'h': s « "hex "; break; } s « *namc; // if size is greater than one, declare it as a vector exprjptr = prototypejptr->storage_entry_size(i); if (exprjptr != (expr*) NULL) { size = (int) cxprjptr->int_value(&dummyl , &dummy2); if (size > 1) s « "I" « size « "]"; } exprjptr = prototypejplr->get_storagejnit(i); // if storage init value present, then output it ir fi'xpijpir ! ( xpι + ) NUL ) s « "=" « *exprjptr; s « ";\n";} // output start of block body text s « "begin\n"; // call output operator for all our children for (i=0; i<childjnstances.size(); i++)[ // use sequenced order i_seq = sequencep]; // check if label needs to be output before this child instance if (prototype _ptr->label_table_size()) { // check if any label refers to this child index // Label sequence has child index. for (int j=0; j<prototypejptr->label_table_size(); j++) { if (proιotype ptr->Iabel_seq_atJndex(j) = i_seq) { name = prolυtypejptr->label_name at_mdex(j); s « *name « ":\n"; } ' } } // make a lincbreaker object to break lines neatly ljbrcak = new lincbreakcr(" ", 80, 4); IJιιcak->in() «- * Nd_ϊnsUιπc sLi_scqJ; s « " " « l_break->out(); delete ljbreak;} // output end of block body text s « "end\n\n";} II out_variantjblocks // Output all blocks in the hierarchy which are variants. // Any block which has a variant child must itself become a variant void instance::out_variantjblocks(ostream& s) { int i; int i_scq; // save current block context and set instance info in block pιιsiι_coιιiexlQ; // call function for all our children -258 for (i=0; i<childjnstances.size(); i++){ // use sequenced order i_scq = sυqucncc[i]; child Jnstances[i_scq]->out_variant_blocks(s);} // if this block has phantoms, it is a variant block if (hasjphantomsO II is_variant()){ // make us a variant make ariantO; // since we are variant, set our parent as a variant if (parentO != (instance*) NULL) parcnt()->make_variant(); // and outputourself outjnstancejblock(s); } pop_coniexl(); } II make_varianl // Make this instance a variant of the prototype instance, provided it // is not already a variant. void instance: :make_variant(){ if (finstjs /ariant)! variantjiumber = prototype()->new ariant_number(); inst_is_variaιιl - TRUL; } } /////////////////////////////////////////////////////////////////////////////// // prototypejiame // Returns the name of the block prototype, including any variant number // to distinguish the block. string* instance::prototype_name(){ string* s; if (instjs_variant){ s = new stringC"'); *s = *s + *prototyρe()->get_blockjιame() + " " + int_to j;_string(variant jiumber); } else s = prototypeO-^ϋct block namcQ; return s; } 6θk M-259 //instance::addjphantom_storage_name // Adds a new phantom location or locations referred to by the given name. // Returns as an argumcm the storage index (next sequential) // which was allocated. // An expression for the storage size is also passed, the value of // which may not yet be known. If the size expression is NULL, set a size //of l. // Returns FALSE if the name was already present // Calls the protected function: // instancejphantoms::addjphantom_storagejιame_only to do most of the wα fc // except for setting the zone info for the new phantom storage. // NOTE: No initial value other than 0 is possible for phantom storage. BOOLEANϊnstancc::addjphanlom_storage_name(string* name, expr* size, int* index, char type)! BOOLEANrcstilt; if (result = add_phantom_sioragc_namc_only(name, size, index, type)) setjphanlomJink_and_zone(*iπdex, NO_PHANTOM_LINK, NO_TTME_ZONE); return result;} // instance::setjphantomJink_and_zone // Create a phantom wire link from a wire to its phantom, and set // the zone for the phantom. void instance-set jphantomJϊnk_and_zone(int i, int phantom J, zone* timezone) { set_phantom_wireJink(i, phantomj); // set zone only if phantom wire is real (it could be NOJPHANTOMJ1JNK) if (phantomj >=0) zone_for_wire[phantomJ] = timezone;} II instance-insertjpartϊtioned // Insert a child into our partitioned child sequence. void inslance::inscrtjpartiιioned(int pos, int child jιumber){ part_scquence.inserl(pos); part sequencefpos] = child jiumber;} II instance-setjpartitioncd // Record fact that this instance in partitioned in the given timezone. M-260 void instance::seLpartitiυιιcd(zυne* zonejptr) { int i; // make sure zone is present and get index (add if not present) if ((i = zone jpu-s.find(zonc ptr)) < 0) { addjzone(zonejptr); i = zonejptrs.find(zonejptr);} // set partitioned flag for this zone index partitioned[i] = TRUE;} II instance::append_partitioned // Append the given child io he partitioned sequence of children. // Do so only if not already in the list. void instance::appendjpartitioned(int i){ if (part_sequence.find(i) < 0) part_sequence[part_sequence.size()] = i;} II instance::needsjpartitioning // See if instance needs partitioning. It does if zone is present for // instance and it has not yet been partitioned. BOOLHΛN iιιstaιιce::ιιccds_pariiιi()iιiιι (z()iιc* zonejptr) { int i; // make sure zone is present and get index if ((i = zonejptrs.find(zonejptr)) < 0) return FALSE; return (!partitioned[i]);} II makejnanual_sequence // Create a manual block sequenc, bypassing partitioning, by copying // the child sequence to the partitioned sequence. BOOLEAN instance-make jnanual_sequence() { int i; int i_seq; BOOLEAN status = TRUE; // save current block context and set instance info in block push_context(); 6θβ M-261 // call function for all our children for (1=0; i<childjnstances.size(); i++){ // use sequenced order, and make next in partitioned sequence ϊ_seq = sequencefi]; append jpartitioned(i_seq) ; status = child Jnstances[i_seq]->make_manual_sequence();} pop_context(); return status;} //instance_phantoms::instancejphantoms // Constructor. instancejphantoms::instaπcejphantoms(block* proto): phantomJabel_seq(SZ), phantom Jabel_offset(SZ) { proιotype_ptr = proto; phantom J Jndex = n jphantom_storJocs = 0; instjias jphantoms = FALSE; //initialize phantom links to null, and zones to none for (int i=0; i<proto->storage_table_size(); i++) ρhaιιlom_wireJink|i| = NO.PI IΛNTOMJ NK;} // instancejphantoms::~instancejphantoms // Destructor. instancejphantoms::~instancejphanιoms() { } //instancejphanιoms::phantom_storage_offsetjαtJndex // Return the phantom storage offset in the storage table at the given index int instancejphanloms::phantom storage jffset_atjndex(int index) { int alloc; // make sure lo add allocation of storage table alloc = prototype ptr->non phantom illoc_stora e_ size(); alloc += phantom_storage_tabIc.ϊndex_toJocation(index); return alloc;} M-262 // inslancejplιaιiU)ms::look ιpjphaιιloιιι Uoragc jiame // Find the given name in the phantom storage table. // Returns TRUE if found, along with the full storage index. BOOLEANinstance_phantoms::look_upjphantom_storage_name(string* s, int* index) { ' {■ expr*dummy_size; int ph Jndex; if (phantom_storage_table.find(*s, &phjndex, &dummy_size)){ *index = ph Jndex + prototypejptr->nonjphantom_storage_tabJejazeO; return TRUE;} else return FALSE;}. . /////////////////////////////////////////////////////////////////////////////// // instance jphantoms: φhantom Jabel jιame_to Jndex // Gel i index for the given phantom label name. // Returns FALSE if name not present BOOLEANinstanccjphantoms::phantomJabel_namc_toJndex(string* name, int* index){ expr* size; return phantom Jabel_table.find(*name, index, &size);} // inslanccjphantoms::add_phanlom Jabel jiame // Adds a new phantom label name along with its seq #. // Returns FALSE if the name and a seq # were already present. BOOLEANinstancejphantoms::addjphaniom Jabel jιame(string* name, int address)! int index; expr*old_size; // see if name already present if (!phantomJabel_table.find(*name, &index, &old_size)){ // name not present, so allocate a new one and get its index index = gctjphantom Jabel Jndex(name);} // store the label seq # in a table, provided not already there if (!phantomJabel_seq[index] II phantom Jabel _seq[index] == NO_ADDRESS){ phaiilomjabel -s d index I - address; return TRUE;} else return FALSE; } M-263 // instancejphantoms::add_phantom_storage_name_only // Adds a new phantom location or locations referred to by the given name. // Returns as an argument the storage index (next sequential) // which was allocated. // An expression for the storage size is also passed, the value of // which may not yet be known. If the size expression is NULL, set a size //of l. // Returns FALSE if the name was already present // Does NOT fill in zone information, and therefore is protected // so that it should just be called by insiance::addjphantom_storage_name // which has access to zone functions. // NOTE: No initial value other than 0 is possible for phantom storage. iiuiiiiinHUimiimiimiumimiuiiumiHuuumttummiuiH BOϋLEANinstance_phantoms::addjphantom_storage_namc_only(string* name,. expr* size, int* index, char type) { BOOLEANresult; int i; int phjndcx; result = phantom_storage_tablc.allocatc(*name, size, &ph Jndex); if (result)! phanlom_slorage_lable.set_size(ph Jndex, size) ; phantom_storage_types[ph_index] = type; // initialize a phantom wire link for this storage location // non-phantom storage is first // get real index number to use, which is offset by stor. table size i = phjndex + prototypejptr->nonjphantomj5torage_table_size0; // give copy to caller *index =i;} return result;} iiiiiiiiiiiiiifiiiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiriiriiiiimiimmiiiiiiii // instancejphantoms::getjphantomJabel Jndex // Gets an index (not an address!) for a phantom label name. // If the name was not encountered before, a new, unique index is allocated // for it M/ /fm // ///ι /m/m ///wιifWM///ww/w int instancejphantoms-gctjphantom Jabcljndex(string* name) { int index; expr* oId_size; // see if name already present if (phantom Jabel _table.find(*name, &index, &old_size)) return index; else{ // store name in hash table with new index phantom Jabel_table.allocate(*name, NULL, &phantomJ ndex); phantom Jabel_seqfphantomJJndcx] = NO_ADDRESS; return phantom J Jndex++; } } // instance_phantoms::gct_phantom_wireJevel // For the given storage index, count the current number of phantom wire // levels and return it. int instanccjphantυms::gctjphanlυm Λ'ireJevel(inl index)! int level; getJast_phantom(indcx, &level); return level;} II instance jphantoms::gciJastjphantom // For the given storage index, get the index of the last phantom, and // return it, along with the phantom level. int instance _phantoms::get Jast _phantom(int index, int* leveljptr){ int level = 0; int next; //jump along phantom wire links until end, counting levels while ((next = phantom_wireJink[index]) != NO_PHANTOM_LTNK){ if (next == index) { out_err_header("INS901"); cerr « "INTERNAL ERROR - phantom links are corrapte .\n"; exit(l); } index = next; level++; } * level jptr = level; return index;} -265 II instance jphantoms-getjphantom // For the given storage index, get the phantom for the given level. int instance _phantoms::get_phantom (int index, int level)! int i, next; i = 0; while ((next = phantom _wirejink[index]) != NO ?HANTOM_LINK){ if (next == index) { outj3rr_header("TNS902"); cerr « "INTERNAL ERROR ~ phantom links are corrapted!\n M ; exit(l); ) if (i++ = level) break; else index = next;} return index;} II instance _phantom.s::rcatltιclιjphantomJahels // Remove any phantom labels from their connection to the "at Jndex" // instance and connect them to the instance at "newjndex". // Used if we are inserting an instance at a particular place and wish a //label to be assocatiated with the new instance. void instancejphantoms-reattachjphantom Jabelsrint at Jndex, int newjndex) { for (int i=0; phantom Jabel _seq.size(); i++){ if (phantom Jabel _seq[i] = at Jndex) phantom Jabel_seq[i] = newjndex; }} // instance.hxx // block instance class //T. Montlick // 11/30/89 /* source code control: @(#)instance.hxxl.56 10/7/91 */ #define INSTANCE DEP #ifndef STRING jDEF #ύιclude "strin »ge>..hxx" M-266 #cndif #ifndcf UΗLITY_DEF #include "utility.hxx" #endif #ifndef INTRFACE _DEF #include "intrface.hxx" #endif #ifndcf EXPR_DEF #include "expr.hxx" #endif #ifndef EXPR JIASH OEF #include "exprhash.hxx". . #endif #ifndcf INT_ARRAY_DEF #include "int_arr.hxx" #endif #ifndef INP_LIST_DEF #include "inp Jisthxx" #endif #ifndcf ALLOC_TABLE_DEF #include "alloctab.hxx" #endif #ifndef INST_ARRAY_DEF #include "instjirr.hxx" #endif #ifndef BLOCK jDEF #include "blockhxx" #cndif #ifndef BLOCK_REF_DEF #include "blck_ref.hxx" #endif #ifndef BLOCK_REF_ARRAY_DEF #include "bref irr.hxx" #endif #ifndel ' ZONE_DEF #include "zone.hxx" #cndif #ifndef ZONE_ARRAYJDEF #include "zone arr.hxx" -267 #endϊf • #ifdef SZ #undefSZ #endϊf #defineSZ 4 // default array and hash table size #defmeHASH_SZ10 // special index in phantom _wirejink table indicating no more links #dcfinc NO_PHANTOM_LINK-l // special zone ptr in zone_for_wire table indicating no zone set #deline NO TIME_ZONE(zone*) NULL // illegal duration signifying unknown value #define UNKNOWN jOURATION-1 // unknown value for segment #define UNKNOWN_SEGMENT-l // initial value for instructionjbase #define NO_INSTR_BASE-l // special parameter name used for virtual I/O block #define CONNECT" connect" // special parameter name used for subroutine control //dcliiieSU RJ 1 ARAM_S ' rR"%siil)r * // special parameter name used to declare exported symbols #defineEXPORTSj?ARAM_STR"%exports" #defineUSE_SUBR_CONDITION>0 #defineDONTJJSE_SUBR_COND==0 // character to tag a micro interface symbol in symbol file #define MICRO HAR'm' class block; class zone; // base class for instance which handles all varieties of phantoms class instance jphantoms! block* prototypcjptr; // our prototype int njphantom Jnst Joes;// phantom only int njphantom_storJocs;// phantoms only int plιaniom_dιιralion;// phantom duration for this block alloc_tablephantom _storage_table;// phantom storage, added to block storage expr αrrayphantom storagejnit^/ init vals for phantom storage ϊnt_arrayphantom_sioragejypes;// types for phantom storage alloc_tablephantom Jabel_table;// phantom label name to index int phantom J Jndex; / next index # for label • M-268 6 l3 int_arrayρhantom Jabel_seq;// index to label seq # int_arrayphantom Jabeljaffset;// index to label offset from start int_arrayphantom_wireJink;// for each wire, index of next phantom int_arrayphantom Jo Jevel;// for each I/O, phantom wire level BOOLEANinstJiasjphantoms;// TRUE if instance has had phantom&added protected: BOOLEANaddjphantom_storagc_name_only(string* name, expr* size, int* index, char type); public: instanccjphantoms(block* proto); ~iιιslaιια:_pl);ιπlom.s(); void set_n_phantom_storj " ocs(int i) { njphantom_storJocs = i; } void add ji jphantom_storJocs(int i) { n jphantom _storJocs += i; } int gct_njphantom_stor_locs(){ return n jphantom stor ocs; } void set_njphantomJnstrJocs(int i){ n jphantom Jnstr Joes = i; } void addji jphantom JnstrJocs(int i){ n jphantom Jnstr Joes += i; } int gctji jphantom Jnstr Jocs(){ return n jphantom Jnstr Joes; } void setjphantom_duration(int i){ phantomjJuration = i; } void addjphantom_duralion(int i){ phantom_duration += i; } int getjphantom_duration(){ return phantomj uration; } int phantom_storage_table_size() { return phantomj?torage_table.size(); } string* phantom 5torage_name_atJndex(int index) { return phantom_storagc_table.name_at_index(index); } int phantom_storage_offset_atJndex(int index); expr* getjphantom_slorageJnit(inl index) { return phantom_storagejnit[index]; } char getjphantom_storage_type(int index) { return (char) phantom_storage_types[index]; } expr* phantom_storage_cntry_size(int index) { return phantom_storage_tablc.gct_size(index); } B ( )() LEANIookjιpjphaιιiom_siorage_name(slring* s, int* index); BOOLEANphanlυmJabei jιame_toJndex(stιing* name, int* index); BOOLEANaddjphantomJabel_name(string* name, int address); int getjphantomJabelJndex(string* name); int phantomJabel able_size() { return phantomJabcl_table.sizc(); } string* phantom Jabeljιame_atjndex(int index) { return phantom Jabel_table.name ιtJLndex(index); } M-269 6 lZ int phantomjabel seq_atjndex(int index) { return phantom Jabel _seq[index]; \ int phantom Jabel_offset αtJndex(int index) { return phantom JabeLoffset[index]; } void setjphantom Jabe offset(int index, int offset) { phantom Jabeljrjffsetftndex] = offset; } int getjphantom_wireJevel(int index); int get Jast phantom(int index, int* level jptr); int getjpIιantom(int index, int level); void setjphantom Jo Jevel(int i, int j) { phanlomJoJcveI|i] = j; } int get_phantomJoJeveI(inti){ return phantom Jo Jevel[i]; } void setjphantom vircjinkfjnl i, int j) { phantom _wirejink[i] = j; } void setJιas_phantoms() { instjiasjphanioms = TRUE; } return instjias phantoms; } void reattachjphantomJabels(int at Jndex, int newjndex); }; // base class of instance class which maintains info about an instance which is //on a rate change boundary (decimation or interpolation) class instance_rate_change{ BOOLEANdecimation; // TRUE if decimation, FALSE if interp. expr* change jratio; // interpolation or decimation ratio BOOLEANnewj-atejblock; // block follows a rate change block public: instance_rate_change() ; -instance jrate_change() ; void set_decimating(expr* ratio); void setJnterpolating(cxpr* ratio); BOOLEANis jate_chaιιge_bl()ck() { return newj-atejbloek; } BOOLEANis lecimatingO ! return (new rate block && decimation); } BOOLEANisJnterpolatingO { return (newjratejblock && Idecimation); } expr*get_change_ratio() ! return change ratio; } void set_as_new ratejblockO M-270 { new_rate_block = TRUE; } BOOLEANis_new_rate_block() { return newj-atejblock; } ) ; // class which defines a block instance class instance : public instance jphantoms, public instance_rate_change{ int njnstructjocs;// sum of instructions including children int njnitjnstrjocs;// init time only int n_stυrageJocs;// sum of storage Iocs including children inl our jι_slorage Joes;// just our own storage Iocs, no kids inl iiisli'iiclionjiase;// starling address of instructions int siojagejbase;// starting address of storage int duration; // total duration for this block int initjiuration;// init duration for this block block* prototype jptr; // our prototype int • linejium; // line # which called us in prototype instance*parent nstance;// pointer to our parent instance int ourjndex; // our index in parent instjirraychild Jnstances;// pointers to our child instances bref_arraychild_refs; // pointers to our child block references string instance jiame; // our name int ιrraystoragc_sizcs;// evaluation of sizes in storage J.able int_arrayio_sizes; // evaluation of sizes in io_table expr_hash*overrides; // override symbols from parent int irraywircj ' n jparent;// wire indices in parent for our I/O intjirraywirej'eallyjo;// parent wire index is really I/O index insljirraybypassjparent;// bypass parent for I/O, but go to inst. int_arraysample_rates;// index of rate or rates for instance BOOLEANis_serial jport; // TRUE if block is a serial port BOOLEANi serial jmtput;// TRUE if serial output zonejιιτayzone_foι jwire;// time zone for wires, real and phantom zoncjirray/.onejplrs; // which limezones instance is in intjirraypartitioned;// partitioned Hags for timezones int seg jiumber;// segment # for timezone, if known intjirraysequence; // child sequence, if hierarchical block int_arraypart_sequcncc;// child sequence after partitioning BOOLEANsequenced; // TRUE of sequenced in parent BOOLEANconnections_set;// TRUE if child connections have been made BOOLEANinit; // TRUE if only instance is an init block M-271 BOOLEANinstJs_variant;//TRUE if variant from prototype int variant_number;// number distinguishing from other variants expr_arrayoverride_storageJnit;//init vals which override prototype BOOLEANoverridesjproccssed;// TRUE if override symbols processed BOOLEANlabels_output; // TRUE if labels output once int_arraystoragc_addrcsses;// evaluated actual addresses for our stor. public: instaπce(block* proto, string& instjiame, instance* parent, int index); -instanceO; block* prololypcQ ( return prolotypejptr; ) inslance*parenl() { return paientjnstance; } void push_conteχt(); void pop_context(); instance*build_tree();// build the instance tree int process_subroutines(); BOOLEANchcckJf_subr_caIl(block* childjblock, instance* chiid nst); int process_exports(); int evaluate rjverridesO; void set_overrides(exprJιash* h) { if (overrides != (exprjiash*) NULL) delete overrides; overrides = h; } expr_hash*geι_overrides() ! return overrides; } void setjrjverrides jprocessedO { overridesjprocessed = TRUE; } BOOLEANarc_overridesjproccsscd() { return overridesjprocessed; } int compute_contents(); int gcl_nJnstπιclJocs(){ return njnstructjocs; } int getjiJnitJnslrJocsO! return njnit Jnstr Joes; } int getjι_storageJocs(){ return n_storage Joes; } inl geljJurationO! return duration; } inl gelJnit_duralion(){ return initjiuration; } inl check_vcrϊfy_expressions(); int check_asm_block(); int compute_storage_sizes(); BOOLEANcompute_code Jocations(int& nextjnstrjbase, zone* timezone); void do_compute_codeJocations(int& nextjnstrjbase, zone* timezone); void compute jaiajocationsønt next store Jbase); int computeJo_sizes(); int connect_chiid_port(string*, int, instance*, block*, int_array&, 2 ' intjιrray&); int wire_connections(); void makejprototyρe_connections(); int add_topJevelJnputs(); int get_addr_of_storage(int index); BOOLEANget_wire JorJo(int index, int phantomjevel, instance** whichjnstance, int* which_wire); BOOLEANgetJo Jor vire(instance* whichjnstance, int which_wire, int* iojndex); BOOLEAN find_wirejιame(string* name, int* which_wire, instance** whiclijnst); int get iddr jf Jo(int index); int getjιddr_of Jabel(int index); inl getjnstructionjbaseO { return instruction jbase; } int generate_code(ostream& code stream, zone* timezone); int do jenerate_code(ostream& code_stream, zone* timezone); int generate_data(ostream& data_stream); int output_storage_symbols(ostream& out); int outputJo_symbols(ostrcam& out); int output Jabels(osiream& out, zone* timezone); int do )utputJabels(ostrcam& out, zone* timezone); int output_symbols(ostream& out); BOOLEANtranslates_to_storage(string* name, instance** symboljnst string** sloragejiame); string* hier_name string(); instance*geljnslancej)f_name(string* name, string** remainder); void out_error(char* msg_code, ostream& c, BOOLEAN parent); void out_warning(char* msg_code, ostream& e, BOOLEAN parent); friend ostream& operalor«(ostream& s, instance& i); BOOLEAN is opJevelO; inl n_samplej-ates(){ return sample_rates.size(); } void add_samplcj * ate(int rate) { if (samplejrates.find(rate) < 0) sample j-ates[samρlej-ates.size()] = rate; } int get_sampiej-ate(int i) { return sample_rates[i]; } int gct_n_childrcn(){ return child Jnstances.size(); } instancc*get_child(int i){ return child Jnstances[i]; } int get_sequence(int i) { return sequencc[i]; } void add _new_child(instance* inst) { child Jnslanccs[childjnstanccs.size()] = inst; } int copyJn_sequence(); void set_zoneJor_wire(int index, zone* timezone); zone* get_zone or_wire(int index) ! return zone or vireftndex]; } BOOLEANaddjphantom_storage_name(string* name, expr* size, int* mdex, char type); void sc phantomJink ιnd_zυnc(int i, int j, zone* timezone); BOOLEAN set_wire_zones(); BOOLEANsetjιew_output_zone(zone* in zone, zone** out_zone_ptr); BOOLEANinheril_wirc_zone_fromjparenl(); BOOLEANset_zone romJo(int io jiumber, zone** zonejptr, zone* last_zone, int* n_ϋme_zonesjptr); BOOLEANadd_zone_connecϋons(); BOOLEAN setJnstance_zones(zone* parent_zone); void setjo_to_wireJnjparenl(int i, intj) ! wirejnjparenlp] =j; } int gct A'ircJnjparcnt(ϊnt i) { return wircjn_parent[i]; } void set_bypassjparent(int i, instance* inst) { bypassjparent[i] = inst; } void appendjpartitioned(inti); int getjpartitioned_size(){ return part_sequence.size(); } int getjpart_sequence(inti)[ return part_sequence[i]; } void iπsertjpartilioned(iπt i, inl j); int get_io_sizcs_size() { return io_sizes.size(); } inl gel_seqιιeιιce_si/.c() ( r turn scqucncc.sizcO; } BOOLEANare_connections_set() { return connections_set; } BOOLEANvalϊdjparentJoO; void setj ' nitO { init = TRUE; } BOOLEANis JnitO; BOOLEANsingle_zoned(){ return (zonejptrs.sizeO = 1);} int howjnany_zones(){ return zone jptrs.sizc(); } zone* get_zone(int i) M-274 { return zonejptrs[i]; } inl gel_seg_numbcr() { return seg_number; } void add done(zone* zonejptr); void delcte_zonc(zone* zonejptr); void change_zone(zone* old_zone, zone* new_zone); void add zonejn_ancestors(zone* zonejptr); BOOLEANis ne present(zonc* z) { return (zonejplrs.lind(z) >= 0); } BOOLEANis / .one_or_subzonejprcsent(zonc* z); void sct_seg_number(int i) . . { segjiumber = i; } friend ostream& operator«=(ostream& s, instance& inst); void out nstance_block(ostream& s); void make_variant(); BOOLEANis_variant(){ return instjs_variant; } int whaLvarianijiumberO { return variantjiumber; } string* prolotypejiameO; void out_variantjblocks(ostream& s); int set_virtualJo(); int setjpseudo_sampled Jnit(); void sct_sequenced(){ sequenced = TRUE; } BOOLEANis_scquenced(){ return sequenced; } void sct_storagej3verrideJniι(int i, expr* exprjptr) { override_storageJniι[i] = exprjptr; } expr* get_storage j3verridejnit(int i) { return override_storageJnit[i]; } void setjpartitioned(zone* zonejptr); llO( )U{ΛNιι ls_paι lilioιιiιιg(/.nιιe + zone ili ); BOOLEANmakejnanual_sequence(); void setjabclsj3utput(){ labelsjDutput = TRUE; } BOOLEANareJabcls_output(){ return labels_output; } }; // inljαrr.cxx // derived class for integer array // Terry Montlick // 10/10/89 /* source code control: */ M-275 static char SccsID[] = "@(#)int_arr.cxxl.56 10/7/91"; #iπciude "int αrr.hxx" int 4rray::int_array() 0 intjαrray::int_array(int i) { } //int_arr.hxx // header for derived int array classes //T. Montlick // 10/10/89 /* source code control: @(#)int_arr.hxxl.56 10/7/91 */ #define INT_ARRAYjDEF . #ifndefARRAY_DEF #include "array.hxx" #endif class int_array : public array! public: ϊnt_array(); int_aπray(inti); void opcrator=(int_array& a)! array: :operator=((array&) a); } int& operatorQ(int i) { return (int&) array::opcrator[] (i); } int find(int ptr) { return array:: find( (elem) ptr); } void aρpend(int ptr)! array::append((elem) ptr); } int_array&operator+(int_array& a) { return (int_array&) array::operator+((array&) a); } ϊnt_array&operator+=(int_array& a) !a = *ύbis + a; return *this; } }; // mtjiash.cxx // functions for integer hash table class // T. Monllick // /12/89 /* source code control: */ static char SccsID[J = " @ (#)int_hash.cxxl.56 10/7/91"; #ifndcfint_HASH_DEF #include "intjiash.hxx" #endif // bring in hash functions, customized from our defines #include "hash.cxx" // intjiash.hxx M-276 // header for integer hash table class // T. Montlick // 9/12/89 /* source code control: @(#)int_hash.hxxl.56 10/7/91 */ #define 1NT_HASH_DEF #ifndef STRING JDEF #includc"slrin .hxx" #endif // define symbols which make a custom hash table class #ifdef HASH #undef HASH #endif ■ #define HASH inljbash #ifdel ' HASH_ELEM #undef HASH_ELEM #endif #define HASH_ELEM intjιash_elem #ifdel ' HASH_LlST #undef HASH_L!ST #endif #dcfine HASH_LIST intjbashjist #ifdef VAL_TYPE #undef VAL_TYPE #cndif #define VAL_TYPE int #ifdef USE_POINTER #undef USE_POINTER #endif //inehκlc"hash.hxx" // intrface.cxx // C language interface to C++ classes // T. Montlick // 10/31/89 /* source code control: */ static char SccsID[] = "@(#)intrface.cxxl.56 10/7/91"; #ifndef lNTRFACE_DEF #include "intrface.hxx" #endif // include header which fjind function uses -277 #include "starstd.h" // make all functions in this file C-callable, so don't mangle names extern "C"[ // current block pointer block* curjblock = NULL; /* pointer to current arg set (for bIock_ref arguments) */ are s i*αιr are scl - NULL; /* pointer lo CUΠX U blockjef */ block -cf*cur_blυckjcf = NULL; /* block stack, for nested blocks */ block_stack the_block_stack; // file stack for nested include, files file_stackthejile_stack; // hash table of pointers to all our block prototypes block_hashprototypejblocks(20); //list of asm blocks, used for generating listing block_array asmjblockjϊst; // list of blocks in order encountered block_arrayblockJϊst; // current input filename char in_fiIename[MAX_NAME SIZE]; // pointer to input filename as a string string* in_filename_striπg; // pointer to path string lo prepend to all input files string* in jpathjstring; /* parser variables: */ int line ; /* line number for current place in parse */ inl insirjine; /* line # of current instruction */ interror_couιιt = (); /* initialization variables from init file */ long n_gsps; long njports; long flagjocs; long io_space_start; long dala_space_sιarl; long code_space_start; long code_space_sϊze; long data_sρacc_size; long ϊα_space_sϊzc; M-278 long fιrst_serial_port; long last_seriaijpυrt; long firstjnjport; long njnjports; long iirst_outjport; long njniljp rls; long lirsl_compιιle_linc; long last_computeJine; long chip jspj"ate; long max jpiojiumber = 3; long maxjtsjiumber = 3; long absjαddr udge = 0; string* SPROCjnodel = (string*) NULL; string* = (string*) NULL; /* variables from the command line */ string*SPROC = (string*) NULL;/* SPROC type - determines init file */ string*altjpath = (string*) NULL;/* alternate path for input files */ string*list_filc = (string*) NULL/* name for listing file */ string*outjιle_base = (string*) NULL/* base name for output files */ string*manjllejbase = (string*) NULL/* base name for manual output file */ externBOOLEAN verify _only = FALSE;/* verify compilation only - no link */ exteπιBOOLEANno_exccutable = FALSE/* suppress output of executable file */ externBOOLEANmakeJisting = FALSE/* by default, don't make listing */ externBOOLEANvcrbosc = FALSE; externBOOLEAN nojilejn o = FALSE/* error messages have file info */ externint clock_crror = DEFAULT_CLOCK_ERROR;/* % clock error to allow */ externBOOLEAN uncensored = FALSE/* uncensor detailed statistics */ exleπiBOOLHΛN nojparliiion = FΛLSI 7 ./* default is lo partition */ externint deilt subr_count = DEFAULT SUBR_COUNT/* count to use subr */ BOOLEANvaluesjnust_be_known; /* pointer to top of instance tree */ i nstance * top J ns tance ; /* pointer to top of user's design */ instance *user_topJ nstance ; /* child index in true top block of user's top block */ int usersjυpjblockjndex; /* pointer to instance of restart vector */ instance*rcstartjnstancc; /* pointer to the restart block prototype */ M-279 2k block* restartjblock; /* fifo hardware (lags allocator class */ (lags* lil jlags; /* gpio and rts allocators */ ϊojbits*gpios; io_bits*ris; /* time zones */ zoπes*the_zones; /* gsp allocator class */ gsps* gsp αllocator; /* makefile file stream */ ostream*makefile_siream ptr; /* partitioning info */ int n ioncs = 0; int_arrayn_gsps_uscd; double exact_gsps[10]; int total _gsps = 0; II nc\v_string // Create a siring from a character pointer and return a pointer to it // Used to create our C++ string from a C code call. siring* new_string(char* s){ I ' l'ltim nπv lι iιιi'(s);) II concal_string // Concatenate two strings. // Used to concatenate 2 C++ strings from a C code call. string* concat_siring(string* si, string* s2){ //just used concatenation operator for string class *sl = *sl + *s2; return si;} II deletejstring // Delete a string. // Used to delete our C++ string from a C code call. iiiiimiiiuiiiiuiiuuittiiiiiiiiiiii miniiuiiiiiiininiii void delele_string(string* s){ delete s; } II intjro_expr // Create an expression class instance from an integer. // Used to create an expression from a C code call. expr* int_to_expr(long numb){ expr*new_expr; new_cxpr = new cxpr(numb); return new_expr; } II real _to_expr . . // Create an expression class instance from a real. // Used to create an expression from a C code call. expr* real_to_cxpr(doublc numb){ expr*ncw_expr; iicwj xpr = new cxpr(ιuιιnh); return new_expr; } II string_toj2xpr // Create an expression class instance from a string. // Used to create an expression from a C code call. expr* siring lo ('xpi ' (slrin_>* s){ expr*ncw_expr; new_expr = new cxpr(s); return ncw_expr; } II opera tor_to_expr // Create an expression class instance from an operator, which is a // single character code representing an arithmetic operation. II Used to create an expression from a C code call. struct expr* operator_to_expr(char op){ expr*new_cxpr; ncw_expr = new expr(op); return new_exρr; } M-281 // concat_expr //Build up an expression by concatenating two expressions. // Used lo build an expression from a C code call. expr* concat_expr(expr* exprl, expr* expr2)! exprl->concat(expr2); return exprl;} II real_value // Return the real value of an expression. // Callable directly from C code. double real_value(expr* e){ int dummyjype; int dummyjevel; return e->real_vaiue(&dummyjype, &dummyjevel);} iiiiiiiiiunnniπiiiiiiiiiiiiπniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiπiiiiiiiiiii II inl_value // Return the integer value of an expression. // Callable directly from C code. long int_value(exρr* c){ int dummyjype; int dummy level; return e->ϊnl_value(&dumιnyjype, &dumnιyjcvel); } iiniitπiiiininiimiiiiiπiiiπiiiπiiiiiiiiniiiiiiiiiiiiiiiiiiiiiiiiiiii If what_relocJevel // Returns relocation level of an expression. // Callable directly from C code. int what jreloc Jevel (expr* e){ return c->what_rel oc Jevel ();} II C interface to block class. // AH routines use the external variable curjblock, which is a pointer // to the current block. Mrifm/m//mifm/miMm///MiMimιιι/M/ιtι/ιι II eur_hlk_check() // If no current block for interface routine, exit with error msg. void cur_blk_chcck(char* msg_cυde, char* msg) ( NOREF(msg); if (!cur_block){ outj3rr_hcader(msg_code); cerr « "INTERNAL ERROR: No current block for ' « msg « V; exit(-l); } } II setjblockjiame // Sets block prototype name.. BOOLEANset_block_name(string* n) { cur _blk_check("INT901", "setjblockjiame"); return curjbloek-xsetjblock jιame(n); } II add_storage jiame // Adds a new memory location referred to by the given name. // Returns as an argument the storage index (next sequential) // which was allocated. // Returns FALSE if the name was already present. B LEANadd_stυragejιame(sU-ing* name, expr* size, inl* index, char type, BOOLEAN isjnicro, BOOLEAN is_variable)! cur_blk_check("INT902", "add_storage_namc"); return cur_block->add_storage_name(name, size, index, type, isjnicro, is_variable);} II add_storageJnit // Associates a storage location with an expression which supplies the // initialization value. void add_storagejnil(inl location, expr* exprjptr) { cur_blk_check("INT903", "add_storageJnit"); cur_block->add_storage Jnit(location, exprjptr); } II addjυjiame // Adds a new I/O offset referred to by the given name. M-283 // Returns as an argument the offset (next sequential) // which was allocated. // Returns FALSE if the name was already present BOOLEANadd o_namc(slring* name, int* offset, BOOLEAN is_micro){ curjblk heck("rNT904", "addJo_name"); return cur_block->addJo_name(name, offset, isjnicro);} II sctJo_size_and_direction // Sets the size and direction for the given VO offset name. // Returns FALSE if the name was not present BOOLπΛNsclJo_size ιndj.Iiιcciion(slring* name, expr* size, inl dir){ cur_blk_chcck("lNT905", "setJo_size_and_direction"); return cur_block->setJo_size_and_direction(name, size, dir);} II setJoJnit_value // Sets an initial value for the given I O offset void setJoJnit_vaIue(int i, expr* e)! cur_blk_check("INT906", "setJoJnit_value"); cur_block->seιJo Jnit_value(ϊ, e); } II addjparam jiame // Allocates a new parameter referred to by the given name. // Returns as an argument the index (next sequential) // which was allocated. // Returns FALSE if the name was already present luiiu iiiiiiiuiiiiiriiiiiniiiiiuπiiiiiuiiiiiiiiiiiiiiiiiiiiiiiiπniif BOOLEANadd jparam_name(string* name, int* offset)! cur_blk_check("INT907", "add jparam jiame"); return curjbIock->addjparam_name(name, offset);} If finish_adding_params // Encountered last parameter declaration, so this routine finished off // adding parameters by always adding the "exports" parameter. void finish jαddingjparamsO! static string exports_string(EXPORTS ?ARAMJSTR); M-284 static string empty_string(""); static expr empty_string_expr(&empty_string); int temp; if (add_expression_name(&cxports_string, &emρty_string_expr)) addjparam jιame(&exports_string, &temp); } // add_symbol_name // Allocates a new symbol referred to by the given name. // Returns as an argument the index (next sequential) // which was allocated. // Returns FALSE if the name was already present BOOLEANadd_symboljιame(slring* name, int* offset, BOOLEAN is_micro){ cur_blk_chcck("INT9()S", "add_symhol jiame"); return cur_block->add_symbol_name(name, offset, isjnicro);} II add_cxprcssion jiame // Associate an expression with a symbol name. // Returns FALSE if the name was already present. BOOLEANadd_expression_name(string* name, expr* exprjptr)! cur_blk_check("INT909", "add_exprcssion jiame"); return cur_block->add_cxprcssion_namc(namc, exprjptr); } II add_alias_name // Adds a new alias name and associate it with an equivalent name. // Returns FALSE if the name was already present. BOOLEANadd_aIiasjιame(string* newjiame, siring* equivjiame)! cur_bIk_check("INT910", "add_alias_name"); return cur_block->add_alias jιame(new_name, equivjiame); } II add v'erify ixpression // Add an expression whose truth is to be evaluated when this block // is instantiated. void add_verify_exprcssion(cxpr* exprjptr, string* fail_string){ cur_blk_chcck("INT911", "add_verify_expression"); cur block->add_verify_expression(expr_ptr, fail_string); } M-285 mmuuiiiHiiiiiimmiimmiiimiinmiimiuiuimuiufiMiii If translation // Returns the expression which is the translation of the given // symbol name. // If the name is an alias, translate until an expression is found. // If name not found, return NULL. uiiinmiiimiiimiiiiimumiimmmumiumumimuimuiiiit expr*transIation(string* name)! cur_bIk_check("INT912", "translation"); return cur jbIock->lranslation(namc); } II known_symboI // Returns TRUE if the given name is a known symbol. BOOLEANknown symbol (string* name) { cur_blk_check("INT913", "known symbol"); return cur_block->known_symbol(name); } I! translationj nown // Returns TRUE if the given name has a known value. BOOLEANtranslation J nown(string* name) { curjblk_chcck("INT914", "ιranslalion_known"); return cur_block->translation_known(name); } II add_operand_value // Record an operand value expression and return an unique index which // identifies the expression. int addjpperand_value(expr* exprjptr)! cur_blk_check("INT915", "add φcrand /alue"); return ((asmjblock*) cιιr_bIock)->add )perand_value(expr jptr); } II add Jabel jiame // Adds a new label name along with its address. // Returns FALSE if the name and an address were already present. BOOLEANadd Jabel_name(string* name, int address)! curjblk_check("INT916", "addJabel_name"); M-286 return (cur_block)->add Jabel_name(name, address); } II set_duration // Set duration expression for asm block. . BOOLEANset_duration(expr* duration)! cur_blk_check("INT917", "set_duration"); return ((asmjblock*) curjblock)->set_duration(duration);} II assign Jabel Jndex // Gels an index (not an address!) for a label name. // If the name was not encountered before, a new, unique index is allocated // for it. int assign Jabel Jndex(suring* name){ cur_blk_check("INT918", "assign Jabel Jndex"); return (cur_block)->assign Jabeljndex(name); } II enter jields // Enter the fields of a new instruction into the arrays for each field. // The number for this instruction is passed, as this is used as the // array index for the fields. // Keeping the instruction fields in distinct arrays makes it easier // to do successive compiler passes, eliminating the need for masking // of the composite instruction. // ////////////////////////////////// //////////////////////////////////////////// void enterjields(int index, int linejium, int opcode, int addrjnode, int operand, int reloc Jevel) { cur_blk_check("INT919", "enter_fields"); ((asmjblock*) curjblock)->enterjιelds(index, linejium, opcode, addrjnode, operand, relocjevel); } II set_origin // Set origin for start of code. void setj3rigin(int org){ cur_blk_check("INT920", "set_origin"); cur_block->set_origin(org); } M-287 II setjphantom // Mark block as a phantom (linker-inserted). void setjphantomO! cur_blk_chcck("INT921", "setjphantom"); cur _block->set_phantom() ; } uuiiπiiπiiuimuiHiiu iiiiiiiiπifiiiiiiiiiiiiiiniiiiiiiiiiiiiπi^ If set_as_virlual Jo // Mark block as a a virtual I/O block. void set_as_virtual_io0{ . cur_blk_check("INT922", "set_as_virtualJo"); cur_block->set_as_vϊrtuaI Jo(); } II setjnit // Mark block as init (once_only execution). void set JnitO! cur_blk_check("INT923", "setjnit"); cur_Wock->set JnitO; } II set_timezone // Sets timezone name and values for current block. BOOLEANset_timezone(expr* name, expr* rate) { cur_blk_check("INT924", "set_timezone"); return cur_block-r>sei_timczone(name, rale);} //set αsjport // Set current block as input or output port, plust set config parameters. ιifmιιιuιιιuιιιιιuιιιιiiu\mιuuuιιιiϊi\ftn\uιmιiϊiιιιιι\fiιιιι BOOLEANset_asjporl(expr* portjium, expr* trigger, BOOLEAN is_output, expr* config, expr* entry _size){ cur_bIk_check("INT925", "set_asjport"); return cur_block->set_asjport(port_num, trigger, isjrjutput config, entry_size);} II set jpio M-288 // Allocate a gpio port. void set_gpio(expr* num, BOOLEAN is_output){ cur_blk_chcck("INT945", "set_gpio"); curjblock->set_gpio(num, is_output); } // Allocate an rts port. void setjts(expr* num, BOOLEAN is )utput){ cur_blk_chcck("INT946", "sctjts"); curjblock->sct_rls(num, isj3iιtput); } II set_computeJine // Set current block as compute line triggered. BOOLEAN set_computeJine(expr* num){ cur_blk_check("INT926", "set_computeJine"); return cur_block->set_computeJine(num); } II is_absolute // Returns TRUE if addresses arc absolute. BOOLEANis_absolute(){ cur_blk_check("INT927", "is_absolute"); return cur_block->is_absolute();} II instrjiumber // Returns instruction number of current block. int instr jiumberO! cur_blk_check("INT928", "instrjiumber"); return cur_block->inslrjιumber(); } II advancejnstrjiumber // Advances instruction number of current block. void advancejnstr jiumberO! cur _blk_check("INT929", "advancejnstrjiumber"); 63k M-289 cur_bIock->advance JnstrjiumberO ; } II storage_error // Output error text for storage initialization. Passed text and //index of storage location. ttiiimiiiimiiimumuiuimtiimimimtii imiuiiiumimiHiu int storage_error(char* msg_code, int loc, char* s) { cur_blk_chcck("INT930", "storage_error"); return ((asmjblock*) cur_blc-ck)->storagc_error(msg_code, loc, s);} miiimimiiiiiuimmiuiimiiHiuiimiimiiiinniuiiiiiumiiun II seljjecimating // Record that this block is decimating. void sel_decϊmaling(cxpr* ratio)! cur_blk_chcck("INT943", "set_decimaϋng"); curjblock->set_decimating(ratio);} II setjnterpolating // Record that this block is interpolating. void setJnterpolating(expr* ratio)! cur_blk_check("INT944", "setjnterpolating") ; cur_bIock->sciJntcrpolaling(ratio);} II new_arg_set // Create a new current arg set void new ιrg_sel(BOOLriΛN store _hy_name)( cur_arg_set = new arg_set(store_by_name); } II cur_arg _set_check() //If no current arg set for interface routine, exit with error msg. void cur_arg_set_check(char* msg_code, char* msg)! NOREF(msg); if (!cur_arg_sct){ out_err_header(msg ;ode); cerr « "INTERNAL ERROR: No current arg set for ' « msg « * \n"; exit(-l); M-290 } } II addjposit_expr // Add a positional argument expression current arg_set. BOOLEANadd jposit_expr(exρr* e){ cur_arg_set_check("INT931", "addjposi expr"); return cur_arg_set->addjposit_expr(e); } II add_named_expr // Add a named argument expression current arg_set BOOLEANadd_named_expr(string* name, expr* c)( cur_arg_set_check("lNT932", "addjposit_expr"); return cur_arg_set->addjιamed_expr(*name, e);} II newjblockj-ef // Create a new current block_ref. void new_block_ref(string* blckjiame, string* instjiame, int 1)! cur jblock _ref = new block_ref(*blck_name, *inst_name, 1);} II curjblock_ref_check() // If no current block ref for interface routine, exit with error msg. void cur_block_ref_check(char* msg_code, char* msg){ NOREF(msg); if (!curjbloekjef){ out_errjbeader(msg_code); cerr « "INTERNAL ERROR: No current block ref for ' « msg « Λn"; exit(-l); } } II store_vals // Store the set of value arguments for the current blυckjcf. BOGLEANstore_vals(arg_set* p){ cur_blockj-ef_check("lNT933", "store_vals"); return cur _block_ref->store /als(p); } M-291 II store jports // Store the set of port arguments for the current blockjref. BOOLEANstore_ports(arg_set* p){ cur_block_re checkCTNT934", "storejports"); return cur_blockjref->storejports(p); } II savejhϊsjblockjef // Save cur jblock jref as the next ref for the curjblock. iiiiiiiiiiiiiiiiiiiriiiiiriiiiiiiiiiiiiiifiiiiriiiiiiiiiriiiiiiiiiiiiiiiiiiiiH BOOLEAN save_this_blo.ckj-ef() [ curjbIk_check("INT935", "save_lhis_block_rcf); return ((hier jblock*) cur _block)->add_blockjrei " (cur jblockjref); } II push jblock // Push the current block on the block stack, and replace it with the given // block. void push_block(block* b)! lhe_bIock_stack.push(cur_block); curjblock = b;} // add jblock // The given block is new, so add it to the list of blocks. void add_block(block* b){ blockJϊsl[blockJistsize()j = b;} II pop Jblock //Pop up the block stack, making the previously pushed block the current //block. void pop jblock(){ curjblock = lhcJ)lock_stack.pop();} II newjiϊerjblock // Create a new hierarchical block and set as the current block. // Push any current block. M-292 void ncw_hicr_block(){ push_block((block*) new hierjblock()); // add block to list of unchecked blocks add_block(cur jblock) ; } II new asm jblock // Create a new assembly block and set as the current block. // Push any current block. void ncw_asm_block(){ pushjblock((block*).nc asm_block()); // save the asm block in llic list of blocks for generating listing asm jblockjistlasm jblockJist.sizeO] = curjblock; // add block to list of unchecked blocks addjblock(curjblock); } II ncwjsubrjblock // Create a new subroutine block and set as the current block. // Push any current block. void ncw_subrjblock(){ push_block((block*) new asm_block()); // tell the block that it is a subroutine block curjblock->set_subrjblock(); // save the asm block in the list of blocks for generating listing asmjblockjistfasm jblockJistsizeO] = curjblock; // add block to list of unchecked blocks ad jblock(curjblock);} // ncw_caII_block // Create a new subroutine call block and set as the current block. // Push any current block. void new_callJ ) l »L'k(){ pushjblock((block*) new asm blockO); // tell the block that it is a subroutine call block cur_block->sel_call_block(); // save the asm block in the list of blocks for generating listing M-293 asmjblock Jist[asm jblock JistsizeO] = curjblock; // add block to list of unchecked blocks add_block(cur jblock); } II new_seq_block // Create a new sequence block and set as the current block. // Push any current block. iiiimmim ui uumtumiu uim uuuiut i mmii void new_seq_block()[ push_block((block*) new seq_block()); // add block lo list of unchecked blocks add block(cur jblock); } If new spjilock // Create a new GSP sequence block and set as the current block. // Push any current block. void new_gsp_block(){ push_block((block*) new gsp_block()); // add block to list of unchecked blocks add_block(cur jblock) ; } II end_of block // The end of the current block has been reached, so pop the block stack. // Returns FALSE if not all IO has been declared for block. BOOLEAN end DfjblockO! int status = TRUE; cur_blk ;hcck("lNT936", "end_of jblock"); // make sure that all IO has been declared for this block if (Icur_block->aIlJo_declared()) status = FALSE; popjblockO; return status; } niiiiimiiuuiiuiiiuiuiiiiiiiiiiiiiiiiiiiiifmiuuininiuiiiuim If end )f_asm section // The end of an ASM section imbedded in the current gsp Jblock has // been reached. //The end of the current block has been reached, so pop die block stack. M-294 BOOLEAN cnd_ofjιsm_sccϋon(){ int status; block* asm_section; // save pointer to the asm section block asm_section = curjblock; // done with this block, so pop status = endjjf jblυckO; cur_blk_check("INT937", "endj3f_asm_section"); ((gsp_block*) cur_block)->add_new_asm 5ection(asnι_section); . return status; } . . II (inishjismjblock // The end of an asmjblock has been reached. Do post-processing on this block: // Resolve forward references, evaluated operands, etc. BOOLEAN finish_asm_block(){ BOOLEANstatus = TRUE; // clear instr line for for following block error msgs instrjine = 0; cur_blk_check("INT938", "finish_asm_block"); // save # of instructions ((asmjblock*) curjblock)->setjιJnstructions(cur_block->instr_numberO); // evaluate operand values status 1= ((asmjblock*) curjblock)->evalj)perands(values_must_be_known); // make sure duration is present if its necessary status 1= ((asmjblock*) cur_block)->check_duration(); return status; } II push Jϊle // Push the currently open file on the block stack, and replace it with the ■ // given new filename, opening it. // If could not open the new file, return FALSE and the full path which failed // (nol ing gels pushed). // Exits with error if maximum file depth exceeded. BOOLEAN pushjιle(string* fjiame, string** path jptr) { extern FILE*yyin; 6k0 M-295 // check for max file stack depth if (the_file_stack.sizc() == MAX ?ILE_DEPTH){ out_err_header("INT001"); cerr « "Maximum include file depth of" « MAX_FILE_DEPTH « " exceededΛn Do you have recursive include files?W; exit(-l);} else { // stack current file info, including FILE ptr in yyin thejjle_stack.push(in_filename_string, yyin, line); // open new file if (lopen _injϊle(f_name, path jptr)) ( popJileO; return FALSE; } // set this filename as current one in_filcname_string = fjiame; } return TRUE;} II pop_file // Pop up the file stack, making the previously pushed file the current // file. Returns TRUE if something was popped from stack. BOOLEAN popJileO! extern FILE*yyin; // pop only if something in file stack if (the_file_stack.size()) ! // close currently open file, since we're all done with it if (yyin) fclosefyyin); // and substitute file from slack injiienamejstring = the_file_stack.pop(&yyin, &line); return TRUE;} else return FALSE;} II strip jpath // Passed a pointer to a filename string, this function creates another string M-296 // consisting of the name with any initial path information stripped, and // returns a pointer to this string. string* stripjpath(string* name)! int i; string *stripped jiame; for (i=namc->lengllι()-l ; i>0; i--){ if ((*name)[i] == 7' II (*namc)[i] == '\V) { i++; break; } } strippedjiame = new slring(&(*namc)|i " l); return sirippedjiame; } II getjpath // Passed a pointer to a filename string, this function creates another string // consisting of just any initial path information, and // returns a pointer to this string. string* getjpath(string* name){ int i; string*path_name; char c; pathjiame = (string*) NULL; for (i=name->lcngth()-l; i>0; i-){ if ((*name)[i] == 7' II (*name)[i] == 4 \V) { // save character after path delimiter c = (*name)[++i]; // substitute string terminator and make path string (*name)[i] = '\0'; pathjiame = new string(&(*name)[0]); // replace character (*naιne)|i| = c; break; } } // if no pathname found, create an empty suing if (pathjiame == (string*) NULL) 6kZ M-297 pathjiame = new stringC'"); return pathjiame;} miimuuuimiummnummnmnmmmiiiiiiuiimtimMiiiu II open Jn_file // Opens the input file with the given name. // This function checks the alternate path if not found in current directory. // If file could not be found, returns FALSE and an pointer to the pathname // which failed. // Includes support for makefile, which lists all files opened for this design. BOOLEAN openJn_file(suring* fjiame, string** path jptr)! extern FILE*yyin; // string* altjiame; string* namcj sed; // string* slrippcdjiainc; char full_nameLMAX_PATH] ;// returned by f _find() // BOOLEAN filc_opcned = FALSE; // try to open input file with file pointer yyin (for lex) // first strip off any path and prepend the standard path string // strippedjiame = strip jpathffjiame); // *f jiame = ""; // *f jiame = *f_name + *in jpath jiring + *stripped_name; if (file_find(&(*f_name)[0], fulljiame) !=OK)( *pathjptr = fjiame; return FALSE;} else{ *f_name = ""; *f jiame = *f_name + fulljiame; } if (yyin = fopen(&(*f_name)[0], "r")) // { namejjsed = fjiame; // file_opencd = TRUE; // } // else if (*in path_slring != "") / { // //cmilriu ' i np ii, so if lliπc was any pn pπiili'd pulli .siring, // // try removing it and opening the file in the current directory // *f_name = *stripped_name; // if (yyin = fopen(&(*f_name)[0], "r")) 6k3 M-298 // { // name_used = fjiame; // file_opened = TRUE; // } // } // if (Ifile jDpened) else{ *pathjptr = fjiame; return FALSE; } /// // couldn't open, so try with alternate path name prepended // altjiamc .= new stringC"'); // strippedjiame = strip jpath(f jiame); // *alljιame = *altjιame + *altjpath + *strippedjιame; // if (yyin = l ' open(&(*alljιame)|()|, "r")) // namejised = altjiame; // else // { // *path jptr = altjiame; // return FALSE; // } // } // record full filename globally in Jilename_string = namejised; // add a line to the makefile for whatever name we used *makefile_streamjptr « *name_used « "\n"; // init counters for the parser line = 1 ; instrjine = 0; return TRUE;} II get_config_constant // Evaluate the SPROC configuration constant read from the init file. int get_config_constant(string name, long* var jptr) { expr* cxprjplr; inl dummyl, dummy2; int status = 0; if (lop Jnstance == (instance*) NULL){ 6kk M-299 out_err_header("INT939"); cerr « "INTERNAL ERROR ~ Failed to get config constantta" « " — no top instanceΛn"; return 1;} // make top instance the current block lop Jnstance->push_context() ; exprjptr = topJnstance->prototype()->translation(&name); if (exprjptr = (expr*) NULL) { out 3rr_header("INT002"); cerr « "Could not find the configuration symbol '" « name « '"Λn is your init file current?\n"; status = I;} if (!status){ if (cxprjplr->hasjnl_value()) { *varjptr = exprjptr->int_value(&dummyl, &dummy2); } else { out_err_header("INT003"); cerr « "Non-integer value for configuration symbol "' « name « '"Λn Your init file may be currupted.\n"; status = 1; } } top Jπstance->pop_context() ; return status;} II get_config_string // Evaluate the SPROC configuration string parameter read from the init file. int get_config_string(string name, string** var jptr) ! expr* exprjptr; int status = 0; if (lo Jnstance = (instance*) NULL){ oul '.rrJιeadcr("INT94()"); cerr « "INTERNAL ERROR ~ Failed to get config constant\n" « " ~ no lop instanceΛn"; return 1;} // make top instance the current block topJnstance->push_context(); exprjptr = topjnsiancc->prototype()->ιranslaiion(&name); if (exprjptr == (expr*) NULL)! υut_err_hcadcr("INT004"); cerr « "Could not find the configuration symbol '" « name « '"Λn Is your init file current?\n"; status = 1 ; ) if (!stalus){ if (!exprjp r->eval_to_symbol(varjptr)) ( out_err_h ader("INT005"); cerr « "Non-string value for configuration symbol '" « name « '"Λn Your init file may be curruptedΛn"; status = 1; } } topJnstance->pop_context(); return status; } II getjιscr_config_constant // Evaluate the SPROC configuration in the user's top block. int get_user_config_constant(string name, long* var jptr) { expr* exprjptr; int dummy 1, dummy2; inl status = 0; if (user j.o Jnstance == (instance*) NULL){ out_err_hcader("INT941"); cerr « "INTERNAL ERROR ~ Failed to get config constanΛn" « " - no lop user blockΛn"; return 1 ; } // make user top instance the current block uscr_topJnsiancc->push_contcxt(); expr_ptr = user _topJnstance->prototype()->translation(&name); if (exprjptr = (expr*) NULL)! out_err_hcadcr("INT006"); 6k6 M-301 cerr « "Could not find the configuration symbol '" « name « "'.\n"; status = 1;} if (.'status)! if (expr jptr->has Jnt_va ieO) { *varjptr &dummy2); } else { oul_eιτJιeader("INT()()7"); cerr « "Non-integer value for configuration symbol '" « name « "'.\n"; status = 1; } } user_topJnstance->pop_contexl(); return status;} If get_user_config_siring // Evaluate the SPROC configuration suing parameter in the top user block. int get_user_config_string(string name, string** var jptr) { expr* exprjptr; int status = 0; if (user op Jnstance = (instance*) NULL) { out_err_header("INT942"); cerr « "INTERNAL ERROR - Failed to get config constant^" « " — no top instanceΛn"; return 1;} // make user top instance the current block user_topJnstance->push_context(); exprjptr = user_lopJnstance->prolotypeO->translalion(&name); if (exprjptr = (expr*) NULL) { out_err_hcadcr("lNT008"); cerr « "Could not find the configuration symbol '" « name « "'.\n"; M-302 status = 1 ; } if ('status)! if ( lexpr _ptr->eval _to_symbol(var _ptr)) { υut_err_header("INT009"); cerr « "Non-string value for configuration symbol '" « name « " l .\n"; status = 1; } } user op nstance->pop :oniexl(); return status;} . II real_outjr)f_range // Returns TRUE if the real number is out of legal SPROC number range. BOOLEAN real_out_of angc(double real_val){ return ((real_val > MAX_REAL) II (real_val < MIN_REAL));} II eval_24_bit_value // Evaluate an expression, whether real or integer, to a 24-bit value. // Returns 0 if an error in computing the value, and a positive error // code. int eval_24jbit_value(cxpr* e, long* valjptr, int* relocjype, int* relocjevel, BOOLEAN* is_real){ doublereal_val; long val = 0, overllowjbits; expr_elcment value; // assume we don't have a real value *is_real = FALSE; // default 24-biι value is 0 // assume reloc level is 0 and type is absolute location ♦ relocjype = ABSOLUTE; ♦ relocjevel = 0; M-303 M if(!e) return NULL_EXPR; // evaluate the expression if (!e->eval(&value)) { // eval error, so return error code, which is an integer value // unless value is simply not known yet if (value.error_code() == NUM_VALUE OT_KNOWN) *reloc_type = UNDEFINED; return vaIue.error_code();} // pass caller relocation info *reloc_type = value.what_reIoc_type(); *reloc Jevel = c->whatjplocJevel(); swilch(valuc.whal Jypt-0) { case SYMBOL_VALUE: *reloc_type = UNDEFINED; return NUM_VALUEjNOT_KNOWN; case INT_VALUE: val = value.int_value(); break; case REALJVALUE: // immediate value is real, so make sure it's in range real_val = value.real_value(); *is_real =TRUE; if (rcal_out_of_range(real al)) return REAL_OUT OF_RANGE; // get 24 bit integer equivalent of real value val = (long) (real_val * REAL_FACTOR); break; default: return COULD_NOT_EVAL;} // make sure value will fit in 24 bits overflowjbits = val & -WORD jMASK; // check if overflow and not just sign extension if (overflow Jiϊts && (overflowjbits != NEG VORD DVERFL)) return OVERFLOW; // return 24 bit value *valjptr = val; return VALUE OK;} m/// ////m/ ////ιι/ffm// m///mwι///////ι/mm/w 6k9 M-304 // shouldjpartitionjJesign // Evaluate if we should partition the design. Don't partition if user's // top level block is a GSP block (manual partitioning). // Returns FALSE if no. BOOLEANshoukijparlition_dcsign(){ if (no_partition) return FALSE; // get ptr to our child, which is the user's top level block if (user_topJnstance == (instance*) NULL) return FALSE; return !(user_topJnstance->prototype()->isjnanualjblock());} ) /* inirface.h ** ** C language interface to C++ classes ** ** T. Montlick ** 10/31/89 */ / ♦ source code control: @(#)intrface.hl.56 10/7/91 */ #define INTRFACE JDEF /* storage type codes used for linker */ #defineRELATIVEl #defineABSOLUTE0 #defincUNDEFINED-l /* use function prototypes for C++ */ til clef cplusplus class arg_set; class block; /* declaration of external functions which deal with expressions */ extern struct expr*realj.o_expr(double numb); extern struct expr*inι_to_expr(long numb); extern long int_valuc(cxpr* c); extern double real_value(expr* e); extern int whaι_relocJevel(expr* e); exiern struct expr* strin j.o_expr(string* s); extern struct expr* operatorj.o_expr(char op); extern struct expr* concat_expr(expr* exprl, expr* expr2); M-305 extern BOOLEANreal_out_o jrange(double real_val); extern int eval_24jbit_value(expr* e, long* valjptr, int* relocjype, int* relocjevel, BOOLEAN* is_real); /* functions which deal with strings */ extern struct string*new_string(char* s); extern struct string*concat_string(siring* si, siring* s2); extern void delclc_string(string* s); /* functions which interface lo block class (the current block) */ extern BOOLEANset_block_name(string* n); extern BOOLEANadd_storage_name(string* name, expr* size, int* index, char type, BOOLEAN isjnicro, BOOLEAN is_variable); extern BOOLEANadd Jo jιame(string* name, int* offset,BOOLEAN isjnicro); extern B ()LEΛNsetJo_size ιndjJirectioιι(slring* name, expr* size, int dir); extern void sct_ioJni vaIue(int i, expr* e); extern BOOLEANadd jparam_name(string* name, int* offset); extern void finish_adding_params(); extern BOOLEANadd_symbol _name(string* name, int* offset, BOOLEAN isjnicro); extern void add_storageJnit(int location, expr* exprjptr); extern BOOLEANadd_exprcssion_namc(string* name, expr* exprjptr); extern int addj3perand_value(expr* exprjptr); extern BOOLEANadd Jabel_namc(string* name, int address); extern BOOLEANadd_alias_name(string* newjiame, string* equivjiame); extern void add_verϊfy_expression(exρr* exprjptr, string* faϊl_string); extern BOOLEANset_duration(expr* duration); extern int assignjabeljndex(strϊng* name); extern void enter_fields(int index, int linejium, int opcode, int addrjnode, int operand, int relocjevel); extern structexpr*lranslalion(siring* name); extern BOOLEANknown_symbol(string* name); extern BOOLEANtransIation_known(string* name); extern int storage_error(char* msg_code, int loc, char* s); extern BO LEANfinish_asm_block(); cxicrn void set_origin(int org); extern void sctjphantomO; extern void set_as_virtualJo(); extern BOOLEANis_absoIute(); M-306 extern int instr jiumberO; extern void advance Jnstr jiumberO; extern BOOLEANset_timezone(expr* name, expr* rate); extern BOOLEANset_asjport(expr* portjium, expr* trigger, BOOLEAN is_output, expr* config- expr* entry size); extern void set pio(expr* num, BOOLEAN is_output); extern void set_rts(expr* num, BOOLEAN isjoutpuf); extern BOOLEANset_computeJine(cxpr* num); extern void enter_define(string* newjiame, string* value)'- extern BOOLEANfind_dcfine(string* name, char** value); /* functions which interfaςe to arg_set class (the current arg _set) */ extern void ncw_arg_set(BOOLEAN storejbyjiame); extern BOOLEANaddjposit_expr(expr* e); extern BOOLEANadd_named_expr(string* name, expr* e); /* functions which interface to blockj"ef class (the current blockj-ef) */ extern void new_block_rcf(string* blckjiame, string* inst_name f int 1); extern BOOLEANstore_vals(arg_set* p); extern BOOLE ANstorejports(arg_set* p); extern BOOLEANsavej.hisjblock_ref(); /* functions which set the current block and push/pop the block stack */ extern void push_block(block* b); extern void add_block(block* b); extern void pop_block(); extern void newJiierjblockO; extern void new ism jblock(); extern void new_call block(); extern void new_subr_block(); extern void new_seqjblock(); extern void new_gspjblock(); extern BOOLEAN end )fjblock(); extern BOOLEANcnd_of_asm_section(); /* misc */ externBOOLEAN pushjile(slring* fjiame, string** pathjptr); externBOOLEAN poρ_filc(); extern BOOLEAN openJnjιle(string* fjiame, string** pathjptr); extern int gct_config_constant(string name, long* varjptr); extern int get_config_string(string name, string** varjptr); -307 extern int get_user_config_constant(string name, long* varjptr); extern int get_user_config_string(string name, string** varjptr); externBOOLEAN shouldjpartition_desϊgn(); // extern long atol(char*); // externdouble aιof(char*); telse /* declaration of external functions which deal with expressions */ extern struct cxpr*rcal_io_expr(); extern struct expr*ϊnt_io_expr(); extern long int_value(); extern double real_value(); extern int whaL.reiocJeveI(); extern struct expr* string_lo_expr(); extern struct expr* operator_to_expr(); extern struct expr* concat_cxpr(); extern BOOLEANrea outj3f_range(); extern int eval_24_bϊt_value(); /* functions which deal with strings */ extern struct string *new_string(); extern struct string*concat_string(); extern void delete_string(); /* functions which interface lo block class (the current block) */ extern B OOLE ANset Jbl ock_namc() ; extern BOOLEANadd_storage_name(); extern BOOLEANaddJo_name(); extern B OOLEANset J o_size_and_direction() ; extern void setjojnit_value0; extern BOOLEANaddjparam_name(); extern void finish_adding_params(); extern BOOLEANadd_symbol_name(); extern void add_slorageJnil(); extern BOOLEANadd_cxprcssionjιame(); extern int add_opcrand_value(); extern BOOLEANaddJabel_namc(); extern BOOLEANaddjiliasjiameO", extern void add_vcrify 3xpression(); extern BOOLEANsct_duration(); extern inl assign Jabel Jndex(); extern void enter JieldsO; M-308 extern structexpr*translation(); extern BOOLEANknown_symbol(); extern BOOLEANtranslationJ nown(); extern int storage j3rror(); extern BOOLEANfinish_asm_block(); extern void sct )rigiιι(); extern void sctjphantom(); extern void extern BOOLEANis_absolute(); extern int instrjiumberO; extern void ad vanccjnsir jiumberO; extern BOOLEANse timezoneO; extern BOOLEANsel isjporK); extern void set_gpiυ(); extern void set_rts(); extern BOOLEANset_computeJine(); extern void enter iefine(); extern BOOLEANfιnd_define(); /* functions which interface to arg_set class (the current arg_set) */ extern void new_arg_set(); extern BOOLEANadd_posit_expr(); extern BOOLEANadd_named_expr(); /* functions which interface to blockj-ef class (the current blockjref) */ extern void new_blockj-ef(); extern BOOLEANstore alsO; extern BOOLEANstorejportsO; extern BOOLEANsavejnis_block_ref(); /* functions which set the current block and push/pop the block stack */ extern void pushjblυck(); extern void add block(); extern void pop_block(); extern void new_hier_block(); extern void new ιsmjblock(); extern void new_sιιbrJ>lock(); extern void new_calIjblock(); extern void new_seq_block() extern void new_gspjblock() extern BOOLEAN end_of_block(); extern BOOLEANend_of_asm_section(); 65k M-309 /* misc */ externBOOLEAN pushjile(); externBOOLEAN pop_file(); extern BOOLEAN openJn_file(); extern int getj;onfig_constant(); extern inl gcl_config_string(); extern int geljJser :onfig_consianl(); extern int get_user_config_siring(); externBOOLEAN shouldjpartition_design(); extern long atol(); externdouble atof(); tendϊf . . /* poinlcr lo current block */ cxtcrnstruct block*cur_blυck; /* pointer to current arg_sct (for blockjref arguments) */ externstruct arg_set*cur_arg_set; /* pointer to current blockjref */ extern struct bfockjref*curjblock_ref; /* parser variables: */ externint line; /* line number for current place in parse */ externint ϊnslrjine; /* line # of current instruction */ extern B OOLEANvaluesjnust jbejenown; externB OOLEANmake Jisting; // intrface.hxx // C language interface to C++ classes II T. Montlick // 10/31/89 /* source code control: @(#)intrface.hxxl.56 10/7/91 */ tdefine INTRFACEjDEF tifndef STRING JDEF tinclude "string.hxx" tendif tifndei ' EXPRjOEF tinclude "expr.hxx" tendif tϊfndefBLOC .DEF tinclude "blockhxx" -310 tendif tifndef BLOCK_REF_DEF tinclude "blck_ref.hxx" tendif tifndef BLOCK_STACK_DEF tinclude "blckslak.hxx" tendif tifndef F1LE_STACK JDEF tinclude "filestak.hxx" tendif tifndef BLOCK_ARRAY_DEF tinclude "blck_arr.hxx" . . tendif tifndef BLOCK_HASH_DEF tinclude "blckhash.hxx" tendif tifndef INSTANCE JDEF tinclude "instance. hxx" tendif tifndef ZONE JDEF tinclude "zone.hxx" tendif tifndef ZONE_ARR AY JDEF tinclude "zonejirr.hxx" tendif extern "C"{ class flags; class zones; class gsps; class iojbits; // max size for filename tdefine MAXJ AMEJSIZEIOO // max size for a hierarchical symbol name tdefineMAX_HlER_NAME_SIZE50 // max depth for include files tdefineMAX_FILE_DEPTH9 /* storage type codes used for linker */ tdefineRELATIVEl tdefincABSOLUTEO -311 tdefineUNDEFINED-1 /* special line number which means no line */ tdefine NO JJNE-1 /* default percent error lo allow for sample clocks */ tdefine DEFAULTJXOCKJERRO 1 /* default count of instances heforc calling subr., if available */ tdefineDEFAULT_SUBR_COUNT 3 /* declaration of external functions which deal with expressions */ extern struct expr*real_to_cxpr(double numb); extern struct expr*ϊnt_to_cxρr(long numb); extern long int_valuc(cxpr* e); extern double real_j alue(cxpr* e); extern ml wIιal_relocJevel(expr* e); extern struct expr* slring_to_expr(string* s); extern struct expr* operator_to_expr(char op); extern struct expr* concat_expr(expr* exprl, expr* expr2); extern BOOLEANrcal_out_of -ange(double real_val); extern int eval_24jbit_value(expr* e, long* valjptr, int* relocjype, int* relocjevel, BOOLEAN* is_real); /* functions which deal with strings */ extern struct suring*new_string(char* s); extern struct siring*concat_string(string* si, string* s2); extern void delete_string(string* s); /* functions which interface to block class (the current block) */ extern BOOLEANsetjblock_name(string* n); extern BOOLEANadd 5torage_name(string* name, expr* size, int* index, char type, BOOLEAN isjnicro, BOOLEAN ϊs_variabl extern BOOLEΛNaddJojιame(slring* name, int* offset, BOOLEAN isjnicro); extern BOOLEANseiJo ize_and_direction(string* name, expr* size, int dir); extern void setJoJnit_vaiue(int i, expr* e); extern BOOLEANaddjparam_name(sιring* name, int* offset); extern void linish_addingjparams(); extern BOOLEANadd_symbυl_name(slring* name, int* offset, BOOLEAN isjnicro); extern void add_storageJnit(int location, expr* exprjptr); extern BOOLEANadd_expression_name(string* name, expr* exprjptr); extern int add_operand_value(expr* exprjptr); -312 extern BOOLEANaddJabel_name(string* name, int address); extern BOOLEANadd_aliasjιame(string* new_name, string* equivjiame); extern void add_verify_expression(expr* expr_ptr, string* fail_string); extern BOOLEANset_duration(expr* duration); extern inl assignjabeljndex(slring* name); extern void enterjιelds(int index, int linejium, int opcode, int addrjnode, int operand, int relocjevel); extern structexpr*translation(string* name); extern BOOLEANknown_symbol(string* name); extern BOOLEANlranslationJ nown(string* name); extern int $loragc_error(char* msg ode, inl loc, char* s); extern BOOLEANfinishjismjblockO; extern void set_origin(int org); extern void setjphantom(); extern void set_as_virtual o(); extern BOOLEANisjibsolutcO; extern int instrjιumber(); extern void advancejnstr_number(); extern BOOLEANsetj.imezone(expr* name, expr* rate); extern BOOLEANset_asjport(expr* portjium, expr* trigger, BOOLEAN isjrjutput, expr* config, expr* cntry_size); extern void set jpio(cxpr* num, BOOLEAN is_output); extern void set_rts(cxpr* num, BOOLEAN isjjutpuf); extern BOOLEANset_computeJine(expr* num); extern void enter_define(string* newjiame, suring* value); extern B OLEANfind_define(slring* name, char** value); extern void sct_decimating(expr* ratio); extern void setJnterpolating(expr* ratio); /* functions which interface to ar _set class (the current arg_set) */ extern void new_arg_set(BOOLEAN storcjbyjiame); extern BOOLEANaddjposiι_exρr(cxpr* c); extern BOOLEANadd_named_expr(string* name, expr* e); /* functions which interface to block_rcf class (the current block_re */ extern void ncwjblock_ref(string* blckjiame, string* inst_name, int 1); extern BOOLEANstore_vals(arg_set* p); extern BOOLE ANstorejports(arg_set* p); extern BOOLEANsave_this_block_ref0; /* functions which set the current block and push/pop the block stack */ extern void pushjblock(block* b); extern void add_block(block* b); extern void pop_block(); extern void newJiierjblockO; extern void new_asm_block(); extern void new_subr_block(); extern void new_calljι )ck(); extern void ncw_scqjblock(); extern void new jsp_block(); extern BOOLEAN end jfJblockO; extern BOOLEANeπdjDf_asm_section(); /* misc */ externBOOLEAN push_file(string* fjiame, string** pathjptr); externBOOLEAN pop_file(); extern BOOLEAN openJn_file(string* fjiame, string** pathjptr); extern int get_config_constant(string name, long* varjptr); extern int get ;onfig_slring(string name, string** varjptr); extern int gct uscr_config_constant(string name, long* varjptr); extern int get_user_config 5tring(string name, string** varjptr); externBOOLEAN should jpartition_design() ; //extern long atol(char*); // externdouble atof(char*); cxtcrnsiring* sιriρjpatlι(slring* name); externstriπg* get_path(string* name); /* pointer to current block */ extemblbck*cur_block; /* pointer to current arg_sct (for block_ref arguments) */ cxlernarg_set*cur trg_scl; /* pointer to current bIock_rcf */ extern block_ref*cur jblock jref; /* block stack, for nested blocks */ externblock stack the_block_stack; // file stack for nested include files extern file_stackιhe _file_stack; // list of asm blocks, used for generating listing extern block_array asmjblock Jist; // list of blocks in the order encountered M-314 extern block_arrayblockJist; /* pointer to block hash table */ extern blockjbashprototypcjblocks; // current input filename extern charm Jilename[M AX jNAME SIZE] ; //•pointer to input filename as a string extern string* injilename_string; // pointer to path string to prepend to all input files extern siring* injpath_string; /* parser variables: */ extern int line; /* line number for current place in parse */ extern int instrjine; /*. line t of current instruction */ extern int error_count; extern BOOLEANvaluesjnustjbcJ nown; /* pointer to top of instance tree */ extern instance*lopJnstance; /* pointer to top of user's design */ extern instance*uscrj;op_instance; /* child index in true top block of user's top block */ externint users_top_blockJndex; /* effective chip gsp clock rate in hz */ extern long chiρ sp_rate; /* fifo hardware flags allocator class */ extern fiags*fifoJlags; /* gpio and rts allocators */ exlernio_bits*gpios; externio_bils*rts; /* lime zones */ exicrnzones*ιhe /.oncs; /* gsp allocator class */ externgsps*gspjιl locator; /* makefile file stream */ externostream*makcfile_streamjptr; /* partitioning info */ externint n_zones; cxternint_arrayn_gsps_used; exierndoublc exact_gsps[10]; externint total_gsps; /* initialization variables from init file */ M-315 β6 ° externlong n jsps; externlong njports; externlong flagjocs; externlong ϊo_space_sιart; externlong data_space_start; externlong code_space_start; externlong code_space_size; externlong data_space_size; externlong io_space_size; externlong lirsljseria porl; externlong lasi serialjport; externlong first Jn_port; • externlong njnjports; externlong firstjoutjport; externlong nj3ut_ports; externlong first_computeJine; externlong last_computeJine; externlong chip sp_rate; externlong max_gpio_number; externlong maxjtsjiumber; externlong abs_addr Judge; externstring*SPROCjnodel; externstring*init_version; /* variables from the command line */ extemstring*SPROC; extcrnstring*altjpath ; extemstring*list_file; externstring*out_file_base; extcrnstring*man_filejbase; exlernBOOLEANverify ily; exlenιB OLEANno_cxeculablc; cxternBOOLEANmakeJϊsting; externBOOLEANverbose; externBOOLEAN nojϊlejn o; externint clock_error; externBOOLEAN uncensored; externBOOLEAN nojpartition; externint deflt_subr_count;} // long_arr.cxx -316 // derived class for long array // Terry Montlick // 10/10/89 /* source code control: */ ' static char SccsID[] = "@(t)long_arr.cxxl.56 10/7/91"; tinclude "long_arr.hxx" // long_arr.hxx // header for derived long array class // T. Montlick // 10/10/89 /* source code control: @(#)long_arr.hxxl.56 10/7/91 */ tdefine LONG_ARRAY_DEF tifndef ARRAY JDEF tinclude "array.hxx" tendif class long irray : public array! public: void operator=(long_array& a) { array::operator= ((array&) a); } long&operator [] (int i) { return (long&) array: :operator[] (i); } int findfjong 1) { return array::find( (clem) 1); } void append(long 1){ array: :append( (elem) 1); } longjirray &opcrator+(long_array& a) { return (long_array&) array: :operator+((array&) a); } long_array&oρerator+=(long_array& a) {a = *this + a; return *this; } 1; /* mystdlib.c * Private verions of functions needed from sldlib, not available on Sun * * T. Montlick * 2/10/90 */ /* source code control: */ static char SccsID[] = "@(t)mystdlib.cl.56 10/7/91"; tinclude <ctype.h> tinclude "mystdlib.h" /* recursive itoa witii limit on number of chars */ void itoaJimit(value, stringjptr, radix, n_chars) -317 ϊnt value; char**slringjptr; int radix; int n_chars;{ int next_value; ϊnt digit; /* see if limit has been reached */ n_chars++; if (n_chars> ITOAj MTT) return; /* compute the right digit of the value */ digit = value - (next_value = value/radix) *radix; value = next_value; /* recursively call us for remaining digits */ if (value) itoaJimit(value, stringjptr, radix, n_chars); /* output our digit at end, converting to ASCII */ *(*stringjptr)++ = digit + '0'; /* add terminator, which can be overwritten by successive digits */ /* here is the real itoa */ char* itoa( value, string, radix) int value; char* string; int radix;! ϊnt next /alue; ϊnt digit; clιar*slrin»_slaιl; int n_chars; n_chars = 1; string_start = string; /* if negative value, output a minus sign and work with positive number */ if (value < 0){ *string++= '-'; value = -value; n_chars++;} M-318 itoaJimit(valuc, &string, radix, n_chars); return (string_start); } char c;{ if (islower(c)) return toupper(c); else return c; } /* mystdlib.h * * Private verions of functions needed from stdlib, not available on Sun * * T. Montlick * 2/10/90 */ /* source code control: @(t)mystdlib.hl.56 10/7/91 */ /* max chars for itoa */ tdefinelTOA J MIT13 /* use function prototypes for C++ */ tifdef cplusplus extern char* itoa(int value, char* siring, int radix); /* stick myjroupper here too, which circumvents Sun toupper bug */ extern inlmyjOuppcr(int c); telse extern char* itoa(); /* stick my_toupper here too, which circumvents Sun toupper bug */ extern intmy_toupper(); tendif // parser. xx /* source code control: */ static char SccsIDf] = "@(t)parser.cxxl.56 10/10/91"; tifndef BLOCK JDEF tinclude "blockhxx" tendif tifndef BLOCK_HASH_DEF tinclude "blckhash.hxx" tendif tifndef BLOCK _STACK_DEF tinclude "blckstakhxx" 66k M-319 tendif tifndef BLOCK_ARRAY_DEF tinclude "blck_arr.hxx" tendif tifndef UTILITYjDEF tinclude "utility.h" tendif //ilndcf lNTRPΛCI DHF tinclude "intrfacc.hxx" tendif tifndef STRING jDEF tinclude "string.hxx" tendif tifndef INSTANCE JDEF tinclude "instance.hxx" tendif tifndef ZONEjDEF tinclude "zone.hxx" tendif tifndef ZONE_ARRAY_DEF tinclude "zonc_arr.hxx" tendif tifndef DEFINESjDEF tinclude "defines.hxx" tendif extern "C" { tinclude "filefunc.h" //tinclude "gelcnv.h" tfϊndudi'. " nulirni'.h" ) tϊfdc sun extern "C~" { tclse extern "C" { tendif tinclude <time.h> tinclude <stdio.h> tinclude <stdlϊb.h>} tinclude <new.hxx> tifndef rKTND M-320 tdefine _FK1ND tendif extern "C" intyyparse(); tdefine LINK //tdefine OLD tifdefDOS tinclude <sys\typcs.h> telse tinclude <sys/types.h> tendif tdefineINIT_BASE"init" tdefineINIT_EXr'sdl" //tdefineDIRECTORY_ENV"SPR_LIB" // define for new external release //tdefine RELEASE // define for uncontrolled test version tundcfTESTREL //tdefine TESTREL // if RELEASE defined, use version t from next line, else use SCCS version t tifdefRELEASE tdefine VERSION _STRING"SCHEDULE Version 1.0" telse tifdef TESTREL tdefine VERSION_STRlNG"SCHEDULE Internal Uncontrolled Version 1.54b" telse tdefine VERSION STRINC'SCHEDULE Revision 1.56a" tendif tendif //ik-liiu- CORYRKJII ' IJS ' ΓRINC "(OpyiiL'lil ((') l« ) ' ) l by STAR Seiniconduclor CorporationW tdefine LOG_FlLE NAME"schedule.log" // hardware configuration info names from the init file tdefine N GSPS "_%n_gsps" tdefine FLAG J-OCS"_%flagJocs" tdefineCODE SPACE_STARr'_%code_space_start" tdefincIO_SPACE_START"_%io_space_start" tdefineDATA SPACE 3TARrj%data_space_start" tdefincCODE SPACE SIZE'J%code_space size" tdefincIO_SPΛCE_SIZE"_ r .io_spacc_size" tdefmcDATA SPACE 3IZE" %data_space_size" M-321 tdefmeFIRST_SERIAL ?ORT"_%first_serialjport" tdefineLAST SERlAL_PORrj%last_serialjport" tdcfincFIRSTJN_PORrj%firstJn_port" tdefineNJN_PORTS "_%nJnjports" tdefineFIRST_OUT_PORr'_%firs outjport" tdcfineN_OUT_PORTS'J%n_ou P"rts" tdefineFIRST_COMPUTEj4lNE"_%firs comρuteJine" tdefineLAST_COMPUTE_LINE'J%last_computcJϊne" tdefineCHIP 3SP_RATE"_%chip_gsp_rate" tdefιneINιT_VERSION"_%ϊnit_version" tdefineSPROC_MODEL"_%sproc_model" tdefine ABS_ADDR_FUDGE'.J%abs_addrJudge" BOOLEANhelp = FALSE; II anyjblockjiotjpresent // Scan the blocks for any block reference not present. // Start at block j, where j is a by-name argument modified by this routine. // Also sets the block ptr in each block ref. // If found one, return it. iiiiiifiiiifiiiiifitiiiiiiiiiiiiiiiiiiiiiiiriiiiiiiiiriiiiifiifiriiiiifiiiiiiif string* any jbIock_notjpresent(int& j) { string* s = 0; for (int i=j; ϊ<blockJϊstsize(); i++){ if (s = bIockJislLiJ->verify_block_refs()) break;} return s;} II oulpuljesl ifjisiing // Copy an input stream to an output listing stream. void output_rest 3fJisting(istream& in, ostream& out){ char ch; BOOLEANnewline = FALSE; while (ϊn.get(ch))! if (newlinc) { // on newline, output left margin pad spaces out «" "; M-322 newline = FALSE; ) output(ch); if (ch == '\n') newline = TRUE; ) } II compile // Compile the given file, recursively opening referenced files // as necessary. int compile(char* filename, BOOLEAN list)! int status = 0; extern FILE*yyin; filebufinbuf; filcbuflislingjile; char list_filcname[MAX_NAME 3IZE]; char newJilename[MAX NAME_SIZE]; char namc[MAX_NAME SIZE]; int listjine; string*missingjblockname; int file_count = 0; int from jblock = 0; // starting block for blocks present check // string*alt_namc; // we don't need to know all values at compile time valuesj ιstjbe_known = FALSE; slrnepy(iιιjilπιame, filename, MAXjNAMF._SIZl 7 .); while (strcmp(in_filename, "") != 0){ file_couni++; // make sure filename has the extension ".SDL" if no other splitnamerinjilename, name, extension); if (strcmp(extension, "") == 0) mergenamc(injllename, name, ".sdl"); // make the input filename available to the blocks which get created inj lename jtring = new string(iπ Jϊlcnamc); // no current line line = NO.L1NE; // open input file (with file pointer yyin for lex) M-323 if (Sopen Jn _file(in_filename_string, &in_filename_string)) { out_err_header("PAR001"); cerr « "Unable to open input file '" « *in_filename_string « '"\n"; return 1; } // call the parser status l=yyparse(); // parser is done with it, so close the input file fclose(yyϊn); // no current input file in Jϊlename_sιring = (string*) NULL; // if this file first and also has any an assembly block, make listing if (file_count== 1 && asm jblock Jistsize() > 0 &<& list) { // init line count for listing list Jine = 0; // reopen input file as a stream for C++ so we can generate listing if (!ϊnbuf.open(injιiename, input)) { // // couldn't open, so try with alternate path name prepended // altjiame = new string(""); // *alt jiame = *alt_name + *altjpath + in Jϊlename; // if (Iinbuf.open(&(*alt_name)[0], input)) { out_err_header("PARϋ()2"); cerr « "Unable lo open the input file for the listing I\n"; eπror_count++; break; } 1 istream in(&ϊnbu0; spliιname(in_filename, name, extension); // use list file name, if present if(*Iist_file== "") { *Iist_file = name; } M-324 splitnamc(&(*IistJile)[0], name, extension); if (exlension[0] == '\0') mergename(list_filename, name, ".1st"); else mergename(lisljilcnamc, name, extension); if πisliιiL> fik'.openOisl ik'nanic, oulpul) -- 0) { out_crr_hcader("PAR003"); cerr « "Unable to open listing file '" « listjϊlename «'".\n"; error_count++; break; // create stream for listing which closes when we exit scope ostream listing(&listing_file); // call the listing routine with the input stream // for all blocks which use this file for (int i=0; i<asm_blockJist.size(); i++) { if (*asm _blockJist[i]->gctjιlenameO = in_filename) { push_block(asm_blockJisl[i]); status 1= ((asmjblock*) cur_block)->out_listing(in, listing, lisijine); pop_block(); ) } // output any remaining portion of listing file output_rest_ofJisting(in, listing); // close the input file inbuf.closeO; ) } // check all new blocks for any reference to a block not present // but only if no errors to prevent recursive file opening errors if (Istatus) { 67O M-325 if (missing Jblockname = anyjblock_notjpresent(from_block)) { // found a missing block, so build a filename from its name strncpyfname, &((*missing_blockname)[0]) f MAXJiAME SIZE); mergename(newjileπame, name, ".sdl"); // see if this is same as previous if (strcmp(new_filename, injilename) = 0) { // it was, so we didn't find the block where it should be! out_errJιeader("PAR004"); cerr « "Couldn't find the block "' « *missing_bIockname «'" in the fil '" « injilename «'" !\n"; error_count++; break; } else strcpy(in Jϊlename, ncw_filename); } else strcpy(in_filename, ""); } else break; } status 1= error_count; r turn . tatus;} II caIl_user_top // Call the user's top level block within the real top level block. BOOLEAN calI_user_top(block* true_top, block* userjrop, int* which_child ptr){ block jref*refjpϋr; string* name; string* ϊnstjiame; arg_set*vals; arg_set*ports; int In; siring top jblock jιame("_user_ιop"); BOOLEANstatus = FALSE; M-326 int which_child = 0; lrucjOp->rcfsjterjnit(); // get each block name instantiated by true top level block while (li ne lop ->ncxl ivKΛivf pir))( ref jptr- >gei_blockjnfo(&name, &inst_name, &vals, &.ports, &ι II see if reference to special "_user_top" if (topjblock jiame == *name) { // it is, so substitute user top block's real name! refjptr->changejblockjιame(userj.op->getjblock ame()); status =. TRUE; break; } which_child++;} // return which is child is user's top block to caller *which_childjptr = which_child; return status; } II instantiate // Create the instance tree from the block list // Mark blocks instantiated by other blocks. // Find the block which is not instantiated by any other block. This is // the lop level block. // Build the instance lice wiih its root at the lop level block. int instantiate(){ int i; block* blk; siring* name; siring* instjiame; arg_set*vals; arg_set*poris; int In; blockj-ef*rcfjptr; block* ref jblock; block* topjevel Jblock = NULL; instance*bad_blockJnstancc; 7 6?2 siring lop_string("_true_top"); string ρhantom_lop_slring("_lop"); int status = 0; // first mark all blocks instantiated by other blocks for (i=0; i<bIockJistsize(); i++){ blk = blockJisl[i]; blk->refsjter Jnit(); //get each block name instantiated by this block while (blk->nextjref(&ref jptr)) ( ref _ptr->gcf_blockJnfo(&name, &ϊnst_name, &vals, &ports, &ln); if (prototypejbIocks.find(*name, &ref jblock)) refjblock->seι_asJnstantiatcd(); else { out 3rr_header("PAR005"); cerr « "Unable to find the block named '" « *name « '"\n"; return 1; } } 1 // now scan for blocks which are not instantiated // there should be just one of these, which is the top level block for (i=0; i<bIockJϊstsize(); i++){ bϊk = blockJϊst[ϊ]; //ignore phantom block declarations, which may not get instantiated if (blk->is_phaπιom()) » // also ignore subroutine and subroutine call blocks else if (blk->is_subrjblock()) else if (blk->is_call_block()) else if (!blk->isjι JnstantialcdO) { // make sure we don't have one already if (Itopjeveljblock) top Jeveljblock = blk; 8 else { out_err_header("PAR006"); cerr « "More than one top level block: \n" « " " « *toρ Jevel _block->gctjblock_nameO « M and ' « *blk->get_blockjιame() « "\n"; return 1 ; } } } if (Itopjevcljblock)! outj3rr_header("PAR007"); cerr « "No top level block !\n"; return 1;} // we now have a lop level block, so we can build llie inslancc tree! // First, though, we must find the phantom block "_tυp" which is the // true top level block. This phantom block can declare storage names // (which initially map to SPROC I/O space) so that all blocks may // sec these names, if (!prototypcjblocks.find(phantomj\op_string, &ref jblock)) { out_crr_headcr("PAR008"); α r « "Cannoi find I he phanlom block ' lopWn"; return I ; } // now make this block instantiate the user's top level block if (!call_user_top(ref jblock, top Jevel Jblock, &users j.op jblock Jndex)) { out_err_header("PAR009"); cerr « "Phantom block Jtop' is corruptedΛn"; return 1; } // now instantiate the true top level block topjnstancc = new inslancc(rcf_block, top_string, NULL, 0); // create the fifo flags allocator, which uses topjnsiance lifojlags = new flags(); // create gpio and rts allocators gpios = new io_bits(); rts = new iojbitsO; // build i he live if (bad_block_instancc = loρ_m.slancc->buildjroeO){ υut_errJιeadcr("PAR01ϋ"); cerr « "Block '" 67k M-329 « *bad_blockjnstance->ρrototype()->get_block_name0 « " * eventually includes itsclffvn"; return 1;} // save a pointer lo the user's top level block userjop Jnstance = top Jnstance->get_chiid(users_top jblockjndex); // Top level block has no I/O, but we must pretend its I/O is to // port blocks so the top level block will get sequenced just like // any other block. status 1= topJnstance->add_lopJevelJnpuis(); return status;} If get_configuration . . //Evaluate the SPROC configuration constants read from the init file. inl gι- [ _αiιιli » ιιtaliuι>()[ inl status = 0; status l=get_config_constant(N 3SPS, &n_gsps); if (Istatus) status 1= get_config_constant(FLAG_LOCS, &fiagJocs); if (Istatus) status 1= gel_config_consiani(fO SPACE_START, &io_space_start); if (!status) status 1= get_config_constant(DATA SPACE 3TART, &data_space start); if (Istatus) status 1= gcι_coπfig_constant(CODE_SPACE_START, &code_space_start); if (istatus) status = get_config_constant(lO SPACE_SIZE, &io_space_size); if (Istatus) status = get_config_consiani(DATA_SPACE_SfZE, &data_space_size); if (Istatus) status = get_config_consiant(CODE_SPACE_SIZE, &code_space_size); if (.'status) status 1= get_config_constant(FIRST 3ERIAL_PORT, &first_serialjport); if (.status) status 1= get_config_constaπt(LAST_SERIAL_PORT, &last_serial port); if (Istatus) status l=get_config_constant(FIRSTJNj?ORT, &firstJn_port); if (Istatus) status 1= get_config_constant(N_INj?ORTS, &n Jnjports); -330 if (Istatus) status 1= gct_config_constant(FIRST 3UT_PORT, &first_out port); if ('status) status 1= get_config_constant(N OUT_PORTS, &n_outjports); if (Istatus) status 1= get_config_constant(πRST_COMPUTE_LINE, rst_computeJine); if (Istatus) status 1= get_config_constant(LAST_COMPUTE_LINE, &last_compute_line); if (Istatus) status 1= gct_config_constant(CHIPjGSPj ATE, &chip gsp rate); if (Istatus) status 1= gct_config_string(SPROC_MODEL, &SPROC_model); if (Istatus) status 1= gct_conrιg_string(TNIT_VERSΪON, &init_vcrsion); // get fudge factor for absolute addresses if (istatus) status 1= gct_config :onstant(ABS_ADDRJFUDGE, &abs_addr Judge); // set t of ports from first and last ports if (istatus) njporls = last_serial jporl - first_serial jporl + 1 ; return status; } II evaluate_and_connect // Evaluate parameters passed to each instance. // Compute contents of blocks, evaluate storage and I/O requirements, // durations, and code sizes. // Wire, the connections between blocks and between instances. int evaluate_and_connect(){ int status = 0; // compute override symbols passed to each instance status 1= topJnstance->cvaluatejDverrides(); // compute contents of each instance if (istatus) status 1= topjnstancc->compute_contcnts0; if (istatus) status 1= topj ' nstance->process_subrυulines ; if (istatus) status 1= topjnstancc->ρrocess_exports(); M-331 // re-compute override symbols passed to each instance if (istatus) status l= topJnstance->evaIuate_overrϊdes(); // re-compute contents of each instance if ('status) status l= topJnstance->compute_contentsO; // wire up the connections between instances if (istatus) status I= top Jnstance->wϊre ;onnections(); // also set any storage for virtual VO blocks if (istatus) status l= topJnstance->set_virtualJo(); // finally set any pseudo-sampled output init values for connected wires i Oslalus) status l= lop Jnstance->setjpseudo_sampled JnitO; return status;} II sequence // Sequence children in block prototypes. //Then copy this sequence into each instance, since it may get modified // if phantom blocks are added. ϊnt scquenceO! ϊnt status = 0; BOOLEANnew_rate;// args for sequence_children // next, determine the sequence of child block firing in each // hierarchical block status l= topJnstance->proiotype()->sequence_chiIdrcn(&newjrate); // now call each instance to copy in its sequence if hierarchical if (istatus) status l= topjnstance->copyjnjsequence(); return status;} // prinl_zoneJisl // Output a master zone name and all its subzones. void prϊnt_zoneJist(zone* z, ostream& out){ int ϊ; M-332 zone* next; for (i=0; i<z->n_next_zoncs(); i++){ next = z->nexLzone(i); out « *next->get_zone_name() « " "; print_zone_list(next, out);} ) II partition // Do temporal partitioning. Create the time zones, partition them, and // report results to user. int partition(){ II create the time zones class the ioncs = new zones(); // also create the gsp number allocator gsp illocalor = new gsρs(); status = thc .oncs->crcaιc ιndjpartition / .oncs(&n zones, &n_gspsjιsed, exact jsps); if (istatus)! for (i=0; i<n_zones; i++) { the zone = the_zones->get sone(i); total sps += n_gspsjιsed[i]; cerr « "Zone " « *the_zones->get_zone_name(i); // if master zone, include names of sub-zones if (the_zυne->isjιιaster_zone()) { cerr « " (plus "; print /.oncJist(the_zonc, cerr); cerr « ")"; ) cerr « " partitioned onto " « n_gsps_used[i]; if (n_gsps_used[i] == 1) cerr « " GSP. "; else cerr « " GSPs. "; // print exact t of GSPs // minimum utilization is X.1 if any remainder overX but < 0.05 exactly = exact gsps[i] - n_gsps_used[i] + 1; if ((exactly < 0.05) && (exactly > 0.0)) exactly = 0.1; exactly += n jsps_used[i] - 1; cerr « "(Utilization is " « fbrm("%.lf ' , exactly) << ".GSPs)\n"; if (unccnsored) { cerr « "Maximum segment cycles are " « the_zones->maxj;ycles(i) « "Λn"; cerr « " Segment 0 (part 1)" « " cycles are " « the /.oncs->cycles_uscd Jn_seg(i, 0) «".\n"; for (j=l; j<the_zones->n 3egments(i); j++) { cerr « " Segment " « j « " cycles are " « ιhe_zones->cycles_used Jn_seg(i, j) « " (including " « the_zones->ovcrhcad illowed _for_in_seg(i, j) « " for inter-segment overhead).\n"; } cerr « " Segment 0 (part 2)" « " cycles are " « the_zones->cycles_usedJn 5eg(i, lhe_zones->n_segments(i)) « ".\n"; } } if (total_gsps > n_gsps) { out_err_hcader("PAR011"); M-334 cerr « "Partitioning requires " « total_gsps « " GSPs, but there are only " « n_gsps « " available on\n" « " SPROC '" « *SPROC_model « '"Λn"; status = ERROR . STATUS; } } return status; } II just_create iones // No partitioning, so just create the lime zones, and // report results to user. int just_crcate zoncs(){ inl status = 0; int i; int n iones = ϋ; // create the time zones class thc iones = new zones(); // also create the gsp number allocator gsp_allocator = new gsps(); if (!topjnstance->makejnanual_sequence()) status = 1 ; if (!status){ if (!the £ones->createjimejzones(&n_zones)) status = 1 ;} if (istatus) status = the .ones->inilializejιI fifoJnfo(); if (istatus) status = the iones->initializejportj"egisters(); if ( istatus) { cerr « "\n"; for (i=0; i<n_zoncs; i++) { cerr « "Zone " « *lhe /.ones->ge '/.onc_namc(i) M-335 « " manually partitioned.\n\n"; } } return status; } iiiiiiiiiiiiiriiiiifiiiiiriifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiriiiiiiiii //reevaluate // Reevaluate contents of blocks after temporal partioning, which has // created phantom blocks. This creates contents for phantom block instances, // and recomputes sizes. int rcevaluateO! return top Jnstaπce->compute_contents(); } II percent // Compute fractional percent of the ratio of two integers. int pcrccntfjnt part, int total)! doubIepan_double; doubleioia douhle; int result; part_doubIe = (double) part; totaI_double = (double) total; result = (int) round( (part_doublc*100/total_double) ); return result;} II generaιe_code_and_data // Set starting addresses for code and data. // Output generated code and data. ϊnt generatc_codejιnd_data() { int status = 0; filebuf pgmjϊle; filebuf daljile; int datajocs; int codejocs; int exec_lime; int overhead_ιinιe; int init_code; ϊnt overhead_code; int appLcodc; tifndef OLD void outpuf 7.onej-ecord(int zonejium, ostream& out); tendif // wc need to know all values at code generation lime valucsjnustjbc nown = TRUE; // compute starling locations for instructions and data top Jnstancc->compute_codej " ocations((int) codc_space 5 tart, NO_TTME_ZONE); topJnstance->compute_dataJocations((int) io_space_start); // make filenames lor output files program_filejιame = *outj11ejbase; program jle iame = programjilejiame + ".spp"; datajilejiame = *outj1Iejbase; data_file_name = datajilejiame + ".spd"; symboljilejiame = *out_file_base; symboljilejiame = symbol jilcjiame + ".sps"; // open files to generate code if (pgmjile.open(&program_filejiame[0], output) == 0){ out_err_hcader("PAR012"); cerr « "Unable to open '" « programjilejiame « '" output fileΛn"; status = 1 ; } if (!siatus){ if (datj11e.opcn(&datajilc_name[0], output) == 0) { oιιt_cπJιeadcr("PARϋl3"); cerr « "Unable lo open '" « datajilejiame « "' output fileΛn"; status = 1; ) } if (istatus)! ostream codc(&pgm Jile); if (istatus) 7 { if (verbose) cerr « "Generating program fileΛn"; status = topJnstance->generate_code(codc, NO TTME_ZONE); check _ostream (code) ; } } if (istatus)! ostrea data(&datjϊle); if (istatus) { if (verbose) cerr << "Generating data fileΛn"; status = topJnstance->generale_dala(dala); checkj3Stream(data) ; } } if (istatus)! // open file for symbols filebuf sy m Jile; if (symjϊle.oρen(&symboljilc_name[0j, output) == 0) { out_err_header("PAR014"); cerr « "Unable to open "' « symboljilejiame « "' output fileΛn"; status = 1; } ostream symbols(&symJϊle); if (istatus) { i (verbose) cerr « "Generating symbols fileΛn"; status = top Jnstance->output 5torage_symbols(symbols); check_ostream (sym bols) ; ] //separate storage from i/o if (istatus) symbols « "\n"; if ('status) { M-338 status = topjnstance->outputjo_symbols(symbols); chcck ,stream(symbois); } // separate io from labels if (istatus) symbol « "\n"; if (istatus) { status = topJnstance->outputJabels(symbols, NO_TTME_ZONE); check_ostrcam (sym bols) ; } if (istatus) symbols « "\n"; if (istatus) { status = lop Jnslance->outpul_symboIs(symboIs); cheek j.sli ' caιn(symbols); } tifndef OLD if (istatus) { symbols « "\n"; for (int i=0; i<ihe iones->nJncluding_sub iones(); i++) outpu zone_rccord(i, symbols); checkj)stream(symbols); } tendif} if (istatus)! // if user desires manual block file of decompiled design, output it if (*manjile_base != "") { // first create man filename with default "sdl" extension splitname(&(*manj11e_base)[0], name, extension); if (extension[0] == '\0') mergename(filename, name, ".sdl"); else mergenamcffilcnamc, name, extension); nianjilejiaine = lilcnamc; 68k -339 // make sure it's not the same as the user's top level file if (*user_topJπstance->proiotype()->get_fiIename() = manjϊlejiame) cerr « "Manual sdl file not generated because it would" « " clobber your source file.\n"; else { if (verbose) cerr « "Generating manual sdl fileΛn"; filebuf man Jile; if (man Jϊle.open(&man Jile jιame[0], output) = 0) ! outj3ir_header("PAR015"); cerr « "Unable to open '" « man_file_name « '" manual sdl output lilcΛn"; status = 1 ; } if (istatus) { ostream man_stream(&manjϊle); // set context to user's top block and output it to file topJnstance->push_contcxt(); man_strcam « "/Λn" «"// Manual design generated from automatically" «" partitioned '" « *user .opJnstance->prototype()->get_filenameO « "'\n/Λn\n"; user_topJnstance->out_variantjblocks(man 5tream); iopJnstance->pop_contcxt(); chcck_oslrcam nan_stream); } } }} // make sure to subtract i/o space and flag Iocs from storage used if (istatus)! ( lalajocs = (inl) OopJnsiance.->gcl jι_slorage_locs() - io_spacejsize - Hag Joes); code Joes = topjnstance->getjιjnstructJocs(); // don't count initialization duration in execution time execjime = topJnstance->gct_duration() - topJnstance->getJnit_duration(); overhead_time = topJnstance->getjphantom_duration(); // censor overhead! if (uncensored) ! cerr « "Of the execution time, " « perccnt(ovcrhcad imc, execjime) « "% is ovcrheadΛn"; } init_code = topJnsiance->getjiJniiJnsirJocs(); overhead_code = iυpjnstance->getjιjphaniomJnslrJocs(); appl_code = codejocs - init_code - overhead_code; overhcad lata = ioρjnstancc->geljιjphanlom_storJocs(); ajipljJala - dalajOcs - overhead jJala; // sec if we have overrun code or data space if (istatus) ! if (code_space_sizc < codejocs) ! ou t_err JieaderC'PARO 16") ; cerr « "This design requires " « codejocs « " code locations but only " « code_spacc_size « " code\n locations are available in this SPROCΛn"; stalus = 1; } } if (istatus) { if (data_space_size < datajocs) ! out_err JieaderC'PARO 17") ; cerr « "This design requires " « da la Joes « " data locations but only " M M-*34 44 1 686 « data_space_size « " daιa\n locations are available in this SPROCΛn"; status = 1; } } } ff (!slalιιs){ cerr « "A total of " « data Joes « " data locations and " « codejocs « " code locations were uscdΛn"; // append info lo log file // use C, because it has "append" file open mode FILE *fp; time_ιtimejplr; if ((fp = l pen(LOGj?lLE_NAME, "a")) == NULL) printfC'Can't open Scompile log fileΛn"); else { ιime(&ϋmejpir); lprintf(fp, VERSION STRING); fprintlTfp, " on design '%s','\ &(*out_filejbase)rθ]); fprϊnif(fp, " %s", ctime(&timc_ptr)); fprinιf(fp, " data: %4i code: 4ϊ GSPs: %li\n", datajocs, codejocs, total gsps); fclose(fp); } //censor details! if (uncensorcd) { cerr « "SPROC Memory Utilizaιion:\n\n" « " application overhead init & othcήn" « "code " « loπn("%4d", appljcode) « " " « form("%4d", overhead_code) « " " « form("%4d\n", init_code) « "daιa " 687 -342 « form("%4d", appljiata) « " " « form("%4d\n\n", overhead_data); H return status;) II no_mem_error II extern "C" { // void abort(int); // } υut_err_hcadcr("PAR018"); cerr « "Sorry, you're out of memory'Λn"; abortO;} II switch functions II d_switch June // process "d" command line switch - define. /////////////////////////////////////////////////////////////////////////////// int d_switch unc(char* namejptr)! siring* name; siring* value; char* equalsjptr; char* valucjptr; value = (string*) NULL; // see if value given if (equalsjptr = strpbrk(namcjptr, "=")){ // null the equals to terminate the first string *equalsjpir = '\0'; value jptr = equalsjptr + 1; value = new sιring( value jptr);} name = new string(namejptr); enter_define(namc, value); return 0;} ////////////////////////////////////////////////////////////////////////////// // 1 switch func II process "t" command line switch ~ SPROC type. inl t_switchjunc(char* namejptr)! ♦ SPROC = *(ncw string(namejptr)) return 0;} If p_switch_func // process "p" command line switch - alternate directory path. //int p_switch Junc(char* namejptr) //{ // *altjpath = *(new slring(namejptr)); // return 0; //} II o_switch June // process "o" command line switch — output file base name. inl o_switch_func(char* name_ptr){ *out_file_base = *(new string(namejptr)); return 0;} II I_switchjunc // process "1" command line switch — list file name. // Filename is optional, hut linns on listing file. inl l_switchjunc(char* namejptr) { *lϊst_file = *(new string(namejplr)); makejisting = TRUE; return ();} II c_switchjunc // process "c" command line switch ~ check compile only. inl c_switchjunc(char* namejptr)! NOREF(namejptr); verify inly = TRUE; return 0; } // m_switch June // process "m" command line switch -- manual output file base name. inl m_swilchj ' une(char* naιnc ιlr){ *manj"ιle Jbase = *(new string(namejptr)); return 0; } II h ?witchj unc // process "h" command line switch -- help. int h_switchjunc(char* namejptr)! NOREF(namcjptr); . help = TRUE; return 0; } II v_swi ten June // process "v" command line switch -- verbose only. inl v_switchj " unc(char* namejptr)} NOREF( namejptr); verbose = TRUE; return 0; } II f_swi ten June // process "f cominaiul line switch -- no lilc info in error messages int f_switchjunc(char* namejptr)! NOREF(namejptr); no jile Jnfo = TRUE; return 0; } II e_switch June // process "e" command line switch - clock error %. inl e_switchjunc(char* namejptr)! clock_error = atoi(namejptr); if (clock JΪΠΌΓ >= 100 II clock_crror < 0 ){ out_err_header("PAR019"); cer « " Illegal value of " « clock 'rro « " for e swilchΛn"; M-345 return 1;} else return ();} II u _switch jfunc // process "u" command line switch - uncensor detailed statistics. int u_switchjunc(char* name_ptr){ NOREF(namejptr); uncensored = TRUE; return 0;} II s_swϊtch June // process "s" command line switch ~ suppress partitioning. int s_switchjunc(char* name_ptr)! NOREF(name_ptr); no_partilioιι = TRUE; return ϋ;} // b_s witch June // process "b" command line switch — default count before switching to // subroutine call. inl b_swilclι_lιmc(clιai "t name Hι )( deflt_subr_couni = atoϊ(namejptr); return 0;} II parser main program main(int argc, char* argvL]){ string* iπit_file; char name[MAX_NAME 5IZE]; char extensionLMAXj AME SIZE]; string makefilejiame; filebuf makefile; int status; dial liIeι ιιue[MΛXjNΛ li_SlZIi|; M-346 // char* . pathjptr; // file name stuff tdefine MΛX_RI.ES4 int njiles; char* files[MAX J^ILES]; // commands switch stuff tdefine N_S WITCHES 13 typedefint (*PTIF) (char*);// pointer to integer function static charswitcheslN SWlTCHES] = { 'D', ', O' , 'L', 'c', 'M\ 'h'Jv'. 'E', 'f'. 'u', Y, 'B' }; static PTIFswitchJuncsfN SWITCHES]; char bad_swiιch; switchjuncs[0] = (PTIF) &d_switchjunc; switch_funcs[l ] = (PTIF) &t_switch_func; // switch uncs[2] = (PTIF) &p_switch June; switchjuncsl2] = (PTIF) &o_switchJ * unc; switchjuncs|3] = (PTIF) &l_ switch June; switchj ' uncs|4| = (PTIF) &c_switchjunc; switchj"uncs[5] = (PTIF) &m_switch une; switch uncs[6] = (PTIF) &h_switch unc; switchjuncs[7] = (PTIF) &v_switchjunc; switch_funcsl8] = (PTIF) &e_switch unc; switchj ' uncs[9j = (PTIF) &f_switch_func; switch_funcsf 10) = (PTIF) &u_switchjunc; switch Juncsl I I J - (l'TII ; ) &s_swilchjunc; swiichj " uncsll2J = (PTIF) &b_switch " unc; // inii names strings to empty string - switch can update them SPROC = new stringC"'); // altjpath = new sιring(""); listjϊle = new stringC'"); outjllcjbasc = new stringC'"); manjllejbasc = new stringC'"); // set out of local memory handler setjιewjbandler(nojncm_error); // process the command line to get the input filename get_filenames(argc, argv, MAX J^ILES, &n_files, files); if (status = do_switchcs(argc, argv, N SWITCHES, switches, switch Junes, &bad_switch)) { if (bad_switch) M-347 out_err_header("PAR020"); cerr •: "You used an invalid command line switch '" « clur(bad_swiich) « '"Λn"; } exil(-slatus);} // // if no alternate path specified, try environment variable // ϊf (*altjpath == "") // ( // if ((pathjptr = getenv(DIRECTORY_ENV)) != NULL) // *altjpaιh = pathjptr; // } ϊf (njιles == O ll help)! cerr « VERSION STRING « "\n" « COPYRIGHTjSTRTNG; cerr « "Usage: SCHEDULE [-V] [-C] [-H] [-F] [-Dname[=defJ] " « "[-Ttypc] [-Ooutfile]\n" « " L-LLiisllileJJ " « "f-Eclockerror] [-Bsubrcouni] sourcefile\n"; exit(ihelp);} else strncpyfjϊlename, files[0], MAX_NAME_SIZE); // build the init file name using a potentially command line- // upplied SPROC type to concatenate ϊnil filf - iiew siriii!'!"") " . *inil_filc = *inil JHc + INITJ.ΛSF + *SPROC i "." 1 1NIT_EXT, // output tiie banner cerr « VERSIONJSTRING « "\n" « COPYRIGHTjSTRTNG; if (n_files > l){ out_err_header("PAR021 "); cerr « "You gave too many file names on the command lϊneΛn"; (-1);} //if no base name for output files supplied, use source file name if (*out_fiIe_base == "") { splilname(filename, name, extension); *out_file_base = name; // make sure we strip off any path from the file base name out Jile Jbase = strip_path(out_file_base);} // gel any path I ' loin die input file to [impend lo all input liles in_path_siring = new string(filename); M-348 in jpathjstring = gctjpaih(injpalh_siring); // makefile name lor output "make" file makefile_namc = *outJ11c_base; makefile_name = makefilejiame + ".spm"; // open makefile if (makcfile.opcn(&makefile_name[0], output) == 0){ outj3rr_header("PAR022"); cerr « "Unable to open '" « makcfile_namc « '" makefileΛn"; status = 1 ; } if (istatus) makefile_sιream_pLr = new ostream(&makefile); // compile init file . if (istatus)! if (!verify_only) status = compilc(&(*init_file)!0], FALSE);} // compile user-supplied lilc if (istatus)! if (verbose) cerr « "Compiling blocksΛn"; status = compile(fιlename, makejisting);} if (!verify_only){ tifdef LINK il ' ( slalιιs) ! if (verbose) cerr « "Creating instanccsΛn"; status = instantiateO; ) if (istatus) status = get_configuration(); if (istatus) ! if (verbose) cerr « "Connecting up instaneesΛn"; status = evaluate_and_connect(); ) if (!stalιιs) { if (verbose) 69k M-349 cerr « "Sequencing blocksΛn"; status = scquenceO; } //partition design & insert phantoms only if auto-partitioning allowed if (shouldjpartition iesignO) { if (istatus) { if (verbose) cerr « "Partitioning design.λn"; status = partitionO; // analyze zones result may not be true error if (status == NO .INPUTS) status = 0; else. status = -status; if (istatus) status = reevaluateO; } } else if (istatus) jusi_create /.oιιcs();// ignore return status, since maybe no zone if (istatus II status = NOJNPUTS) status = generate_code_and_data(); tendif} // delete the stream for the makefile to close it delete makefile_stream jptr; exit(-status);} // poststrm.cxx // post-proccessing stream class functions // Terry Montlick // /28/90 /* source code control: */ static char SccsIDU ="@(t)posιslrm.cxxl.56 10/7/91"; tinclude "poststrm.hxx" II quoter class // Class lo add quotes around an ostream which contains characters which // originally would have been quoted on input, that is, which contain special M-350 // characters. // To use, create an object in this class. Then use the in() member // function as the target of the output stream. Then use the out() // member function as the source to the desired output stream. II quoter: rquoter // Constructor. quoter::quoter(){ int i; // make stream point to array, allowing space for quotes os jptr = new ostream(QUOTE_ARRjSIZE-3, &arr[l]); // fill array with nulls which will terminate the input for (i=(); i<QUOTE_ARR_SIZE; i++) arr[i] = '\0';} //quoter: :~quoter // Destructor. quoicr::~qιιoler() { } II quoter::out() // Called afier an in() operation, this function adds quotes to stream data // if it contains non-alphanumeric characters and returns a pointer to iL char* quoter::oui(){ int i; BOOLEANadd juotes = FALSE; if (arr[l] == '\0') return &arrll]; // if first char is a number, then this is a number string, so don't add // quotes. if (arr| l | >= '()' && arr| l | <='9') return &arr| l |; // see if first char is a legal starl of identifier if ( (arrf I] >= 'a' && arr[l] <= 'z') II (arr[l] >= 'A' && arr[l] <= 'Z') M-351 II arr[Υ] == II arr[l] = '%' II arr[l] == 'J ){ // first char is legal for an identifier, so see if rest of chars ok for (i=l; arrh * ] != '\0'; i++) { if ( farr[i] >= && arr[i] <= 'z' ) II (arr[ij >= 'A && arr[i] <= 'Z') II (arr[i] >= '0' &&arr[i] <= '9') H anr[i] = T || arr[i] = '%' || arrfi] = ' J ll arr|ij = \' ) else { // not in legal set for identifier, so must add quotes add |Uoles = TRUE; break; } } else add quotes = TRUE; if (add_quotes){ arr[0] = ""; arr[strlen(arr)l = ""; return &arr[0J;} else return &arr[l];} II linebreaker class // Class to neatly break lines of an ostream. //To use, create an object in this class. Then use the in() member // function as the target of the output stream. Then use the out() // member function as the source to the desired output stream. M-352 // Iinebreaker::linebreakcr // Constructor. linebreaker::linebrcakcr(char* prefix_chars = "", int ljen = 80, int init Jen = 0){ int i; // make stream point to array os jptr = new ostrcam(BREAK_ARR SIZE-l , &arrf0]); // fill array with nulls which will terminate the input for (i=0; i<BREAK_ARR_STZE; i++) arr[i] = '\0'; // save prefix char string slrncpy(prefix, prelix_chars, PRF.FIX \RR sIZE- 1 ); // save size of prefix stirng prcfixjen = sirlcn(prefix); // save max line length line Jen = 1 Jen; // save initial line length initial Jen = iniιjen;} II lincbreakcr::~linebreakcr // Destructor. linebreaker::-linebreaker() { } II linebreaker::out() // Called aflcr an in() operation, this function breaks a line of stream data. // It looks for while space characiers and overwrites them with returns. char* linebreaker::out(){ int i.j; inl line_slart = inilialjcn; inl count = initialjcn; // scan siring, counting characters and resetting on new line for (i=0; arrlij != '\0' ; .++){ if (arr[i] == '\n') { // reset for new line M-353 Iϊne_start = ϊ + I; count = 0; } else if (count++ = linejen) { //line is loo long, so back up till wc hit while space for (j=ϊ; j>=lϊne_start; j— ) { if (arrrj] = " ll arrϋ] == '\t') . { // found white space, so make a new line. . . arrfj] = « \n'; line_start =j+l; // add die prefix string, shifting up remaining chars for (j=BREAK_ARR SIZE-ρrefixJen-1; j>=line_start; j-) arrfj ' +prefixjen] = arr[j]; //add prefix siring for (j=0; j<prefi jen; j++) arrlline_slart+j| = prefix|jj; // start new line with prefix characters count = prcfϊxjcn; i += prefix Jen; break; } } }} return &arr[0];} // poststrm.hxx // header for stream post-processing classes //T. Montlick // 3/28/90 /* source code control: @(t)poststrm.hxxI.56 10/7/91 */ tdefine POST.STREAM _DEF tifndef STAND ARD JDEF tinclude "siandard.hxx" tendif tdefine QUOTE_ARR SIZE100 tdefine BREAK_ARR_SIZE300 M-354 tdefine PREFIX_ARR SIZE30 class quoter! char arr[QUOTE_ARR_STZE]; ostream *os jptr; public: quotcrO; ~quoter(); ostream&inO { return *osjptr; } char* out(); }; class linebreaker! char arr[BREAK_ARR_SIZE]; ostream *os_plr; char prefix[PREFTX_ARR_STZE]; int linejen; int prefixjcn; int initialjen; public: lincbreaker(char* prcfix_chars, inl Men, inl initjen); -linebreakerO; ostream&inO { return *os_ptr; } char* oul(); } ; tifndef OWC// objectworks hdr is C++ tifdef sun extern "C-"// but otherwise, sun doesn't have C function prototype! telse extern "C"{ tendif tendif tinclude<string.h> tifndef OWC} tendif // schedule.cxx // scheduler class // T. Montlick // 9/1/90 /* source code control: */ static char SccsIDf] = "@(t)schedule.cxxl.56 10/7/91"; M-355 tifndef SCHEDULER_DEF tinclude "schedule.hxx" tendif II scheduler constructor iiiiifiiiiiiiiiiiififiiiiiiiifiiiriiiiiiiiiiiiiiiifiiiiiiiiiiiiiiirriiiiiifiiiii scheduler::scheduler() { inϊt_done = FALSE; njasks = 0;} iiiiiiiiiiiiiiiiiiiitiiiiiiiifiiiiiiiiiifiiiiiiiitirinifiiiiiiiiniiiiiiiiiiiii II scheduler destructor schcduler::-scheduler() { } iiifirriiiiiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiiiiifiriimimiiiiiiiiiiifiiiii II scheduler: :add_sample jperiod_and_duralion() // Add the next task, in order of execution sequence (as determined by the // compiler's block sequencing algorithm). //This task is defined by a sample period and a duration, given relative to // this particular sample period. void schcduler::add_samplejperiod_and_duraiion(long per, double dur){ original_period[njasks] = per; duration [njasks++] = dur;} If scheduler::add_connection() // Add a topological connection from task i to task j. // add_samplejperiod_and_duration() must have been called previously. //This function also verifies that the sample periods for the connections // are consistent, else it returns FALSE. BOOLEAN scheduler::add_connection(intfrom, inl to){ int i, l; long per; // make sure all fan-in tasks have same rate per = original jperiodffrom]; for (ι=0; t<njprevious(to); t++){ ϊ = prcvious(to, t); if (originaljperiodfij i= per) M-356 return FALSE;} connections[from][lo] = TRUE; return TRUE; } II schcduler::previous() // Return ihe index of the previous task in the task topology. Prcvjndex // is used to distinguish between multiple previous tasks, where 0 is the // first, 1 is the second, etc. (call n_previous() to find out total number). int scheduler::previous(int task, int prevjndex){ int i; inl count = ϋ; for (i=0; i<njasks; i++){ if (connections! i J| task j ) ! count++; if (count > prevjndex) return i; } } return -1 ;} II scheduIer::njprevious() // Return the number of previous tasks in the task topology. If init done, // we can look it up, else we must compute it. int scheduler::n_prcvious(int lask){ if (init lone) return prev_counifιask]; else return computejι_previous(task); } //////////////////////////////////////////////////////////////////////////////// // scheduler::compute_n_prcvious() // Compute the number of previous tasks in the task topology. inl schedulcr::compute_n_previous(int lask){ int i; int count = 0; for (i=0; i<njasks; i++)( i f (conncciionsfi] [ task ] ) counι++;} return count;} irifiifiiiiiiiiiiiifiifiiifiiiififiiriiiiiiiiiiffiiiiiiiiiiiiriiiiifiififiiiiiπ II scheduler::next() // Return the index of the next lask in the task topology. Nextjndex // is used to distinguish between multiple next tasks, where 0 is the // first, 1 is the second, etc. (call n_next() to find out total number). ϊnt scheduler::next(inι task, ϊnt nextjndex)! inl ϊ; int count = Q; for (i=0; i<n jasks; i++)i if (conncciions[lask][ϊ]) ! count++; ϊl~ (count > nextjndex) return i; } } i uirii - I ;} II scheduler::n_ncxt() // Return the number of next tasks in die task topology. If init done, // we can look it up, else we must compute it. ϊnt scheduler::n_ncxt(int task)! if (inϊt_done) return next_counι[task]; else return compule_n_next(lask);} // scheduler::compute_n _next() // Return the number of next tasks in the lask topology. ϊnt scheduleπ:compuiejι_next(int task)! int ϊ; int count = 0; for (i=0; i<njasks; ϊ++){ if (connectϊons[taskJlϊJ) count++;} M-358 7 °3 return count; } // gcd() // Euclid's algorithm for greatest common divisor. long gcd(long m, long n){ long r; while ( (r = m % n) != 0 ){ m = n; n = r; } return (n); } II gcd_sel() // Find gcd for a set of numbers. long gcdset(long ιrray& numbers, inl n){ int i; longjirraynums; /* compute gcd by Euclid's algorithm for each adjacent pair, which reduces the total t by one. Repeat until just one result */ for (i=0; i<n; i++) numsfi] = numbcrsfi]; while (n>l){ for (i=0; i<(n-l ); i++) ! numslij = gcd(numslij, nums[i+IJ); } n-;J return numsfO];} II lcm() // Find least common multiple for a scl of numbers. ///////////////////////////////////////////////////////////////////////// long lcm(longjιrray& numbers, inl n){ int i; long multiple; BOOLEANnot Jound = TRUE; // use brute force method for now multiple = 1 ; SUBSTFTUTE SHEET while (notj ' ound)! notjound = FALSE; for (i=0; ϊ<n; i++) { if (multiple % numbersLϊ]) ! notjound = TRUE; break; } } if (notjound) multϊple++;} return multiple; } II scheduler::add Jem poral jask() // Called by schedulcr::iniι_counters(), this function adds a task to the // scheduler for temporal partitioning. It returns the last task number // added. ϊnt scheduler::add jemporal jask(double sum, int task, int *n_ptr) ( double total; int gsps; // if beyond last lask, all done if (task >= njasks){ gsps = (inl) (sum + 0.99999999); *n_ptr = gsps; return (task-1);} // add this task total = sum + duration[task]; gsps = (int) (total + 0.99999999); // see if wc have filled last gsp sufficiently if ( (gsps - total) < headroom ){ *n_ptr = gsps; return lask; } else // haven't filled sufficiently, so add next lask return add Jem poral jask(totaI, task+1, n_ptr);} II scheduler::ϊnϊι_counters(} M-360 // Compute the initial counter values for the scheduling algorithm. // These initial values are loaded into the SPROC task scheduling // counters used to do run-time scheduling. void schcduler::init_counters(){ int i, j, k, n; int task, firstjask, lastjask; long longest; long base; long_arraylcm_array; // figure out which gsp lask should go on n jsps = 0; lust_la.sk - 0; while (firstjask < njasks){ // try lo add tasks for lemporal partitioning lastjask = addjemporaljask(0.0, firstjask, &n); // we have allocate "n" gsps for (task=firstjask; task<=lastjask; task++) ! // place this task in all gsps consumed for (k=nj>sps; k<(n_gsps+n); k++) which jsp[task][whieh_gsp[taskj.sizc()j = k; } // if schedule is more than one gsp, set as temporally partitioned if (n > I ) ( // find least common multiple period for this group of tasks for (task=firsijask; task<=lasi ask; task++) lem jirrayl task-first JaskJ = periodllaskj; longest = lcm(lcm_array, lastjask-firstjask+1 ); // set reload count based on longest period for (la.sk=lirsijask; iask<=lasljask; lask++) rcload_count| lask] = longcsl/pcriodllaskj; // record as temporally partitioned for (k=n_gsps; k<(n jsps+n); k++) ! isjemporalfk] = TRUE; // set initial lask to run previous _ιask[k] = firstjask; 3/08524 706 M-361 // every gsp past 1st in series is a "chaser" if (k > n sps) ϊs_chaser_gsρ[k] = TRUE; } ) n_gsps += n; firstjask = Iastjask+1;} // set a counter for each task for each gsp for (j=0; j<n jsps; j++) { base = 0; for (i=(); i<n jasks; i++) { // init max iuc counter max_due[i] = 0; // init counter // if this is single gsp, then we arc doing interlieved scheduling // so whenever interpolation is done wc must update a "base" // initial count so that interpolation counter wails until // previous sample is available if ( iisjemporalfj] && (njprevious(i) > 0) ) ! // interpolating if current not divisible by previous if ( reload _count[i] % reload_count[previous(ϊ,0)] ) // if (reload_count[prevϊous(i,0)]/reload_count[i] > 1) base = counier[j][previous(i,0)]; ) counicrl fj[ϊ] = base + reload iounϋ J; // init due counter duefj][ϊ] = 0; } } // compute utilization fraction based on t of gsps utilization = iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiininiiiiiiiiiiniiiiiiiiiiiiiitiiiiiin II scheduleπxompuiejperiodsO //Compute the period for each scheduler task, returning the GCD of the // periods. If unable to compute the periods, return 0. iifiiiiiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiiiiiifiiiiiiriniiriiiiiiiiiiiiiiiiiiiiii lon scheduler::computejpcriodsO{ int i; M-362 long gcdjperiod; double sum; BOOLEANfoundJt = FALSE; // this is a good time to count the next and previous tasks in the // network lopolυgy for (i=0; i<njasks; i++){ next_count[i] = compute_n_ncxt(i); prev_count|i] = compute_n_previous(i); } // first normalize the original periods by their GCD gcdjperiod = gcdset(originaljpcriod, njasks); for (i=0; i<n Jasks; i++) periodl i | = original jperiod| i |/gcd jperiod; // find smallest multiply integer for the .scheduler periods such that the // sum of their inverses is 1 or less schcduler_rate = 1 ; do{ sum = 0.0; for (i=0; i<njasks; i++) sum += 1.0/(schedulerjate*pcriod[i]); if (sum <= 1.0) found Jt = TRUE; else schcdulcr_rate++; } while (ifoundji); // now compute ttue period at average scheduler rate // also sum task limes for utilization utilization = 0.0; for (i=0; i<njasks; i++){ period[i] = scheduler ate * periodfij; reload_counlfi] = periodp]; utilization += durationfi]; } inil_couιιleιs(); inil lone = TRUπ; return (gcdjperiod); } // scheduler::geijιexi ask() // Get the next task from the scheduler. // This algorithm is implemented on the SPROC for run-time scheduling. 70S M-363 inl scheduler::gci_nexLjask(int gsp) { int nextjask = NOJTASK; ϊnt i; int most_due_count; BOOLEANnotJoundjiext; BOOLEANgo_ahead =TRUE; if (ϊsjemporaltgspj) { ϊ = previousjaskfgsp]; // if first count for this task, decrement previous gsps ahead count if ( (coimtcrlgsplfϊ] == reload jJounl[i]) && is_chascr_gsp[gsp] ) ahead_counl[gsp- 11--; // assume repeating cuπ-ent lask next_lask = ϊ; // if counter is 0, then we should advance task, but first make // sure next gsp is ahead by at least one task if (countcrfgsp][ϊ] = 0) ! // is next gsp ahead by at least one task? if (is_chaser gsp[gsp]) { if (!(ahead_count[gsp-l] >= I)} gojihead = FALSE; } } if (gojihead) ! if ("C unier[gsp][i] == 0) { // finished with this task, so advance to next // reload counter for this task counter[gsp][ϊ] = reIoad_countfi]; alιead_cotιnl|gsp|++; notj und iext = TRUE; while (notjoundjiext) ! ϊ = (i+1) % njasks; if (which _gsp[i].find(gsp) >= 0) ! prevϊousjask[gsp] = i; notj ' oundjiext = FALSE; } } } } else // don't have go-ahead, so tell caller next ask = WAITJTASK; } else! // spacial partitioning while (next_ta.sk == NO_TA.SK) { // see which task is most due - this is the next task to run mosi_due_count = 0; for (i=0; i<n jasks; i++) ! if (whicli_gsp[i].tind(gsp) >= ϋ) ! if (due[gsρ][i] > 0) ! if (duc[gsp][i] > mos i_duc_count) ! nextjask = i; most_duc_count= duefgsp][i]; } // if a task was selected, decrement its due count if (nextjask != NO_TASK) duetgspjf nextjask]--; // decrement modulo counts for (i=(); i<n jasks; i++) ! if (which_gspfi].find(gsp) >= 0) ! if (— countcr[gsp][i] == (J) M-365 counter[gsp][i] =reload_count[i]; duc[gsp][i]++; // max_due is maintained purely for accounting purposes if (duefgsp][i] > max_due[i]) max_due[i] = due[gsp][ϊ]; } } return (nextjask);} // schedule.hxx // scheduler class //T. Montlick // /1/90 // source code control: @(t)schedule.hxxl.56 10/7/91 tdefine SCHEDULER )EF tifndef STRING j EF tinclude "string.hxx" tendif tifndef LONG_ARRAY_DEF tinclude "loπg_arr.hxx" tendif tifndef INT_ARRAY_DEF tinclude "int irr.hxx" tendif tdefine BOOLEANshort tdefiiicTRUE 1 tdefineFALSE 0 tdelineINFINlTY99999999999 tdefine NO TASK-l tdefine WAITJTASK-2 tdefine MAXJTASKS100 tdcfϊneMAX_GSPS32 /' • The scheduler class is first passed the headroom allowable for spacial partitioning (expresses as a fraction of one sample period) via a call to scheduleπrse tJieadrυomO. This is the amount of "wasted processing power" that is tolerated for a gsp in spacial partitioning. Sequential lasks are placed on a gsp until the next task will not fit on the gsp. If ihe amount left over on that gsp is less than the headroom allowed, then the remaining tasks are spacially partitioned onto other gsps. If the amount left over on that gsp is greater than or equal to the headroom allowed, then the next gsp is enlisted for temporal, rather than spacial partitioning. A headroom value of zero forces purely temporal partitioning. The class is then given a sequence of sample periods and lask durations, relative to a sample period (via schedulcr::add_sample_pcriod_and_duration()), one for each task in a sequence of decimated and/or interpolated tasks. scheduler::add_connection is called for each pair of topologically adjacent tasks. scheduler: :compute_periods() is then called lo create the scheduler sequence. The scheduler period for each lask counter can then be read via schcdulcr::gcl_sclιedtιlcrjperiod(), and initialization values for counters read by calls to schcduler::geι_counter_valuc(). To run the scheduler, call scheduler::gct_nextjask(), which returns ihe next lask number, starting from 0, to run, or the negative value NOJTASK if no task for this scheduler slot. */ class scheduler! longjirray original_period; longjirray counter[MAX_GSPS]; inljirray isjemporal;// TRUE if gsp is temporally partitioned int_array previou jask;// last tasks for temporally part, gsps int_array connections! MAXJTASKS];// TRUE if connection from i to j longjirray period; long_array rcload_count; inljirray is_chaser_gsρ;// TRUE if temp. part, gsp chases another int_array ahead_count;// tasks which next gsp ahead - lemp. part inljirray which_gsp[ MAXJTASKS]; double duration! MAXJTASKS]; int_array due[MAX_GSPS]; int_array maxjJue; inl n jasks; inl irray ncxi -ouni; // pre-compuled coiini of next in topology inljirray prcv_cυunt; // pre-compuled count of prev in topology int n_gsps; double utilization; int scheduler ate; double headroom; // max headroom on gsp for lemp. part M-367 BOOLEAN init_done; // TRUE when init phase completed private: void ϊnii_counters(); int compute_n_prevϊous(int task); int compuιe_n_nexi(int task); . int add_lemporal_task(double .sum, inl lask, int *n_ptr); public: schedulerO; ~scheduler(); void set_headroom(doubIe h){ headroom = h; } void add_sample_period_and_duraiϊon(long per, double dur); BOOLEANadd_conncction(ϊnt ϊ, int j); long compιιie_pcriods(); int get_njasks(){ return n jasks; } int get_n_gsps()! return n sps; } long gel_counicr_vaIuc(int i){ return counter[0][i]; } long gct_scheduler_pcriod(int i){ return periodfi]; } long geιjemporal cpeats(int i){ return period [ψschedulerjate; } ϊnt get_which_gsp(int i, int j){ return which _gsp[i]fj]; } ϊnt n_gsps_for_task(int i){ return which_gsp[i].sizeO; } int gct_scheduler atc()! return scheduler_rate; } int get_nextjask(int gsp); int gct_max_due(int i) { return max_due[i]; } double ge _utiIϊzaiϊon() { return utilization; } int previous(ϊnt task, int prcvjndex); ϊnt n_previous(int task); int nexι(int task, int nextjndex); int n_next(int lask); B OLEANaJirsljask(inl i){ return (njιexl(i) && !n_prcvious(i)); } }; // misc functions: long gcd(long m, long n); long gcdset(long_array& numhers, int n); %{ struct string*define_name; struct .string*define_val; struct surϊng*include_file; %) -368 %START NORMAL COMMENT DEFINE DEF ONTIN DEF_VAL INCLUDE a [aA] b fbB] c fcC] d [dD] e [eEl f I IF] g IgG] h [hH] i UI] j [ill k [kKJ I | I | m [mMJ n fnNJ 0 |oO] P [pPl q [qOJ r [rR] s [sS] t [IT] u luUJ v [vV] w fwW] x IxX] y [yY] Λ |zZj %k 2000 %e 2000 %p 4000 %{ tinclude <stdio.h> tinclude <clype.h> tinclude "ficids.h" tinclude "standard.h" /* interface to C++ data structures */ tinclude "intrface.h" /* general utility routines */ tinclude "utility.h" 71 -369 tϊfdef DOS/* DOS can't handle standard yacc filename */ tinclude "ytab.h" telse tinclude "y.tab.h" tendif /* source code control: */ static char SccsIDϋ = "@(t)sdUexl.56 10/7/91"; %} %% <NORMAL>[ \t]; /* skip delimiter characters */ <NORMAL>\n linc++; /* skip newline but advance line count */ <NORMAL>"//".*Λn; /* skip comment to end of line */ <N RMAL>'7*"BEGIN COMMENT;/* enter comment slate */ <COMMENT>\n Iine++; /* skip newline but advance count */ <COMMENT>. ; /* ignore other chars */ <COMMENT>"*/"BEGTN NORMAL;/* exit comment state */ <NORMAL>"t"define[ \l]*BEGIN DEFINE; * enter define state */ <DEFINE>[a-zA-Z$%J[a-zA-Z$%0-9J*{ /* create a strin Όg for the define name. definejiame = new_string(yytext); define_val = new_string(""); BEGIN DEFJVAL;/* enter define value state */ } <DEFINE>. BEGIN NORMAL;/* exit define - no name */ <DEF_VAL>.+\\${ /* line continuation character at end */ /* just add to existing value without leaving state */ yyiext[yyleng-l] = '\0 * ;/* write null over 4 V*/ definc_val = concat_sιring(define r'al, new_string(yytext)); BEGIN DEF ONTIN;/* continue state till cr */ <DEF_CONTIN>\n{ Iine++; BEGIN DEF_VAL; } M-370 <DEF_VAL>.+ { deline_val = concat_string(define_val, new_string(yytext)); } <DEF_VAL>\n { /* bump line count */ linc++; enter_definc(define_name, define_val); BEGIN NORMAL;/* exit define value state */ } <NORMAL>"t"include[ \t]* BEGIN INCLUDE;/* enter include state */ <lNCLUDE>\"[ Λ "\n]*\"{ /* get the name of ihe include file. */ char *name_ptr; /* write null over last ", and skip first one */ yytextfyylcng-1] = '\0'; name_ptr = &yytext[0] + 1; /* get string for include file */ includc_file = new_string(name_ptr); /* push current file on stack and open this one */ if (!push_file(include_file, &i nclude Jile)) ! c or_w_string("LEX001", "Unable to open include file '", includejile, "'."); exit(-l); } BEGIN NORMAL;/* return to normal state */ } <NORMAL>{a}{s}{m}{b}{l}{o}{c}{k}return(ASMBLOCK); <NORMAL>{s}{e}{q){b}{l}{o}{c}{k}return(SEQBLOCK); <NORMAL>{m}{a}(n}{b}{l}{o}{c}{k}return(GSPBLOC ); <NORMAL>{s}{u}{b}{r}{b}{l}{o}!c}{k}rcturn(SUBRBLOCK); <N () RMA >{c}!a}(ll{l)!b}{l}{o}(c}(k}rclurn(CALLBLOCK); <NORMAL>{b}(l}{o}{c){k}rcturn(BL CK); <NORMAL>{b}{e}{g}!i}{n}reiurn(BEG); <NORMAL>{e}{n}{d} relurn(END); <NORMAL>{i}{n}{p}{u}{t}return(INPUT); <NORMAL>{m} {i} {c} (r) (o}return(MICRO); M-371 <NORMAL>{o}{u}{t}{p}!u}{l)return(OUTPUT); <NORMAL>!w} {i} {r} !e}return(WIRE); <NORMAL>{v} !a} {r} {i}!a} {b} {1} {e}return(VARIABLE); <NORMAL>!p} {a} {r} {a} {m } return (PARAM); <NORMAL>{s}!y}{m}!b}{o}{l}return(SYMBOL); <NORMAL>!d}!u}{r}!a}{t}{i}{o}!n}return(DURATION); <NORMAL>!a}{l}{i}!a}{s}returπ(ALIAS); <NORMAL>{v} {e} {r} {i} {f} {y)return(VERIFY); <NORMAL>!v}{i}{r}{t}{u}{a}{l}rcturn(VIRTUAL); <NORMAL>{o)!r}{g} return(ORG); <NORMAL>{p}{h} {a} {n} {t} {o} {m}return(PHANTOM); <NORMAL>{i} {n} {i} {t}rcturn(INIT); <NORMAL>{l) {i} {m} {e} {-/.} {o} {n} {c}return(TIMEZONE); <NORMAL>{p}{o}{r}{i}reiurn(PORT); <NORMAL>{g}!p}{i}{o}reιurn(GPIO); <NORMAL>{r}{t}{s} return(RTS); <NORMAL>{c} {o} {m} !p} {u} { t} {e} {1} {i} {n} {e} return(COMPUTELINE); <NORMAL>{d}{o}!w}{n}{s}{a}{m}{p}{I}{e}return(DECIMATE); <NORMAL>{u} !p}!s} {a} {m}!p} {I}!e} return(INTERPOLATE); <NORMAL>{ a} ! d } { d } return(ADD); <NORMAL>{a}!d}{c} return(ADC); <NORMAL>{a}{n}!d} return(AND); <NORMAL> { a } { } { I } return(ASL); <NORMAL>{a}{s}{r} return(ASR); <NORMAL> { c } { I } { c } rcturn(CLC); <NORMAL>{c} {m} {p} return(CMP); <NORMAL>{d} fj} {n} !e}return(DJNE); <NORMAL>{x} {υ} lr} reLurn(EOR); <NORM AL> {j } { m } { p } relurn(JMP); <NORMAL>{j}{c}{c} return(JCC); <NORMAL>{j} {c} {s} return(JCS); <NORMAL>{j} {e} {q} relurn(JEQ); <NORMAL>{ j } { 1 } { f ) reiurn(JLF); <NORMAL>{ j} {m} {[} return(JMF); <N RMAL>{j} {o} { v} return(JOV); <NORMAL> { j } { } { i } reiurn(JSl) ; <N RMAL>{ j } { z} { } reιurn(JZE); <NORM AL> { j } { } [ c } return(JGE); <NORMAL>{j } { I } {e } return(JLE); M-372 <NORMAL> j}{g}{t) return(JGT); <NORMAL> } { 1 > { } return(JLT); <NORMAL> j}{n}{e} return(JNE); <NORMAL> I}{b){s}{j}rcturn(LBSJ); <NORMAL> l}{d}(a) return(LDA); <NORMAL> !}{d){b} relurn(LDB); <NORMAL> l){d}{c}{c}return(LDCC); <NORMAL> l}{d}{d] rcturn(LDD); <NORMAL> l}{d}{w}{s}return(LDWS); <NORMAL> l){d}{f} return(LDF); <NORMAL> l|{d}{l) rctιιrn(LDL); <NORMAL> !}{d}{x) return(LDX); <NORMΛL> l)[d}|y) relum(LϋY); <NORMAL> m}{a}{c} return(MAC); <NORMAL> m}{p}{y} return(MPY); <NORMAL> n}{o}{p} return(NOP); <NORMAL> n}(o}{t} return(NOT); <NORMAL> o}{r}(a} return(ORA); <NORMAL> s}{e}{c) return(SEC); <NORMAL> s}{u}{b} return(SUB); <NORMAL> ι){b){c}rcturn(SUBC); <NORMAL> a} return(STA); <NORMAL> b) return(STB); <NORMAL> d) return(STD); <NORMAL> w}{s}return(STWS); <NORMAL> f} reιurn(STF); <N ( )R Λ > I j ιcitιπι(STL); <NORMAL> m}{h}return(STMH); <NORMAL> m}{l}rciurn(STML); <NORMAL> m)(g}return(STMG); <NORMAL> m}(h}{i}return(STMHI); <NORMAL> m}{l}{i}return(STMLI); <NϋRMAL> }{g}{i}return(STMGl); <NORMΛI.> b)lsjιelιιm(STBS); <N()RMAL> x} rcturn(STX) <N()RMAL> y} return(STY) <N RMAL> |0| 11} return(ROL) <NORMAL> |o)(r} return(ROR) <NORMAL> w}{f) return(JWF) M-373 <NORMAL>{x} !l} !d) return(XLD); <NORMAL>A return(A); <NORMAL>B return(B); <NORMAL>D rciurn(D); <NORMAL>F rcturn(F); <NORMAL>L rcturn(LL); <NORMAL>BS return(BS); <NORMAL>WS return(WS); <NORMAL>X return(X); <NORMAL>Y return(Y); <NORMAL>MLreturn(ML); <NORMAL>MHreltιrn(MH); . <NORMAL>MGreturπ(MG); <NORMAL>MLIreturn(MLI); <NORMAL>MHIreturn(MHl); <NORMAL>MGIrcturn(MGI); <NORMAL>{i} {n} {t}reiurn(INT); <NORMAL>{f} {i} {x}rcturn(FIX); <NORMAL>{!} {o} !g}return(LOG); <NORMAL>!e} {x} {p}return(EXP); <NORMAL>"&&"return(L_AND); <NORMAL>"H"rciurn(OR); <NORMAL>"i" return(NOT); <NORMAL>"="relurn(EQ_EQ); <NORM AL>" i="retum(NOT_EQ); <NORMAL>"<="return(LT_EQ); <NORMAL>">="reLurn(GT_EQ); <NORMAL>"»"rcturn(R_SHIFT); <NORMAL>"«"return(L_SHIFT); <NORMAL>{i} {n} !t} {e} {g}{e}{r}return(INTEG); <NORMAL>{f}{i}!x} {e} {d}return(FIXED); <NORMAL>{h} {e} {x } return(HEX); <NORMAL>[a-zA-Z$%Jf -zA-Z$%0-9J*! /* found an identifier, so * create a character string, and return pointer * to it as the value of yylval */ char *val; int length = 0, i; M-374 char*p; yylval.string_ptr = new_string(yytext); /* first look to see if its a defined name */ if (find_define(yylval.stringjptr, &val)) { /* found the identifier, so substitute value */ p =&val[0]; /* first count the length of the string */ while (*p++ != '\0') lenglh++; /* push the string back on the input stream */ for (i=— length; i>=0; i-) { uπput(val[i]); else return(IDENTlFIER); } <NORMAL>\"[ Λ "\n]*\"{ /* string — * handle same as identifier, but strip off quotes */ char *val; int length = 0, i; char*p; /* write null over last ", and skip first one */ yytext[yyleng-l] = '\0'; val = &yytext[0] + 1; yylval.stringjptr = new_string(val); return(STRlNG); <NORMAL>\'l Λ, \nJ*\' | /* single-quoted string is same -- * handle same as identifier, but strip off quotes */ char *val; int lenmh = 0, i; M-375 ch'ar*p; /* write null over last ", and skip first one */ yytext[yyleng-I] = ΛO'; val = &yytext[0] + 1; yylvaLstringjptr = new_string(val); return(STRING); \ <NORMAL>[0-9]+{ yylvaUval = atol(yytext); return(INTEGER); ) <N RMAL>[0-9|+"."fO-9|*f . yylval.rval = atof(yytcxt); return(REAL); } <NORMAL>"."fO-9]+{ yylval.rval = atoffyytcxt); return(REAL); } <NORMAL>[0-9]*("."[0-9]+)?[Ee][-+l?[0-9]+{/* scientific notation number */ yylval.rval = atoffyytext); reiurn(REAL); } <NORMAL>[0-91[0- A-Fa-fI*[Hh]{/* hex number */ char *p, c; yylval.ival = 0; for (p=yytext; myJoupper(*p) != 'H'; p++) { c = myjoupper(*p); yylval.ival *= 16; if ((c >= 'A') && (c <= c F)) yylval.ival +=c - 'A' + 10; else yylval.ival += c - '0 T ; rcturn(INTEGER); } <NORMAL>[0-ll+[Bb]{ /* binary number */ char *p, c; M-376 yylval.ival = 0; for (p=yytext; my_toupper(*p) != 'B'; p++) { c = *p; yylval.ival *= 2; yylval.ival += c - '0'; } rcturn(INTEGER); } <NORMAL>. rcturn(*yytcxt);/* return any other char */ ( liGIN NORMAL; ιιnput(*yytexl); } \n ■ { BEGIN NORMAL; unput(*yytext); } %% I* routine to sync to next input line */ resynch(){ char c; while (c = inpulO) if (c == '\n') { line++; break; } ) tinclude <stdio.h> tinclude <ctype.h> tinclude "ficlds.h" tinclude "standard.h" /* interface to C++ data structures */ tinclude "intrface.h" /* general utility routines */ //include "iiiilily.h " /* source code control: */ static char SccsID[J = "@(t)sdl.yac l.56 10/7/91"; /* fields in the current instruction being assembled */ int opcode; int addr_mυde_ficld; inl operandjϊeld; int temp; -377 int relocjype = ABSOLUTE;/* relocation type for operand, if known */ struct expr*arr_size;/* size expr. for a variable which can be an array NULL implies size of I */ char storagejype;/* current storage type in declaration */ BOOLEANmicro; /* TRUE if variable is a micro interface variable */ /* tdefine YYDEBUG don't define for newest SUN OS */ %} %start sdl %union{ struct expr* in l_consi; struct expι * *i'eal - * onsl; siruci expr*sym_cxpr; struct siring*strϊng_ptr; struct arg_sct :,= arg_set_ptr; long ival; double rval; BOOLEAN bool;} /* declarations for Ihs */ %type <rcal_const> reaI_constant %type <sym_expr> expression %typc <sym_expr> sym_cxprcssion %typc <sym_expr> int_cxpression %type <ϊnt_const>int_constant %type <string_ptr>jmp_address %type <string_ptr>symhoI %type <sym_cxpr>n_elemenιs %type <sym_expr>opt_size_spcc %type <arg_set_pιr>opt_param Jist %lypc <arg_scljpir>inslancc_portJist %lypc <string_plr>block_rcf_namc %type <string_pir>inslance_name %type <.siπng_ptι>identilιcrj njstriiig %type <bool>opt_micro /* operator precedence */ %leftlNT %left FIX %IeftOR %left L_AND %lefι T M-378 %left ' Λ ' %left '&' %Icft E _EQ N T_EO . %left LT_EQ GT_EQ '<' '>' %left L_SHIFT R_SHIFT %left '+' '-' %left '*' V lcft LOG EXP %Ieft UMINUS '-' NOT tokcnASMBL CK %tokenBLOCK %lokcn SEQBLOCK %tokenGSPBLOCK tokenSUBRBLOCK %lokcnCALLBLOCK %tokenBEG %tokcnEND %token<string ptr>IDENTIFIER %token<string_ptr>STRING %tokenINPUT %tokenOUTPUT %tokenWIRE %tokcn VARIABLE %tokenPARAM tokenSYMBOL %lokcnDURATION %lokenALIAS %tokenVERIFY %lokcnVIRTUAL %tokenORG %tokcnPHANTOM %lokeπlNIT tokenMTCRO %tokenTIMEZONE %tokenPORT %tokenGPIO %tokenRTS αtokenCOMPUTELINE %>tokenDECIMATE M-379 %tokenINTERPOLATE %tokenEQ_EQ %tokenNOT_EQ %tokenLT_EQ %tokenGT_EQ %tokenL_SHIFT 7otokenR_SHIFT %tokenL_AND %tokenOR %tokcιιN()T %token <ϊval> INTEGER %loken <rval> REAL /* opcodes */ %tokenADD %tokenADC %-iokenAND %tokenASL %tokenASR %lokenCLC %token CMP %tokenDJNE %ιokenEOR %tokenlMP %tokenJCC %tokenJCS %tokeπ JEQ %tokenJLF %tokenJMF %lokenJOV %tokenJ I %lokcnJZE %tokenJGE %tokenJLE %lokeπJGT %tokenJLT %lokenJNE %token LBSJ %tokenLDA %tokenLDB M-380 725 %tokenLDCC %token LDD %tokenLDF %tokenLDWS %tυkcnLDL tokenLUX %tokenLDY %tokenMAC %tokenMPY %tokenORA %tokenSUB %lokcnSUBC XlokenSTA %tokenSTB %tokenSTD lokenSTF %lokenSTWS %tokenSTL %tokenSTMH %tokenSTML %tokenSTMG %tokcnSTMHI %tokenSTMLI %tokenSTMGI lokcnSTBS %lokenSTX %lokcnSTY %tokcnNOP %tokenNOT %tokcnROL %tokenROR %lokenSEC %token XLD %lokenJWF /* source registers */ %tokenA %tokcnB %tokenD % token F SUBSTITUTE SHEET /* don't use * L * because it screws up defines of Long constants! */ %tokenLL %tokenBS %tokenWS %tokcnX lokenY %tokenML %tokenMH %token MG %tokenMLI %tokenMHI %token MGI /* storage types */ %ιokenFIXED %tokenTNTEG %tokenHEX %% sdl : /* null */ I blocks » blocks : block I blocks block bloc : hierarchicaljilock I prϊmitive_bIock I sequence_block I gsp_block I subr_block I call block ; hϊerarchϊcal_bloc : hϊer_block_start param Jist portjist hier_declarations BEG hier _body END ( if (lcnd_of_blυck()) { other_error("YAC001", M-382 7 ∑ ? "IO for this block has not been declared."); YYERROR; } pi iinilivc Mock : asm_block_start param Jist portjist asm_declarations BEG asm_body END { if (!finish_asm_block()) { olhcr_error("YAC002", "Couldn't successfully compile this block."); YYERROR; } if (!cnd_of_block()) { other_crror("YAC001", "IO for this block has not been declared."); YYERROR; subr tlock : subr_block_start param Jist portjist asm lcclarations BEG asm Jiody END { if (!finish_asm_block()) ( other_error("YAC002", "Couldn't successfully compile this block."); YYERROR; } if (!end_of_block()) { oιher_error("YAC001", "IO for this block has not been declared."); YYERROR; call_block : call >Iock_siart paramjist portjist asm_decIarations BEG asm Jnody END { if (!finish_asm_block()) { other_error("YAC002", "Couldn't successfully compile this block."); YYERROR; } if (!cnd_of_biock()) { other_crror("YAC001", "IO for this block has not been declared."); YYERROR; \ } sequence_bIock : seq_block_start paramjist portjist hier_declaratϊons BEG hier_body END { if (!end_of_block()) { oιher_error("YAC001", "IO for this block has not been declared."); YYERROR; • } sp jblock : gsp_block_siart paramjist portjist hicr_dcclarations BEG gsp_body END { ϊf (!end_of_block()} { other_crror("YAC001", 'TO for this block has not been declared."); YYERROR; } -384 hicr_block_start : BLOCK υιhcr_error("YAC003", "You must give an instance name."); YYERROR; BLOCK IDENTIFIER new_hier_block(); if (!sct_block_name($2)) error_w_string("YAC004", "A block named '", $2,"' already exists."); YYERROR; scq_blυck_start : SEQBLOCK other_eriOr("YAC003", "You must give an instance name."); YYERROR; ) SEQBLOCK IDENTIFIER { new_seq_block(); il ' ( !sel_Mock_name($2)) { crrυr_w_slring("YAC004", "A block named '", $2,'" already exists."); YYERROR; } gsp_block_start : GSPBLOCK other_crror("YAC003", "You must give an instance name."); YYERROR; M-385 } I GSPBLOCK IDENTIFIER { new_gsp_bIock(); if (isc i_bIock_name($2)) ( error_w_string("YAC004", "A block named '", $2,'" already exists"); YYERROR; } } asm_bIock_start : ASMBLOCK { oiher_crror("YAC003", "You must give an instance name."); YYERROR; } ASMBLOCK IDENTIFIER { new ιsm_block() ; if (!set_block_name($2)) { error_w_string("YAC004", "A block named '", $2,"' already exists."); YYERROR; else extern struct string* new_string(); /* create a label called "Sstart" for the start of code */ addjabel_namc(ncw_sιring("$start"), instijnumberO); } subr_block_sιart : SUBRBLOCK { othcr_error("YAC003", "You must give an instance name."); M-386 YYERROR; } I SUBRBLOCK IDENTIFIER { iiew subr . blockO; if (!sct_block_name($2)) { error_w_string("YAC004", "A block named "', $2,'" already exists."); YYERROR; } else { extern struct string* new_string(); /* create a label called "Sstart" for the start of code */ add_labcl_name(new_siring("$start"), instijnumberO); } } ealI_block_slarl : CALLBLOCK { other_error("YAC003", "You must give an instance name."); YYERROR; CALLBLOCK IDENTIFIER new_call_block(); if (!sct_block_name($2)) error. w_string("YAC004", "A block named '", $2,"' already exists."); YYERROR; else extern .struct string* new_string(); /* create a label called "Sstart" for the start of code */ add_label_name(new_string("$start"), instr jiumberO); 3/08524 732 M-387 port_Iist : /* null */ I T V I '(' ports ')' > ports : labeledjports I implicϊtjports Iabeled_port : port_spec 1 ports ';' port_spcc impIicit_ports: inputs ';' I inputs *■ ;' outputs I ';' outputs > port_sρec : iπput_ports I outputjports inpuljport : INPUT inputs inputs : input I inputs input input : opt_micro IDENTIFIER opt_size_spec { /* allocate I/O offset with this name */ if ([addJo_name(S2, &temp, $D) { error _w_string("YAC005", "An input or output name '", M-388 $2, "' already exists."); YYERROR; /* set size for 1/ϋ with this name */ if (!scl Jo_si/.e_aικl_direcιion($2, $3, FALSE)) { error_w_string("YAC006", "An I/O port named '", $2, "' has not been declared."); YYERROR; output_ports : OUTPUT outputs outputs ; output I outputs 7 output » output : optjnicrυ IDENTIFIER υpι_si/.c_sρcc { /* allocate I/O offset with this name */ if (!add_io_name($2, &temp, $1)) { error Λ_siring("YAC005", "An input or output named '", S2, "' already exists."); YYERROR; } /* set size for I/O with this name */ if (!sct_io_size_and_direction($2, $3, TRUE)) { error_w_string("YAC006", "An I/O port named '", $2, '" has not been declared."); YYERROR; optjnicro IDENTIFIER opι_size_spec '=' expression 7 ^ M-389 /* allocate I/O offset with this name */ if (!addJo_name($2, &temp, $1)) { crror_w_siring("YAC005", "An input or output named "\ $2, '" already exists."); YYERROR; } /* set size for I/O with this name */ if (!setJo_size_and_direction($2, $3, TRUE)) { error _w_strϊng("YAC006", "An VO port named '", $2, "' has not been declared."); YYERROR; } /* set initial value for I/O (psuedo-sampled output) */ setjojni ι_yalue(iemp, $5); } optjnicro : /* optional interface declaration for micro interface */ /* null */ { $$ = FALSE; MICRO = TRUE; paramjist : /* null */ { finish_addϊng_params(); I T * } fϊnish_addϊng_ρaramsO; } params '}' { M-390 linish_adding_params(); params : param I params ',' param param : param lcf I param_valuc_def > param_def : identifier or strins /* enter NULL as value for this name */ if (!add_expression_name($l , NULL)) ( error_w_string("YAC007", "The parameter or variable "', $1, "' is already defined."); YYERROR; ) if ( !add_param_name($ 1 , &lemp)) { error Λ_string("YAC () 08", "A parameter named * ", $1, "' already exists."); YYERROR; } param_value_def : identifier_or_string '=' expression { /* enter expr as value for this name */ if (!add_expression_name($l, $3)) { eιτor_w_string("YAC009", "The parameter '", $1, * " is already defined."); YYERROR; } M-391 if (Iadd_param_name($l, &ιemp)) { error _w_string("YAC0()8", "A parameter name °\ $1, "' already exists."); YYERROR; } } asm_decIarations : /* null */ I asmjleclarationjist > asm_declaration Jist : asm_decIaration I asmjJeclaration Jist asm_dcclaraιion asm_declaratϊon : variabIe_dccIaration I symbol_dcclaralion I duration_decIaration 1 alias_declaration I verify_dcclaration I org_dcclaralion I phantom leclaration I virlual_declaraiiou I init_declaration I limezone ieclaraiion I port_dcclaration I compuie_decIaration I dccimaie_declaration I inte θlate_dcclaralion I error ';' » hier_declarations : /* null */ I hier lcclaratϊonjist hier_dcclaraιion_lϊst : hier_declaration M-392 I hier_declaration_lisi hicr_declaration » hier_declaraιion : wirejlcclaialioii I variable_declaration I symbol leclaraiion I alias_declaration I verify_declaration I phantom leclaration I virtual_declaration I init_declaration I error ';' » wire_declaration : wire_type_declare wire_dcfs ';' » wire_type_declare : optjnicro WIRli FIXED { storage _type = T; micro = $1; } I optjnicro WIRE INTEG ( storage Jypc = V; micro = $1; ) I optjnicro WIRE HEX { storagejype = 'h'; micro = SI ; } I optjnicro WIRE { storagejype = ' '; micro = SI; variable leclaraiion : M-393 var ype_declare var_defs ';' » symbol_declaration : symbol Jype_declare symbol_defs ';' symbol_type_declare : opt_micro SYMBOL { micro = $1; } duratϊon_declaration : DURATION int_expressϊon ';' { if (!set_duration($2)) { other_error("YAC010", "A duration for this block has already been declared."); YYERROR; } } decimate_declaration : DECIMATE int_expression ';' { set_decimating($2) ; } interpolatejleclaration : INTERPOLATE ϊnt_expression ';' { set nterpolating($2); } wire_defs : wϊre_def I wirejlef ' wire_def wire_def : M-394 IDENTIFIER opt_size_spec { /* if no type declared for storage, default it to "fixed" */ if (storagejype == ' ') storagejype = ; /* allocate storage with this name, and initialize to NULL */ if (!add_storage_name($l, $2, &temp, storagejype, micro,FALSE)) { error_w_string("YAC011", "A wire or I/O port named '", $1, "' already exists."); YYERROR; } } I wire_value_def wire_value_def : IDENTIFIER opt_size_spec '=' sym_expression { /* if no type declared for storage, default it to "fixed" */ if (storagejype == ' ') storagejype = 'f ; /* allocate storage with this name, and initialize to expr */ if (add_storage_name($l, $2, &temp, storagejype, FALSE, FALSE)) { add_storage_init(temp, $4); /* enter expr as value for this name */ if (!add_expression_name($l, $4)) { error_w_string("YAC012", "The variable or parameter '", $1, "' is already defined."); YYERROR; } } else { error_w_string("YACO 13", "Storage named '", $1, '" already exists."); YYERROR; γ o M-395 } } I ΓDENTΓFTER opt_sϊze_spec '=' int_constant { /* if no type declared for storage, default it to "int" */ if (storagejype = ' ') storagejype = ; /* allocate storage with this name, and initialize to expr */ if (add_storage_name($l, $2, &temp, storagejype, FALSE, FALSE)) { add_storageJnit(temp, $4); /* enter expr as value for this name */ if (iadd_expression_name($l, S4)} { error_w_string("YAC012", "The variable or parameter '", $1, '" is already defined."); YYERROR; } } else { error _w_string("YAC014", "Storage named '", $1, "' already exists."); YYERROR; } } I IDENTIFIER opt_size_spec '=' real constant { /* if no type declared for storage, default it to "fixed" */ if (storagejype = ' ') storagejype = T; /* allocate storage with this name, and initialize to expr */ if (add_storage_name($l, $2, &temp, storagejype, FALSE, FALSE)) { add_storageJnit(temp, $4); /* enter expr as value for this name */ if (!add_expression_name($l, $4)) { ? l -396 error_w_string("YAC012", "The variable or parameter '", $1, '" is already defined."); YYERROR; } } else { error_w_string("YAC014", "Storage named '", $1, '" already exists."); YYERROR; } var _type_declare : opt_micro VARIABLE FIXED { storagejype = 'f; micro = $1; } I opt.micro VARIABLESNTEG { storagejype = 'i'; micro = $1; } I opt_micro VARIABLE HEX { storagejype = 'h'; micro = $1; } I op t_micro VARIABLE { storagejype = ' '; micro = $1; } var_defs : var_def I var_defs ',' vaijdef 7kZ M-397 var_def : IDENTrFIER opt_size_spec { /* if no type declared for storage, default it to "fixed" */ if (storagejype = ' ') storagejype = 'f; /* allocate storage with this name, and initialize to NULL */ if (add_storagejιame($l, $2, &temp, storagejype, micro, TRUE)) add_storageJnit(temp, NULL); else { error_w_string("YAC014", "Storage named '", $1, "' already exists."); YYERROR; } } I var_value_def var_value_def : IDENTIFIER opt_sϊze_spec '=' sym_expressϊon { /* if no type declared for storage, default it to "fixed" */ if (storagejype = ' ') storagejype = ; /* allocate storage with this name, and initialize to expr */ if (add_storage_name($l, $2, &temp, storagejype, micro, TRUE)) { add_storageJnit(temp, $4); /* enter expr as value for this name */ if (!add_expression_name($l, $4)) { error_w 5tring("YAC012", "The variable or parameter '", $1, "' is already defined."); YYERROR; } } 7^3 -398 else { error_w_string("YAC014", "Storage named "', $1, "' already exists."); YYERROR; } } I IDENTIFIER opt_size_spec '=' int_constant { /* if no type declared for storage, default it to "int" */ if (storagejype == ' ') storagejype = 'i'; /* allocate storage with this name, and initialize to expr */ if (add_storage_name($l, $2, &temp, storagejype, micro; TRUE)) { add_storage_init(temp, $4); /* enter expr as value for this name */ if (!add_expression_name($l, $4)) { error_w_string("YACO 12", "The variable or parameter '", $1, '" is already defined."); YYERROR; } } else { error_w_string("YAC014", "Storage named '", $1, "' already exists."); YYERROR; } } I IDENTIFIER opt_size_spec '=' real_constant { /* if no type declared for storage, default it to "fixed" */ if (storagejype == ' ') storagejype = 'f ' ; /* allocate storage with this name, and initialize to expr */ if (add_storage_name($l, $2, &temp, storagejype, micro, TRUE)) ?kk M-399 add_storage_init(temp, $4); /* enter expr as value for this name */ if (!add_expressϊon_name(Sl, S4)) { error_w_string("YACO 12", "The variable or parameter '", $1, "' is already defined."); YYERROR; } } else { error_w_string("YACϋl4", "Storage named "', $1, '" already exists."); YYERROR; symbol_defs : symbol_def I symboI_defs Y symbol_def symbol_def : identϊfier_or_string '=' expression { /* enter expr as value for this name */ if (!add_expressϊon_πame($l, $3)) { error_w_string("YAC015", "The symbol or parameter '", $1, "' is already defined."); YYERROR; } if (iadd_symboI_name($I, &temp, micro)) { error_w_string("YAC016", "A symbol or parameter named '", $1, '" already exists."); 7k5 -400 YYERROR; } opt_size_ ' spec : /* declares arrays and digital bus widths */ /* null */ { $$ = NULL;/* implies scalar */ } I '[' n_elements ']' { SS = S2; } alias_declaration : ALIAS IDENTIFIER IDENTIFIER ';' { /* add alias name & equivalent name to alias name table */ if (!add_alias_name($2, $3)) { error_w_string(" YACO 17", "The alias '", $2, "' is already defined."); YYERROR; } } identifier_or_string : IDENTIFIER I STRING verify_declaration : VERIFY expression ';' add_verify_expression($2, NULL); I VERIFY expression ',' STRING ';' { add_verify_expression($2, $4); 7k6 M-401 org_declaratϊon : ORG INTEGER ';' { set_origϊn((ϊnt) $2); } phantom_decIaration : PHANTOM ';' { set_phantom(); } virtual_decIaration : VIRTUAL ';' { set_as_virtual_ϊo(); init_declaration : INIT r { set nitO; timezone_declaration : TIMEZONE synι_expressϊon Y { if ( iset_timezone($2, NULL)) { /* function prints error msg */ YYERROR; } 1 I TIMEZONE sym_expressϊon '=' int_expressϊon ';' { if (lset ϊmezone($2, $4)) { 7k7 M-402 YYERROR; } } port_declaration : PORT int_expression ',' int_expression ',' INPUT ',' int_expression ',' int_expression ';' { if (!set_as_ρort($2, $4, FALSE, $8, $10)) { other_error("YAC018", "A port for this block has already been declared."); YYERROR; } } I PORT int_expression ',' in .. expression ',' OUTPUT ',' int_expression ',' int_expression ';' { if (!set_as_port($2, $4, TRUE, $8, $10)) { other_error("YAC018", "A port for this block has already been declared."); YYERROR; } } I GPIO in .. expression ',' INPUT ';' { set_gpio($2, FALSE); } I GPIO int.expression ',' OUTPUT ';' { set_gpio($2, TRUE); } I RTS int_expression ',' INPUT ';' { set_rts($2, FALSE); } I RTS in .. expression ',' OUTPUT ';' { 7^3 M-403 set_rts($2, TRUE); } compute_decIaratϊon : COMPUTELINE int_expressϊon ';' { if (Isei_compute_line($2)) { other_error("YAC028", "A computeline or port for this block has already been declared."); YYERROR; int_expressϊon : int_constant { $$ = $1; } I sym_expression » expression : int_constant { $$ = $!; } I real_constant { $$ = $1; } I sym_expressϊon int_constant : /* integer expression from known values */ INTEGER { $$ = intjo_expr($l); } /* convert to constant expression */ I int_constant l + τ ϊnt_constant { $$ = ϊnt_to_expr(int_value($l) + ϊnt_value($3)); } I int_consianl '-' int_constant { $$ = int o_expr(ϊnt_value($l) - int_value($3)); } I int_constant '*' ϊnt_constant { $$ = intjo_expr(int_value($l) * int_value($3)); } 1 ϊnt_constant T int_constant { $$ = intjo_expr( round( divϊde((double) ϊnt_value($l), (double) ϊnl_value($3) ))); 7k9 M-404 } I int_constant LOG int_constant { $$ = int_to_expr( round( logn( (double) int_value($l), (double) int_value($3) ) ) ); } I int_constant EXP int_constant { $$ = int o_expr( round( expn( (double) int_value($l), (double) int_value($3) ) ) ); } I int_constant L_AND int_constant { $$ = int_to_expr(int_value($l) && int_value($3)); } I real . constant L_AND real_constant { $$ = intjo_expr(round(real_value($l)) && round(real_value($3))); } I real_constant L_AND int_constant { $$ = int o_expr(round(real_value($l)) && int_value($3)); } I int_constant L . AND real . constant { $$ = int_to_expr(int_value($l) && round(reaLvalue($3))); } I int_constant OR int . constant { $$ = int_to_expr(int_value($l) II int_value($3)); } I real_constant OR real . constant { $$ = intjo_expr(round(real_value($l )) II round(real_value($3))); } I real_constant OR int_constant { $S = int o_expr(round(rea value($l)) ll int_value($3)); } I int_constant OR real . constant { $$ = int_to_expr(int_value($l) II round(real_value($3))); } I '-' int_constant %prec UMINUS { $$ = int_to_expr( - int_value($2)); } I '-' in t_constant { $$ = int_to_expr( ~ int_value($2)); } I NOT int_constant { $$ = intjo_expr( ! int_value($2)); } I NOT real . constant { $$ = in t_to_expr( ! round(real_value($2))); } I '-' real_constant { bitwise_err(); YYERROR; } I INT int_constant { $$ = $2; } I INT real_constant { $$ = int_to_expr(int_value($2)); } M-405 I FIX real_constant { $$ = $2; } I FIX int_constant { $$ = real o_expr(real_value($2)); } I *(' int_constant ')' { $$ = $2; } I int_constant EQ_EQ ϊnt_constant { $$ = int o_expr((long) (int_value($l) == int_value($3))); } I real_constant EQJEQ real_constant { $$ =ϊnt o_expr((loπg) (real_value($l) = real_value($3))); } I real_constant EQJEQ int_constant { $$ = lnt o_expr((long) (real_value($l) = (double) int_value($3))); } I ϊnt_constant EQ_EQ real_constant { $$ = int o_exρr((long) ((double) ϊnt_value($l) = real_value($3))); } I int_constant NOT_EQ int_constant { $$ = intjo_expr((long) (int_value($l) I= int_valuc($3))); } I real_constant NOT_EQ real_constant { $$ =intJo_expr((long) (real_yalue($l) !=real_value($3))); } I real_constant NOT_EQ int_constant { $$ = ϊntjo_exρr((Iong) (real_value($l) != (double) int_valuc($3))); } I int_constant NOTJEQ reaI_constant { $$ = ϊntJo_expr((ϊαng) ((double) int_value(Sl) != real_value(S3))); } I int_constant LTJΞQ int_constant { $$ = intjo_expr((Iong) (ϊnt_value($l) <=ini_value($3))); } I real_constant LTJEQ real_constant { $$ = int o_expr((long) (real_value($l) <=real_value($3))); } I reaI_constant LTJEQ int_constant { $$ = int o_exρr((long) (real_value($l) <= (double) int_value($3))); } - I in .constant LT.EQ reaI_constant { $$ = int_to_expr((long) ((double) int_value($l) <= rcal_value(S3))); } I Int_constant GT_EQ ϊnt_constant { $$ = int _to_expr((Iong) (int_value($l) >=ϊn i_value($3})); } I real_constant GT_EQ reaI_constant { $$ = ϊnt o_expr((long) (real_value($l) >=real_value($3))); } I real_constant GT_EQ int_constant { $$ = intjo_expr((long) (real_value($l) >= (double) int_value($3))); } I int_constant GT_EQ real_constant { $$ = intjo_expr((long) ((double) ϊnt_value($l) >= real_value($3))); } I int rronstanl '<' ϊnt_constant M-406 { $$ = int_to_expr((long) (int_value($l) < int_value($3))); } I real_constant '<' real_constant { $$ = int_to_expr((long) (real_value($l ) < real_value($3))); } I real_constant '<' int_constant { $$ = intjo_expr((long) (real_value($l ) < (double) int_value($3))); } I int_constant '<' real_constant { $$ = int_to_expr((long) ((double) int_value($l) < real_value($3))); } I int_constant '>' int_constant { $$ = int_to_expr((long) (int_value($l) > int_value(S3))); } I real_constant '>' real_constant { $$ = int_to_expr((long) (real_value($l) > real_value($3))); } I real_constant '>' int_constant { $$ = int o_expr((long) (real_value($l) > (double) int_value($3))); } I int_constant '>' real_constant { $$ = int_to_expr((long) ((double) int_value($l) > real_value($3))); } I int_constant '&' int_constant { $$ = int_to_expr((long) (int_value($l) & int_value($3))); } I real_constant '&' real . constant { bitwise 3rr(); YYERROR; } I real_constant '&' int_constant { bitwise 3rr(); YYERROR; } I int_constant '&' real_constant { bitwise 3rr(); YYERROR; } I int_constant T int_constant { $$ = int_to_expr((long) (int_value($l) I int_value($3))); } I real_constant T real_constant { bitwise 3rr0; YYERROR; } I real_constant T int_constant { bitwise_err(); YYERROR; } I int_constant L_SHIFT int_constant { $$ = int_to_expr((long) (int_value($l) « int_value($3))); } I real_constant L_SHIFT real_constant { shift_err(); YYERROR; } I real_constant L_SHIFT int . constant { shift_err(); YYERROR; } I int_constant L_SHIFT real_constant { shift_eιτ(); YYERROR; } I int . constant R_SHIFT int_constant { $$ = int_to_expr((long) (int_value($l) » int_valne($3))); } M-407 I real_constant R_SHIFT real_constant { shift_err(); YYERROR; } I real.constant R SFflFT int_constant { shift_err(); YYERROR; } I int_constant RjSHTFT real_constant { shift_err(); YYERROR; } I ϊnt_constant ' Λ ' ϊnt_constant { $$ =ϊnt o_exρr((lαng) (ϊnt_valιιe($l) Λ ϊnt_value($3))); } I real_constant ' Λ ' real_constant { bϊtwise_err(); YYERROR; } I real_constant ' Λ ' int_constant { bϊtwise_errO; YYERROR; } I ϊnt_constant ' Λ ' real_coπstant { bϊtwise_err(); YYERROR; } real_constant : /* real expression from known values */ REAL { $$ = realjo_expr($l); } /* convert to constant expression */ I real_constant '+' real_constant { $$ = realjo_expr(real_value($l) +real_value($3)); } I real_constant '+' int_constant { $$ = real jo_expr(real_value($l) + ϊnt_value($3)); } I int_constant '+' real_constant ( $$ =realjo_expr(ϊnt_value($l) + real_value($3)); } I reaI_constant '- * real_constant { $$ = real o_expr(reaI_value($l) -real_value($3)); } I real_constani '-' int_constant { $$ =real o_expr(real_value($l) - int_value($3)); } I int_constant '- * real_constant { $$ = real o_expr(int_value($l) - real_value($3)); } I real_constant '*' real_constant { $$ = real o_expr(real_value($l) * real_value($3)); } I reaI_constant '*' int_constant { $$ = real o_expr(real_value($l) * int_value($3)); } I int_constant '*' reaI_constant { $$ = real o_expr(int_value($l) * real_value($3)); } I real_constant 7 * real_constant { $$ = real jo_expr( dϊvϊde(real_value($l), real_value($3) ) ); M-408 } I real_constant V int.constant { $$ = real _to_expr( divide(real_value($l), (double) int_value($3) ) ); } I int_constant real_constant { $$ = real o_expr( divide((double) int_value($l), real_value($3) ) ); } I rcal_constant LOG real_constant { $$ = real jo_expr( logn( real_value($l), real_value($3) ) ); } I real . constant LOG int_constant { $$ = real Jo_expr( logn( real_value($l), (double) int_value($3) ) ); } I in . constant LOG real_constant { $$ = real_to_expr( logn( (double) int . value(Sl), real_value($3) ) ); } I real_constant EXP real_constant { $$ = real_to_expr( expn( real_value($l), real_value($3) ) ); } I real_constant EXP int_constant { $$ = real Jo_expr( expn( real_value($l),(double) int_value($3) ) ); } I int_constant EXP real_constant { $$ = real _to_expr( expn( (double) int_value($l),rcal_value($3) ) ); } I '-' real_constant %prec UMINUS { $$ = realjo_expr( - real_value($2)); } I '(' real_constant ')' { $$ = $2; } sym_expression : /* expression from symbolic values */ 75^ M-409 /* These rules return a symbolic expression from the RHS tokens. */ /* The expression is created in Reverse Polish order. */ symbol { $$ = strϊngjo_expr($l); } I sym_expressϊon '+' sym_expression { $$ = concat_expr(concat_expr($l, $3), operator _to_expr('+') ); } I sym_expression V int_constant { $$ = concat_expr(concat_expr($l, $3), operator jo_exprO+') ); } I ϊnt_constant '+' sym_expressϊon { $$ = concat_expr(concat_expr($l, $3), operator Jo_expr(V) ); } I sym_expression '+' real constant { $$ = concat_expr(concat_expr($l, $3), operator Jo_exρr( ') ); } I reaI_constant '+' sym_expression { $$ = concat_expr(concat_expr($l, $3), operator o_expr(V ) ); } I sym_expression '-' sym_expression { $$ = concat_expr(concat_expr($l, $3), operator _to_expr('-') ); } I sym_exρression '-' int_constant { $$ = concat_expr(concat_expr($l, $3), operator jo_exρr('-') ); } I int_constant '-' sym_expressϊon { $$ = concat_expr(concat_expr($l, $3), oρerator_to_exprC-') ); } I sym_expressϊon '-' real_constant { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('-') ); } I real_constant '-' sym_expressϊon { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('-') ); } I sym_expressϊon '*' sym expressϊon { $$ = concat_expr(concat_expr($l, $3), operator jo_cxpr('*') ); } I sym_expressϊon '*' int_constant { $$ = concat_expr(concat_expr($l, S3), operatorjo_expr('*') ); } I ϊnt_constant '*' sym_expressϊon { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('*') ); } I symjexpressϊon '*' real_constant { $$ = concat_expr(concat_expr($l, $3), operator _to_expr('*') ); } I real_constant '*' sym_expressϊon { $S = concat_expr(concat_expr($l, $3), operator _to_expr('*') ); } I sym_exρression V sym_expression { $$ = cvncat_expr(co? -at_expr($I, $3), operator jo_expr( 7') ); } 1 sym_exρressϊon V int_ t .vnstant { $$ = co cjt_expr(cc :t_expr($l, $3), operatorjo_expr(7') ); } I ϊnt_constant T sym_expression M-410 { $$ = concat_expr(concat_expr($l, $3), operator Jo_expr(7') ); I sym_expression T real.constant { $$ = concat_expr(concat_expr($l, $3), operator Jo_expr( T ) ); I real_constant 7' sym_expression { $$ = concat_expr(concat_expr($l, $3), operator_to_expr(7') ); I sym_expression LOG sym_expression { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('L') ); I sym_exρression LOG int_constant { $$ = concat_expr(concat_expr($l, $3), operator o_cxpr('L') ); I int_constant LOG sym_expression { $$ = concat_expr(concat_expr($l, $3), operator _to_expr('L') ); I sym_cxρression LOG real_constant { $$ = concat_expr(concat_expr($l, $3), operator o_expr('L') ); I real_constant LOG sym_expression { $$ = concat_expr(concat_expr($l, $3), operator jo . expr('L') ); I sym_expression EXP sym_expression { $$ = concat_expr(concat_expr($l, $3), operator jo_expr('E') ); I sym_exρression EXP int . constant { $$ = concat_expr(concat_expr($l, $3), operator_to_expr('E') ); I int_constant EXP sym_expression { $$ = concat_expr(concat_expr($l, $3), operator o_expr('E') ); I sym_exρrcssion EXP real.constant { $$ = concat_expr(concat_expr($l, $3), operator o_exρr('E') ); I real_constant EXP sym_expression { $$ = concat_expr(concat_expr($l, $3), operator Jo_expr('E') ); I '-' sym_expression %prec UMINUS { $$ = concat_expr($2,operatorjo_expr('M') ); } I '-' sym_expression { $$ = concat_expr($2,operator_to_expr('~') ); } I NOT sym_expression { $$ = concat_expr($2,operator_to_expr('n') ); } I INT sym.expression { $$ = concat_expr($2,operatorjo_expr(T) ); } I FIX sym_expression { $$ = concat_expr($2,operator_to_expr('F') ); } I '(' sym_expression ')' { $$ = $2; } sym_exρression EQJEQ sym_expression { $$ = concat_expr(concat_expr($l, $3), operator o_expr('Q') ); } M-411 I sym_expression EQJEQ int_constant { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('Q') ); } I ϊnt_constant EQ_EQ sym_expression { $$ = concat_expr(concat_expr($l, $3), operatorjo_exprCQ') ); } I sym_exρression EQ_EQ real_constant { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('Q') ); } I real_constant EQJEQ symjsxpressϊon { $$ = concat_expr(concat_expr($l, $3), operator jo_expr('Q') ); } I sym_expressϊon NOTJEQ sym_expressϊon { $$ = concat_expr(concat_expr($l, S3), operator jo_expr( t N') ); } I sym_expression NOTJEQ int_constant { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('N') ); } I ϊnt_constant NOT_EQ sym_expression { $$ = concat_expr(concat_expr($l, $3), operator jo_expr('N') ); } I sym_expression NOT_EQ real_constant { $$ = concat_expr(concat_expr($l, $3), operator jo_expr('N ); } I reaI_constant NOTJEQ sym_expression { $$ = concar_expr(concat_expr($l, $3), operator jo_exρr('N') ); } I sym_expressϊon LTJEQ sym_expression { $$ = concat_expr(concat_exρr($l ? $3), operator o_exρr(T) ); } I sym_expression LT_EQ ϊnt_constant { $$ = concat_expr(concat_expr($I, $3), operatorjo_expr(T) ); } I ϊnt_constant LT_EQ sym_expression { $S = concat_expr(concat_expr($l, $3), operator jo_expr(T) ); } I sym_expressϊon LTJEQ real_constant { $$ = concat_expr(concat_expr($l, $3), operator jo_expr(T) ); } I reaI_constant LTJEQ sym_expression { $$ = concat_expr(concat_expr($l, $3), operatorjo_exρr(T) ); } l.sym_expressϊon GTJEQ sym_expression { $$ = concat_expr(concat__expr($l, $3), operatorjo_exprCg') ); } I sym_expression GTJEQ int_constant { $$ = concat_expr(concat_expr($l, $3), operator_to_expr('g') ); } I int_constant GTJEQ sym_expressϊon { $$ = concat_expr(concat_expr($l, $3), operator o_expr0g') ); } i sym_expression GTJEQ real_constant { $$ = concat_expr(concat_expr($l, $3), operator jo_exρr('g' ) ); } real_consιant GTJEQ sym_expressϊon { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('g') ); } sym_expressϊon '<' sym_expression M- 12 { $$ = concat_expr(concat_expr($l, $3), opera tor _to_expr('<') ); } I sym_expression '<' int_constant { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('<') ); } l int_constant '<' sym_expression { $$ = concat_expr(concat_expr($l, $3), operator o_expr('<') ); } I sym_expression '<' real_constant { $$ = concat_expr(concat_expr($l, $3), operatorjo_expr('<') ); } I real_constant '<' sym.expression { $$ = concat_expr(concat_expr($l, $3), operator Jo_expr('<') ); } I sym_expression '>' sym.expression { $$ = concat_expr(concat_expr($l, $3), oρeratorjo_expr('r>') ); } I sym.expression '>' int_constant { $$ = conca t_expr(conc t_expr($l, $3), operator o_expr('>') ); } I int_constant '>' sym_expression { $$ = concat_expr(concat_expr($ 1 , $3), operator o_expr('r ') ); } I sym.expression '>' real_constant { $$ = concat_expr(concat_expr($l, $3), operator o_expr('>') ); } I real.constant '>' sym.expression { $$ = concat_expr(concat.expr($l, $3), operator_to_expr('>') ); } I sym.expression '&' sym.expression { $$ = concat_expr(concat_expr($l, $3), operator _to_expr('&') ); } I sym . expression '&' int . constant { $$ = concat_expr(concat_expr($l, $3), operator_to_expr('&') ); } I int.constant '&' sym.expression { $$ = concat_expr(concat.expr($l, $3), operator _to_expr('&') ); } I sym.expression '&' real.constant { bitwise arO; YYERROR; } I real.constant '&' sym.expression { bitwise_err(); YYERROR; } I sym.expression sym.expression { $$ = concat_expr(concat_expr($l, $3), operatorjo . expr( ) ); } I sym.expression T int.constant { $$ = concat_expr(concat_expr($l, $3), operator.to.exρr(T) ); } I int.constant 'I' sym.expression { $$ = concat_expr(concat_expr($l, $3), operator_to_expr(T) ); } I sym.expression T real.constant { bitwise 3rr(); YYERROR; } I real.constant 'I' sym.expression { bitwise 3rr(); YYERROR; } M-413 I sym.expression L.SHIFT sym.expression { $$ = concat_expr(concat_expr($ $3), operator.to.expr('s') ); } I sym.expression L.SHIFT int.constant { $$ = concat_expr(concat_expr($l, $3), operatorjo.expr('s') ); } I int.constant L.SHTFT sym.expression { $$ = concat_expr(concat_expr($l r $3), operatorjo.exρr('s') ); } I sym.expression L.SHIFT real.constant { shift.errO; YYERROR; } I real.constant L . SHIFT sym . expression { shift.errO; YYERROR; } I sym.expression R.SHIFT sym.expression { $$ = concat_expr(concat_expr($l, $3), operator.to.expr('r') ): } I sym . expression R.SHIFT int.constant { $$ = concat_expr(concat.expr($l, $3), operator.to.expr('r') ); } I int . constant R.SHIFT sym.expression { $$ = concat.expr(concat_expr($l, $3), operatorjo.expr('r') ); } I sym.expression R.SHIFT real.constant { shift.errO; YYERROR; } I real.constant R . SHIFT sym.expression { shift.errO; YYERROR; } I sym.expression ' Λ ' sym.expression { $$ = concat_expr(concat_expr($l, $3), operator_to_exρr(' Λ ') ); } I sym.expression ' Λ ' int.constant { $$ = concat_expr(concat_expr($l, $3), operator_to_expr(' Λ ') ); } I int.constant w sym.expression { $$ = concat_expr(concat_expr($l, $3), operator_to_expr(' Λ ') ); } I sym.expression ' Λ ' real.constant { bϊtwϊse.errO; YYERROR; } I real.constant ' Λ ' sym.expression { bϊtwise.errO; YYERROR; } I sym.expression L.AND sym.expression { $$ = concat_expr(concat_expr($l, $3), operator Jo.expr('a') ); } I sym.expression L.AND int.constant { $$ = concat_expr(concat_expr($I, $3), operator_to_expr('a τ ) ); } I int.constant L.AND sym.expression { $$ = concat_expr(concat_expr($l, $3), operator jo.expr('a') ); } I sym.expression L.AND real.constant { $$ = concat_expr(concat_expr($l, $3), operator . to.expr('a') ); } I real.constant L . AND sym.expression M-414 { $$ = concat_expr(concat.expr($l, $3), operatorjo.ex r('a') I sym . expression OR sym.expression { $$ = concat_expr(concat_expr($l, $3), operator o . exρr('o') I sym . expression OR int.constant { $$ = concat_expr(concat_expr($l, $3), operator jo.expr('o') I int.constant OR sym.expression { $$ = concat_expr(concat_expr($l, $3), operatorjo . expr('o') I sym.expression OR real.constant { $$ = concat_expr(concat_expr($l, $3), operator o . expr('o') I real.constant OR sym . expression { $$ = concat_expr(concat_expr($l, $3), operatorjo . expr('o') symbol : IDENTIFIER I STRING n.elements : int.expression hier.body : block.refs gsp.body : gsp.block.refs gsp.block.refs : gsp.block.ref gsp.block.refs gsp.block . ref gsp.block.ref : block.ref I start_gsp_asm asm.body end gsp.asm I label start gsp.asm : BEG /* embedded assembly block looks like nested asm block */ new . asm . blockO ; M-415 end_gsp_asm END if (ifinish.asm.blockO) { other_error("YAC021", "Unable to compile this block."); YYERROR; } if (iend . of.asm.sectionO) { otlier_error("YAC021", "Unable to compile this block."); YYERROR; } /* treat like a line (for labels) */ advance.instr.numberO ; } block.ref : block.ref I block refs block ref blockjref : block.ref.name instance.name op t.param Jist instance.port Jist ';' { ϊnstrjϊne = 0;/* use "line" for error reporting */ new_block_ref($l, $2, line); store_vals($3); store_ports($4); if (isave.this_block.refO) { other_error("YAC022", "An instance by this name already exists."); YYERROR; } else /* treat like a line (for labels) */ advance.instr.numberO; M-416 } block.ref . name opt.param.list instance.port.list ';' { other_error("YAC023", "You must give an instance name."); YYERROR; } block I error block.ref . name : IDENTIFIER instance . name : IDENTIFIER opt.param.list : /* null */ /* make an empty argument set */ new.arg_set(FALSE); $$ = cur.arg.set; cur_arg_set = NULL; '{ " } ' /* make an empty argument set */ new_arg_set(FALSE) ; $$ = cur_arg_set; cur are set = NULL; I 'l ' values ' }' /* save values which have been parsed, and init cur. arg . set */ $$ = cur.arg.set; cur_arg_set = NULL; } instance.port . list : /* null */ M-417 /* make an empty argument set */ new_arg_set(FALSE) ; $$ = cur_arg_set; cur_arg_set = NULL; /* instrjine = line; *//* save just as for asm line */ i τ Ύ /* make an empty argument set */ new_arg_set(FALSE) ; $$ = cur_arg_set; cur.arg.set = NULL; /* instrjine = line; *//* save just as for asm line */ '(' values ')' /* save ports which have been parsed, and init cur. arg.set */ $$ = cur.arg.set; cur_arg_set = NULL; /* instrjine = line; *//* save just as for asm line */ } values : positional.values I named.values » positional.values : positϊonal.value I positional.values ',' positional.value positional.value : expression { if (!cur_arg_sef)/* if no current arg set, make by position */ new.arg_set(FALSE) ; add_ρosϊt_expr($ I); M-418 named.values : named . value I named . values ',' named.value named.value : identifier . or . stiing '=' expression { if (!cur_arg_set)/* if no current arg set, make by name */ new_arg . set(TRUE) ; if (!add_named_expr($l, $3)) { error_w_string("YAC024", "The name '", $1 , '" is used more than once."); YYERROR; } } I identifier.or.stiing '=' /* ignore unspecified param so default value is used */ asm.body : /* null */ I asmjines asmjines : asm.line I asmjines asm . line asm.line : label I asm.instruction opt . terminator { enter_fields(instr_number(), instrjine, opcode, addr.mode . field, operand.field, relocjype); advance.instr.numberO; relocjype = ABSOLUTE; } I error 76k M-419 resynch(); yyerrok; yyclearin; } asm.instructϊon : opcode.src.op.class src.operand I opcode.dest . op . class dest.operand I opcodejmp.op . class jmp.operand I opcode.non.op.class { addr.mode.field = operand.field = 0; } I IDENTIFIER { instrjine = line;/* set line # for error message */ error_w_string("YAC025", ""', $1, * " is not a valid opcode."); YYERROR; } » opt ermϊnator : /* null */ label : IDENΗFIER ' • { /* record label with current instr number as value */ if (!addjabel_name($l, instr_number())) { error.w_string("YAC026", "The label "', $1, "' is already defined."); YYERROR; } } opcode.src.op.class : ADD { opcode = ADD.OP; instrjine = line; /* record opcode line # */ } I ADC M-420 opcode = ADC . OP; instrjine = line; I AND opcode = AND.OP; instrjine = line; I CMP opcode = CMP.OP; instrjine = line; I EOR opcode = EOR.OP; instrjine = line; I LDA opcode = LDA . OP; instrjine = line; I LDB opcode = LDB . OP; instirjine = line; I LDCC opcode = LDCC . OP; instrjine = line I LDD opcode = LDD.OP; instrjine = line; I LDF opcode = LDF.OP; instrjine = line; I LDL opcode = LDL.OP; instrjine = line; I LDWS opcode = LDWS.OP; instrjine = line I LDX opcode = LDX.OP; instrjine = line; I LDY opcode = LDY . OP; instrjine = line; I MAC opcode = MAC.OP; instrjine = line; I MPY opcode = MPY.OP; instrjine = line; I ORA opcode = ORA . OP; instrjine = line; I SUB opcode = SUB.OP; instrjine = line; I SUBC opcode = SUBC . OP; instrjine = line; } I XLD opcode = XLD . OP; instrjine = line; } opcode mp.op.α ass : M-421 JMP { opcode = JMP.OP; instr.line = line; } I JCC { opcode = JCC.OP; mstr Jine = line; } IJCS { opcode = JCS.OP; instr.line -line; } I JEQ { opcode = JEQ.OP; instrjine = line; } I JLF { opcode = JLF.OP; instr.line = line; } I JMF { opcode = JMF.OP; instr.line = line; } I JOV { opcode = JOV.OP; instrjine = line; } I JSI { opcode = JSI.OP; instr.line = line; } I JZE { opcode = JZE.OP; instirjine = line; } I JLE { opcode = JLE.OP; instrjine = line; } I JLT { opcode = JLT_OP; instr.line = line; } I JGE { opcode = JGE OP; instrjine = line; } I JGT { opcode = JGT.OP; instr.line = line; } IJWF { opcode = JWF.OP; instr.line - line; } I JNE { opcode = JNE.OP; instr.line = line; } I DJNE { opcode = DJNE.OP; instr.line = line; } I LBSJ { opcode -LBSJ.OP; instrjine = line; } opcode.dest.op.class : STA { opcode = STA.OP; instr.line = line; } I STB M-422 opcode = STB . OP; instrjine = line; } I STD opcode = STD . OP; instrjine = line; } I STF opcode - STF.OP; instrjine = line; } I STL opcode = STL.OP; instrjine = line; } I STML opcode = STML.OP; instrjine = line; } I STMH opcode = STMH . OP; instrjine = line; } I STMG opcode = STMG . OP; instrjine = line; } I STML1 opcode = STMLI . OP; instrjine = line; } I STMH1 opcode = STMHI . OP; instrjine = line; } I STMGI opcode = STMGI . OP; instrjine = line; } I STWS opcode = STWS.OP; instrjine = line; } I STBS opcode = STBS . OP; instrjine = line; } I STX opcode = STX.OP; instrjine = line; } I STY opcode = STY.OP; instrjine = line; } > opcode . non . op . c ass : ASL opcode = ASL.OP; instrjine = line; } I ASR opcode = ASR.OP; instrjine = line; } I CLC opcode = CLC.OP; instrjine = line; } I NOP opcode = NOP.OP; instrjine = line; } I NOT opcode = NOT.OP; instrjine = line; } M-423 I ROL { opcode = ROL.OP; instr.line = line; } I ROR { opcode = ROR.OP; instrjine = line; } I SEC ' { opcode = SEC.OP; instr.line = line; } src.operand : ϊmmedϊate.operand I absolute.operand I indexed.operand I src.reg_operand dest.operand : absolute.operand I indexed.operand * jmp.operand : jmp.address I '[' absolute.operand ']' I indexed.operand I src . reg . operand ϊmmedϊate.operand : '# * expression { addr.mode.field =IMMEDIATE_MODE; /* record immediate value, and record index in instr. */ operand.field = add_operand_value($2); } '#' '<' expression { addr.mode.field =IMMED_L_MODE; operand.field = add_operand_value($3); } '#' expression { addr . mode.field = IMMED . R .MODE; M-424 operand . field = add_operand_value($3); } absolute . operand : expression { addr . mode.field = ABSOLUTE . MODE; operand . field = add . operand_value($l); } indexed.operand : '[' B '+' expression ']' { addr . mode.field = IND.MODE; operand . field = add_operand_value($4); } I '[' B expression ']' { /* this parses an initial "-" */ addr . mode . field = IND . MODE; operand . field = add_operand_valuc($3); } I '[' B '+' LL '+' expression ']' { addr . mode . field = IND . LOOP . MODE; operand.field = add_operand_value($6); } l '[' B LL expression ']' { /* this parses an initial "-" */ addr . mode . field = IND . LOOP.MODE; operand . field = add_operand.value($5); } I '[' F '+' expression ']' { addr . mode . field = IO . IND . MODE; operand . field = add_operand_value($4): } I '[' F expression ']' M-425 { /* this parses an initial "-" */ addr.mode.field = IO.IND.MODE; operand.field = add_operand_value($3); } I '[' F '+ r LL '+' expression ']' { addr.mode . field = IO.IND.LOOP.MODE; operand.field = add.operand_value($6); } l '[' F V LL expression ']' { /* this parses an initial "-" */ addr.mode . field = IO.IND . LOOP . MODE; operand.field = add_operand_value($5); I T B Υ addr.mode.field = IND.MODE; operand.field = add_operand_value(int_to_expr((long) 0)); ) 1 T B '+ r LL ']' addr.mode.field = IND.LOOP . MODE; operand.field = add_operand_value(int_to_expr((long) 0)); I '[' F T addr.mode.field = IO.IND.MODE; operand.field = add_operand_vaIue(ϊnt_to.expr((long) 0)); } 1 '[' F V LL ']' addr.mode.field = IO.IND.LOOP . MODE; operand.field = add_operand_value(ϊnt_to.expr((long) 0)); src.reg.operand A M-426 addr.mode.field = REG.MODE; operand.field = A.REG; } I B addr . mode . field = REG.MODE; operand.field = B.REG; } I D addr . mode.field = REG.MODE; operand.field = D.REG; } I F addr.mode.field = REG.MODE; operand.field = F.REG; } I LL addr . mode.field = REG.MODE; operand.field = L.REG; } I BS addr.mode.field = REG.MODE; operand.field = BS . REG; } I WS addr . mode . field = REG . MODE; operand.field = WS . REG; } I X addr.mode . field = REG.MODE; operand.field = X . REG; } I Y addr.mode.field = REG.MODE; operand.field = Y.REG; } I ML addr.mode.field = REG.MODE; operand.field = ML.REG; } I MH addr.mode.field = REG.MODE; operand.field = MH . REG; } I MG addr.mode.field = REG.MODE; operand.field = MG.REG; } 1 MLI addr.mode.field = REG.MODE; operand.field = MLI . REG; } I MHI addr.mode.field = REG.MODE; operand.field = MHI . REG; } I MGI addr.mode.field = REG.MODE; operand . field = MGI . REG; } jmp.address : identifier.or.string { /* record name and return index for it, which is operand */ operand.field = assign.label_index($l); /* address mode is immediate (right justified) to load PC */ addr.mode.field = IMMED . R.MODE; /* mark this operand field as relocatable or absolute */ if (is.absoluteO) M-427 relocjype = ABSOLUTE; else relocjype = RELATIVE; } %% void bitwϊse_err(){ other_error("YAC019", "Bitwise operator can't be applied to a fixed point number.");} void shift . errO { other_error("YAC020", "Shift operator can't be applied to a fixed point number.");} void fixed_p_offset(){ other_error("YAC027", "Fixed point number not permitted as an address offset."); } // simulate.hxx // simulation class //T. Montlick // 9/1/90 /* source code control: */ static char SccsID J = "%W% %G%"; #define SIMULATION.DEF #ifndef STRING_DEF #include "string.hxx" #endif ffifndef LONG.ARRAY.DEF #ϊnclude "long.arr.hxx" #endϊf #ifndef INT.ARRAY.DEF #include "ϊnt . arr.hxx" #endϊf #define BOOLEANshort #defineTRUE 1 #defineFALSE 0 #defineINFINITY99999999999 #define NO.TASK-1 #define WAIT.TASK-2 #define MAX.TASKS100 M-428 #defineMAX_GSPS32 #ifndef SCHEDULER . DEF #include "schedule.hxx" #endif ' II gsp simulation // These classes perform a discrete event simulation with the // scheduler. #defineNO_GSP -1 II class waiting gsps // gsps waiting for for something class waiting_gsps { in t_arraywaiting_gsp [MAXJTASKS];// gsps waiting for task double time_waiting[MAX_TASKS]; // time which each task was waiting double max_task_waitjime[MAX_TASKS];// longest a task's gsp been waiting int.arraydo . accounting; int n.tasks; int n_gsps; public: waiting_gsps(int n, int n.g); ~waiting_gsps(); void add_waiting_gsp(int gsp, int task, BOOLEAN accounting); BOOLEANtest_waiting_gsp(int task); BOOLE ANis_gsp_waiting_for_task(int task, int gsp); BOOLEANget_next_^sp_waiting_for_task(int task, int* gspjptr); BOOLEANget_gsp_waiting_fOrjask(int task, int gsp); void advance_waiting_time(double time); doubleget_longest_wait(int task){ return max.task.wait.timeftask]; } int which_task_gsp_waiting_for(int gsp); }; II class "working_gsps" // gsps working on tasks // note that more than one gsp can work on a task if the task is multisegmented 77k M-429 class working_gsps { ϊnt n_gsps; int.array workingjask . numbers;// task # for each GSP double gsps_tϊme_left[MAX_GSPS] ;// time left for each GSP double origϊnaI_time[MAX_GSPS];// orig. duration for each GSP public: working__gsps(int gsps); -working _gsps() ; void adαJgsp_sϊmulation(ϊnt gsp, int task, double tiOe); BOOLEAN next gsp_free(ϊnt* gsp, ϊnt* task, BOOLEAN time.passage.ok, double* passedjime); ϊnt whϊch_task_for_gsp(iπtgsp); BOOLEANany_tϊme_passed(int gsp); double due.timeO; void advance_tϊme(doubIe delta); }; //"idle" class // The idle class (pun intended) keeps a list of free items, each with a unique // sequential positive ID number starting from 0. // Each item has a count, which gets decremented when an item is checked out. class idle { ϊnt.arrayidle . count; public: ϊdleO; -idle(); BOOLEANcheck_any_out(ϊnt* which); BOOLEANany.avaϊlableO; BOOLE ANcheck_specific_out(int which) ; void return_one(inti); BOOLEANis_ϊt_ϊdle(int i){ return (idle_count[i] > Q); } void set.idIe_count(ϊnt ϊ, int count); }; II "simulation" class iiiitiiiiiiiiiiiiiiiiiiiifiiiiiiiifiiiiiiiiiiiifiiiiiiifiiiinniniuiiiiifiiii enum gsp.staius { IDLE, WAIΗNG, PENDING, JUST.STARTED, WORKING }; -430 class simulation { idle idle_gsps; idle *idle_tasks_ptr; waiting gsps *waiting_ptr; waiting gsps *pending_ptr; working_gsps *working_pti; int max gsps; int n_gsps; int n . tasks; double total . time; schedulerthe . scheduler; double sample_period_fraction[MAX_TASKS] ; int_arraytask_queue[MAX_TASKS];// current sizes of queues from i to j int_arrayneeded_q_size[MAX_TASKS];//size needed to fire next task int_arraynιax.q_size[MAX_TASKS];// log of max sizes int.arrayinput . queue; // inputs queues for first tasks int.arrayneeded.input.q . size; int.arraymax Jnput.q; // log of max input q sizes int.arrayinterpolation; int.arrayinterp . count; int verbose; double input . timer; BOOLEANbuffered.input . block; public: simulation(int gsp . count, double headroom); -simulationO; void add_task(long period, double period.fraction); BOOLEANconnectjasksønt i, int j) { return the.scheduler.add . connectionø, j); } void done_adding.tasks(); • V void simulate(BOOLEAN time . passage . ok, double* ϋme . ptr); int get.n . tasksO { return n . tasks; } double get_waiting_time(int i){ return waiting_ptr->get_longest_wait(i); } double get_pendingjime(int i){ return pending.ptr->get_longest_wait(i); } void set.verbosity(int v){ verbose = v; } long get.scheduler_period(int i) { return the_scheduler.get_scheduler_period(i); } long get_counter_value(int i) { return the_scheduler.get_counter_value(i); } M-431 ϊnt get_max_due(int i) { return the_scheduler.get_max_due(i); } ϊnt get.which sp (int i, int j) { return the.scheduler.get_which_gsp(ϊ, j); } int n jsps_for.task(int ϊ) { return the_scheduler.n_gsps_for_task(i); } int get_n_gsps() { return n_gsps; } int whichjask_for_gsp(int gsp, gsp.status* status jptr); void clock_input_timer(doubIe amount); void bump_fired(intϊ); BOOLEANtry.runningfBOOLEAN time.passage.ok); BOOLEANtry_promoting() ; double get_utilizatϊon(){ re rn the.scheduler.getjJlilϊzation(); } BOOLEANenough_ϊn . input_queues(int t) ; void gobble_ϊnputs_from_firing(int t); void set_samples_needed(int t, int s) ; int n_input_queues(int task); int input.queue_size(ϊnt task, int q) ; int n.network.inputsO; ϊnt network_input_q_size(int q); }; #include <stdio.h> enum opcode { asl,asr,rol,ror,add,adc,sub,subc,and,not,ora,eor,lda,ldb, ldbs j ldd,ldds,ldl,ldws,ldx,ldz ? xld,mac,mpy,ldf,clc,sec,xx 1 , cmp,nop,stz,stbs,stf,stb,std,stl,sta,stds,xx2,stws,stml,smιh, stmg,stx,sttnli,stmhϊ,stmgϊ,sty,jsr,jmp cc,jcs,jne,jlf,jmf, jov sϊjzejlejltjgejgtjwf.djne}; enum add.mode {dir,reg,imml,immr,bli,bϊ r flϊ,fi}; enum registers { Areg,Breg,BSreg,Dreg,Freg,Lreg,MGreg,MHreg,MLreg,MGIi'eg, MHIre£,MLIreg,Xreg,Yreg,WSreg } ; class regs{ private: long r; ϊnt number.of.bits; long mask; public: regs(intnob); regs(); void assign(long a); long valueO; int bits(); void print(); }; regs::regs(int nob){ number_of_bits=nob ; mask=l; for (int i=0;i<number . of_bits;i++) mask=m askl (m ask« 1 ) ; } regs::regs(){ r=0; number_of_bits=24; mask=0xffffff; } void regs::assign(long a){ r=a&mask; } long regs:: value (){ return (r); } int regs: :bits(){ return (number . of.bits); } void regs::print(){ } class gsp { private: long data,data_address,prog . address; opcode op; add.mode address.m; registers regis; long instruction; intjump . flag; // define the registers regs A; regs AC; regs X,Y,F,B,L,D,W, M-433 MH,ML,MG,MHI J MLI J MGI,BS,WS; // define the flags regs CF,ZF,OF,SF,MF,WF,LF; publϊc: gsp() : A(24), AC(25),X(24),Y(24),F(24),B(16),L(12),D(8),W(24), MH(24),ML(24),MG(24),MHI(24),MLI(24),MGI(24),BS(24),WS(24), CF(l),ZF(l),OF(l),SF(l),MF(l),WF(l),LF(l){ jump.flag=0; } II fetch instruction from program space iimiiimiiiiiiiiiiiiiiiiiiiirmiiiiiiiiiiifiniiiiiiiiir long prog_fetch(){ instruction=program[prog_addressl; returnønstruction) ; } If instruction decode void decodeO{ address.m = (add.mode) (instruction & 0x038000)»15; op=(opcode) (instruction & 0xfc0000)»18; } II fetch data from data space voϊd data_fetch(){ switch (address.m) { case dir:{ data_address=ϊnstruction & 0x7fff; data=dataram [data.address] ; break;} case reg:{ regis=(registers) instruction & Oxlf; switch (regϊs) { case Areg: { data=A.value();break; } case Breg:{data=B.value();break;} M-434 case BSreg: { data=BS.value();break; } case Dreg:{data=D.value();break;} case Freg:{data=F.value();break; } case Lreg:{data=L.value();break;} case MGreg: { data=MG.value();break; } case MHreg: {data=MH.value();break; } case MLreg: { data=ML.value();break; } case MGIreg: { data=MGI.value();break; } case MHIreg: { data=MHI.value();break; } case MLIreg: { data=MLI. value();break; } case Xreg: { data=X.value();break; } case Yreg:{data=Y.value();break;} case WSreg: { data=WS. value();break; } default: { printf ('ΕRROR in oρcode\n");} } break; } case imml: { data_address=(((instruction & 0x7fff)«9)&0xfffe00); data=dataram [data.ad dress] ; break; } case immr: { data_address=(((instruction & 0x7fff)«9)&0xlff); data=dataram [data . address] ; break;} case bli:{ data_address=(instruction & 0x7fff)+B.value()+L.value(); data=dataram [data.address]; break;} case bi:{ data_address=(instruction & 0x7fff)+B.value(); data =dataram [data . address]; break; } case fli:{ data_address=(instruction & 0x7fff)+F.value()+L.value(); data=dataram [data.address] ; break;} case fi:{ data_address=(instruction & 0x7fff)+F.value(); data=dataram [data.address]; M-435 break;} default: {printf ("ERROR in opcode\n");break;} } } voϊd execute(){ switch (op) { case asl:{ AC.assign((A.value()«l) & Oxlfffffe); // zero fill A.assϊgn( AC. value()) ; break;} case asr:{ long tempCF=A.value()&Oxl; // save lsb if (A.value()&0x800000 1= 0) // shift and do sign extension AC.assign((A.value()»l) 10x800000); else AC.assign((A.value()»l) & 0x7fffff); if (tempCF != 0) // set bit 25 in AC AC.assϊgn(AC.value() 1 0x1000000); // set it else AC.assign(AC.value() & Oxffffff); // clear it A.assign(AC.value()) ; break;} case rol:{ AC.assign(((A.vaTue()«l) & 0xlfffffe)+CF.value()); // carry fill A.assϊgn(AC. value()) ; break;} case ror:{ long tempCF=A.value()&0xl; // save lsb AC.assign((A.valueO»l) & 0x7ffffff); if (CF.valueO != 0) // set msb AC.assign(AC.vaTue() I 0x800000); // set it else AC.assign(AC.value() & 0x7fffff); // clear It if (tempCF != 0) // set bit 25 in AC AC.assign(AC.value() 10x1000000); // set it else AC.assϊgn(AC.valueO & Oxffffff); // clear it A.assϊgn(AC.value()) ; break;} case adc:{ AC.assϊgn(A.value()+data+CF.value()); A.assϊgn(AC.value()) ; break;} M-436 case add:{ AC.assign(A.value()+data); A.assign(AC.valueO); break; } case sub:{ A.assign(A.value()-data);break;} case subc:{A.assign(A.value()-data-CF.value());break;} case and: { A.assign(A.value()&data);break;} case not; { A.assign(-A.value());break; } case ora:{ A.assign(A.value()ldata);break;} case eor:{ A.assign(A.value() Λ data);break;} case lda:{ AC.assϊgn(data&0xffffff); A.assign(AC.value()); break; } case ldb:{ B.assign(data);break;} case ldbs:{printf("ERROR in opcode\n");break;} case ldd:{ D.assign(data);break; } case ldds:{printf("ERROR in opcode\n");break;} case ldl:{ L.assign(data);break;} case ldws:{WS.assign(data);break;} case ldx: { X.assign(data);break;} case ldz:{ printf("ERROR in opcode\n");break; } case xld:{ break;} case mac: { Y.assign(data); MH.assign(MH.value()+X.valueO*Y.value()); break; } case mpy: { Y.assign(data); MH.assign(X.value()*Y.value()); break; } case ldf: { F.assign(data);break;} case clc:{ AC.assign(AC.value() & Oxffffff); A.assign(AC.value()); break; } case sec:{ AC.assign(AC.value() I 0x1000000); A.assign(AC.valueO); break; } case xxl:{printf("ERROR in opcode\n");break;} case cmp: {break;} case nop: {break;} M-437 case stz:{printf('ΕRROR in opcode\n");break;} case stbs:{dataram[data_address]=BS.value();break; } case stf:{dataram[data.address]=F.value();break;} case stb:{dataram[data_address]=B.value();break;} case std:{dataram[data_address]=D.value();break; } case stI:{dataram[data_address]=L.value();break; } case sta:{dataram[data_address]=A.value();break;} case stds:{ printf ("ERROR in opcode\n");break;} case xx2:{ printf ("ERROR in opcode\n");break;} case stws:{dataram[data_address]=WS.value();break;} case stml: { dataram [data_address]=ML.value() ;break; } case stmh: { dataram [data_address]=MH.value() ;break; } case stmg: { dataram[data_address]=MG.value();break; } case stx:{ dataram[data_address]=X.value();break; } case smιlϊ:{dataram[data_address]=MLLvaIue();break; } case stmhϊ:{dataram[data_address]=MHI.valueO;break;} case stmgϊ:{dataram[data_address]=MGI.valueO;break;} case sty:{dataram[data.address]=Y.value();break; } casejsr:{break;} case jmp: { prog_address=data_address;break; } case jcc:{ if (CF.value() = 0) prog_address=data_address; break;} case jcs:{ if (CF.valueO = 1) prog_address=data_address; break;} case jne:{ if (ZF.vaIue() = 0) prog_address=data_address; break;} case jlf: { if (LF.valueO = 1) prog_address=data.address ; break;} case jmf:{ if (MF.value() = 1) prog_address=data_address; break;} case jov:{ if (OF.valueO == 1) prog_address=data_address; break;} case jsϊ:{ if (SF.value() = 1) M-438 prog_address=data_address; break; } case jze:{ if (ZF.value() = 1) prog_address=data_address; break;} • case jle:{ break;} case jit: {break;} case jge:{ break;} case jgt: { break; } case jwf:{ if (WR value () = 1) prog_address=data_address; break; } case djne: { break; } default: {printfC'ERROR in opcode\n");break;} } } ///////////////////////////////////////////////////////// /////// // update the flags.this is cycle 5 operations void flag_update() { // update program counter if (jump.flag==l) prog_address=data_address; else prog_address++; // the zero flag if (A.value() == 0) ZF.assign(l); else ZRassign(O); // the sign flag if (A.value() & 0x800000 != 0) SRassign(l); else SF.assign(O); // the overflow flag if (AC.value()&0x 1000000 != 0) ORassign(l); M-439 else OF.assϊgn(0); // the carry flag if (AC.value()&0xl000000 1= 0) CF.assϊgn(l); else CF.assϊgn(O); // the wait flag if (WS.value() = 0) WF.assϊgn(l); else WF.assign(0); } void print_registers(){ printf("A(24),X(24),Y(24),F(24),B(16),L(12),D(8),MGI(8),MHI(24) J MLI(24),BS(24),WS(24)\n"); printf("%6x %6x %6x %4x %4x 3x %2x %2x %6x %6x %6x %6x\n", A.value(),X.value(),Y.value(),F.value(),B.value(),L.value(),D.value(), MGI.value() ) MHI.value(),MLLvalue(),BS.value() J WS.value()); } }; main(){ long program[10],dataram[10]; gsp * gspl_ptr,*gsp2_ptr,* gsp3_ptr,*gsp4.ptr; gsp l_ptr->prog_fetch() ; gsp l_ptr->decodeO ; gsp l_ptr->data_fetch() ; gsp l_ptr->execute() ; gspl_ptr->flag_update(); gsp l_ptr->print_regϊsters() ; } ' // stackxxx // stack class functions // Terry Montlick // 10/20/89 /* source code control: */ static char SccsID[] = "@(#)stack.cxxl.56 10/7/91"; #include "stack.hxx" If stack class M-440 ////////////////////////////////////////////////////////////////////////////// //stack::stack // Constructor. /////////////////////////////////////////////////////////////////////////////// stack: :stack(){ st.index = 0; } /////////////////////////////////////////////////////////////////////////////// //stack:: -stack // Destructor. stack: :~stack() { } //stack: :push // Push the given element on the stack. void stack: :push(elem e){ (* (array*) this) [st.index] = e; st_index++; } //stack: :pop // Pop the top element off the stack. elem stack: :pop(){ if (st.index) { st.index--; return (* (array*) this) [st.index]; } else return NULL; } //stack: :nth // Return the nth element up the stack. Returns 0 if no such element. elem stack: :nth (int n){ if (st.index) { if ((st.index - n) >= 0) return (* (array*) this)[st_index - n]; } return NULL;} M-441 // stack.hxx // header for stack classes // T. Montlick // 11/20/89 /* source.code control: @(#)stack.hxxl.56 10/7/91 */ #define STACK.DEF #ifndefARRAY_DEF #include "array.hxx" #endϊf class stack : public array{ int st . index; public: stack(); ~stack(); void push(elem); elem pop(); void clearO { st.index = 0; } elem nth(ϊntn); int size() { return st.index; } }; /* standard.h * standard header definitions * * T. Montlick * 10/2/89 */ /* source code control: @(#)standard.hl.56 10/7/91 */ #define STANDARD.DEF #undefNOREF #defineNOREF(a)a=a /* needed to fake out C++ compiler */ #define BOOLEANshort #defineTRUE 1 #defiπeFALSE 0 // standard.hxx // standard header definitions //T. Montlick // 10/2/89 /* source code control: @(#)standard.hxxl.56 10/7/91 */ #include "standard.h" M-442 typedefvoid*elem; // generic element #ifdef OWC #ifndef STREAMH #include<stream.h> #endif #else #ifndef .STREAM.XXX #include<stream.hxx> #endif #endif /* SHeader: /home/solus/users4/release/CVS/star/lib/starstd.h,v 1.1 1991/08/28 21:28:10 ed Exp $ $Id: starstd.h,v 1.1 1991/08/28 21:28:10 ed Exp $ $Log: starstd.h,v $ * Revision 1.1 1991/08/28 21:28:10 ed * Initial revision * */ S T A R S T D . H -general header file for STAR software run in DOS environment */ #defineOK 1 #define NO 0 #define NFG -1 #define FALSE 0 #define TRUE 1 typedef unsigned short ushort; typedef unsigned char uchar; /* ** function prototype */ int file_find( char *filename, char *filepath ); /* for C++ and SUN compatibility */ #define_MAX_PATH256 #ifdef DEBUG #undef DEBUG #endif -443 // strg.arr.cxx // derived class for string array //Terry Montlick // 10/10/89 /* source code control: */ static char SCCSIDΓJ = "@(#)strg_arr.cxxl.56 10/7/91"; #include "strg.arr.hxx" strg_array: :strg_array () {} strg_array::strg_array(int i) { } II strg_array::strg_array // Constructor with string array as argument strg_array::strg_aιray(strg_array& a){ for (int ϊ=0; i<a.size(); i++){ // create a copy of each source string string* s = new string(*a[i]) ; (*this)[fj = s; } } II strg_array::operator = // Assϊgment of array. void strg.array::operator = (stirg_array& a){ for (int i=0; ϊ<a.sϊze(); i++){ // create a copy of each source string string* s = new string(*a[i]); (*this)[ϊ] =s; }} // strg.arr.hxx // header for derived string array classes //T. Montlick // 10/10/89 /* source code control: @(#)strg_arr.hxxl.56 10/7/91 */ #define STRG.ARRAY.DEF #ifndef ARR AY.DEF M-444 #include "array.hxx" #endif #ifndef STRING_DEF #include "string.hxx" #endif class strg . array : public array { public: strg_array(); strg . array(int i); strg_array(strg_array&);// consttuctor from another strg_array void operator=(strg_array&);// assignment op from other strg.array string*&operator [] (int i) { return (string*&) array: :operator[] (i); } int find(string* ptr) { return array: :find(ptr); } void append(string* ptr){ array:: append (ptr); } sti"g_array&operator+(strg_array& a) { return (stig_aιτay&) array: :operator+((array&) a); } strg . array &operator+=(strg_array& a) {a = *this + a; return *this; } }; // strghash.cxx // functions for string hash table class // T. Montlick // 9/12/89 /* source code control: */ static char SccsID[] = "@(#)strghash.cxxl.56 10/7/91"; #ifndef STRG . HASH . DEF #include "strghash.hxx" #endif // bring in hash functions, customized from our defines #include "hash.cxx" // ' strghash.hxx // header for string hash table class // T. Montlick // 9/12/89 /* source code control: @(#)strghash.hxxl.56 10/7/91 */ #define STRG.HASH.DEF #ifndef STRιNG_DEF #include"string.hxx" #endif // define symbols which make a custom hash table class #ifdefHASH #undefHASH #endif #define HASH sϋrg_hash #ifdefHASH_ELEM #undefHASH_ELEM #endϊf #define HASH.ELEM strg.hash . elem #ifdefHASH_LIST #undefHASH_LIST #endϊf #define HASH.LIST strg . hash Jist #ifdef VAL_TYPE #undefVAL_TYPE #endϊf #define VAL.TYPE string // use string*, not string #ϊfdef USE.POINTER #undef USE.POINTER #endϊf #define USE . POINTER #include"hash.hxx" // strϊng.cxx // functions for string class // Copied almost verbatum from Stroustrup, pp. 184-186 //T. Montlick // 8/28/89 /* source code control: */ static char SccsIDD = " @ (#)string.cxxl.56 10/7/91"; #ifndefSTRING_DEF #include "string.hxx" #endif strϊng::string(){ p = new srep; p->s = new char[ 1 ]; strcpy(p->s, ""); p->n = l;} string::string(char *s){ p = new srep; M-446 p->s = new char[ strlen(s)+l ]; strcpy (p->s, s); p->n = 1;} string::string(string & x){ x.p->n++; p = x.p;} string:: -string (){ if (-p->n == 0){ delete p->s; delete p; } } string&string::operator=(char* s){ if (p->n > 1) { // disconnect self p->n~; p = new srep; } else if (p->n == 1) delete p->s; p->s = new char[ strlen(s)+l ]; strcpy (p->s, s); p->n = l; return *this;} string& stiing: :operator=(string & x){ x.ρ->n++; if (-p->n == 0){ delete p->s; delete p;} P = x.p; return *this; } int string: :length(){ return strlen(p->s);} ostream&operator«(ostream& s, string& x){ return s « x.p->s;} istream&operator»(istream& s, string& x){ char buf [256]; s » buf; x = buf; return s;} NM47 void error(char* p){ cerr « p « "\n"; exit(l);} char&string::operatorD(int i) const{ if (ϊ<0 II strlen(p->s)<ϊ) return p->s[0]; else return p->s[ϊ];} // concatenate strings string&striπg::operator+(string &x){ char* new.stir; // create a new string which is concatenation of this this arg new.stir = new char[ strlen(p->s) + strlen(x.p->s) + 1 ]; strcpy(new_str, p->s); strcat(new_str, x.p->s); if (p->n > 1) { // disconnect self p->n~; p = new srep;} else if (p->n = 1) delete ρ->s; p->s = new.str; p->n = l; return *thϊs;} string&stiring::operator+(char* s){ char* new.str; // create a new string which is concatenation of this this arg new.str = new char[ strlen(p->s) + strlen(s) + 1 ] ; strcpy (new.str, p->s); strcat(new_str, s); if (p->n > 1) { // disconnect self p->n~; p = new srep;} else if (p->n = 1) delete p->s; p->s = new.str; p->n = 1; M-448 return *this;} int operator==(const string &x, char *s) { return strcmp(x.p->s, s) == 0; } int operator==(const string &x, const string &y) { return strcmp(x.p->s, y.p->s) == 0; } int operator !=(const string &x, char *s) { return strcmp(x.p->s, s) != 0; } int operator!=(const suing &x, const string &y) { return strcmp(x.p->s, y.p->s) != 0; } // string, hxx // header for string class // Copied almost verbatum from Stroustrup, pp. 184-186 // T. Montlick // 8/28/89 /* source code control: @(#)string.hxxl.56 10/7/91 */ #define STRING.DEF #ifndef STAND ARD.DEF #include"standard.hxx" #endif #ifndef OWC// objectworks hdr is C++ #ifdef sun extern "C--"// but otherwise, sun doesn't have C function prototype { #else extern "C"{ #endif #endif #include<string.h> #include <stdlib.h> #ifndef OWC} #endif ψ class string { struct srep { char* s; // pointer to data int n;// reference count ); srep *p; 79^ - 49 public: strϊng(char*); // string x ="abc" stringC); // string x; strϊng(string &); // string x = string ... string&operator=(char*) ; string& operator=(string &); -stringO; char&operatorπ(intϊ) const; string&operator+(string &x); strϊng& operator+(char*); int lengthO; friend ostream&operator«(ostream&, strϊng&); friendϊstream&operator»(ϊstream&, string&); friendϊnt operator=(coπst string &x, char *s); friendint operator=(const string &x, const string &y); friendϊnt operator!=(const string &x, char *s); friendϊnt operator !=(const string &x, const string &y); }; // utility.cxx // C-callable utility routines //T. Montlick // 10/31/89 /* source code contirol: */ static char SccsTDD = "@(#)utϊlity.cxxl.56 10/7/91"; #ifndefUTILITY_DEF #include "utilityhxx" #endϊf extern "C" { II eπror ϊne // Return the current line # for an error routine. //If we are into assembly code, we remrn "instr.line", which is the // line number where the opcode is, else we use just "line", // which is the current place in the parse. This is so that // if there is no assembly line delimiter, we will not have gone // on the the next line to recognize the instruction. int error_line(){ extern intinstr.line;// use this line if >0 (assembly code) extern intline; // else use this line if (instrjine) return instrjine; else return line;} II check . error . count // Advance error count, and output msg if it just passed max, else exit. // return TRUE if ok to output error. int check . error_count(){ error_count++; if (error.count == M AX.ERROR . COUNT) { cerr « "Error count limit has been reachedΛn"; exit(l); } return 1; } II out.header // Output the error or warning header, including current block info, // if available. void out_header(){ int error . lineO; string* filename.ptr; if (cur_block){ // if currently open file, use this filename if (in.filename . string) filename.ptr = in.filename . string; else filename.ptr = cur.block->get.filename(); if (no . file . info) cerr « "Block '"« *cur_block->get_block_name() « '"" « ERR . DELIM; else cerr « "Block '"« *cur_block->gct_block_name() « "' in file '" « *filename_ptr « '", line " « error_line() « ERR.DELIM; } else if (in . filename.string && (error.lineO != NO_LINE)){ if (no.file.info) cerr « ERR.DELIM; else cerr « "File '" « *in .filename.strϊng « "\ line " « error.lineO « ERR.DELIM; } else cerr « ERR.DELIM;} iiimiiiiiiimiiiinuiiiinπmiπuiiriπiiiiimiiπiiimπiiiπiiii II out.errjieader // Output the error header, including current block info, if available. void out.err_header(char* msgjium) { if (check_error_count()){ cerr « ERR . STRING « msg_num « " "; out_header(); }} II out.warn .header // Output the warning header, including current block info, if available. void out_warn_header(char* msg_num){ cerr « WARN.STRING « msgjium « " "; out_header();} iiiiiiiiiiiiiiiifiiiiiiiiifiiiiiiriiiiiriiiiiiiiiifiiiiiiiiiiiiriiriiiiiitiiiii ' II yyerror // Error routine called from YACC parser with a pointer to error text. int yyerror(char* s){ extern charyytextfj; NOREF(s); out_err_header("YAC001"); cerr « " "' « yytext « '" doesn't make sense hereΛn"; return 1;} πiiπi ii iiwiiπiii iiπiiiiiii ii ii i πiiiiiiiiiiπi II error.w.string // Misc routine called from YACC parser with two pointers to error text, M-452 // plus a string to insert in the middle. int eriOr_w_string(char* msg_code, char* stil, string* str2, char* str3){ * if (check_error_count()){ * • out_err_header(msg_code); cerr « stirl « *str2 « str3 « "\n";} return 1;} II other.error // Misc routine called from YACC parser with a pointer to error text. int other_error(char* msgjium, char* s){ if (check_error_count()){ out.err_header(msg_num); cerr « s « "\n";} return 1;} II warning // Generate warning message, called with a pointer to warning text. int warning(char *msg_num, char* s){ out_warn.header(msg_num); cerr « s « "\n"; return (0); } II yy wrap // Function called from LEX analyzer when end of text is reached. // Pops the file stack for nested include files. int yywraρ(){ if (popJileO) return 0; else return 1;} II check.O.r // Check for a 0 real value, which is illegal. If gotten, generate // an error message and exit. // M-453 mi iiiiπiiuiπimπiiπ iiiiiii iiiiiiii iiiiiiiiiiiiiiiiiiiir double check . 0_r(double val){ int dummy; if (val = 0.0) { dummy = other_error("UTL001", "Attempt to divide by 0") ; exit(dummy);} else return val;} //check . lO.r // Check for a <= 0 real value, which is illegal. If gotten, generate // an error message and exit. // double check_10_r(double val){ int dummy; ϊf(val <= 0.0){ dummy = other_error("UTL002", "Attempt to take a log of a number <= 0"); exϊt(dummy);} else return val;} II round // Round a double to a long. // long round(double x) { ' return (long) ( (x >=0.0) ? (x+0.5) : (x-0.5) ) ; } II divide // Compute a / b with value checking. // double dϊvide(double a, double b){ return ( a / check.O.r(b) );} //logn M-454 // Compute log x to the base n. // double logn(double x, double n){ externdoublelog(double); return ( log( check.lθ.r(x) ) / check_0_r( log( check . lθ . r(n) ) ) );} II expn // Compute x to the power n. // double expn(double x, double n){ extern doubleexp(double); extern doublelog(double); return( exp( n * log( check . lθ.r(x) ) ) );} II is.cond Jump.opcode // Returns TRUE if argument opcode is a conditional jump. BOOLEAN is.cond ump_opcode(int opcode) { switch (opcode) { case JCC.OP: case JCS.OP: case JEQ.OP: case JLF.OP: case JMF.OP: case JOV.OP: case JSI.OP: case JLE.OP: case JLT.OP: case JGE.OP: case JGT.OP: case JWF.OP: case DJNE.OP: case LBSJ.OP: case JNE.OP: M-455 return TRUE; default: return FALSE; }} //isj ' ump.opcode // Returns TRUE if argument opcode is in the jump class. // BOOLEAN isJump_opcode(ϊnt opcode) { if (is.cond ' ump.opcode(opcode)) return TRUE; else return (opcode = JMP.OP);} II ϊs.source.op.opcode // Returns TRUE if argument opcode is in the source operand class. // BOOLEAN ϊs_source_op_opcode(ϊnt opcode) { switch (opcode) { case ADD.OP: case ADC.OP: case AND.OP: case CMP.OP: case EOR.OP: case LDA.OP: case LDB.OP: case LDD.OP: case LDF.OP: case LDL.OP: case LDWS.OP: case LDX.OP: case LDCC.OP: case MAC.OP: case MPY.OP: case ORA.OP: case SUB.OP: case SUBC.OP: -456 case XLD.OP: return TRUE; default: return FALSE; } } II is.dest.op.opcode // Returns TRUE if argument opcode is in the destination operand class. // BOOLEAN is_dest.op_opcode(int opcode) { switch (opcode) { case STA.OP: case STB.OP: case STD.OP: case STF.OP: case STL.OP: case STML.OP: case STMH.OP: case STMG.OP: case STMLI.OP: case STMHI.OP: case STMGI.OP: case STWS.OP: case STBS.OP: case STX.OP: case STY.OP: return TRUE; default: return FALSE; } } II is.indexed.mode // Returns TRUE if argument addressing mode is one of the indexed modes. // BOOLEAN is_indexed_mode(int mode){ switch (mode){ case IND.MODE: NM57 case IND . LOOP.MODE: case IO.IND.MODE: case IO . IND.LOOP.MODE: return TRUE; default: return FALSE; }} mmtuiiiiπimmiiiimminiiinimimiiMiiuumtmiuumiiui If is.ϊmmediate . mode // Returns TRUE if argument addressing mode is one of the immediate modes. // BOOLEAN is_immediate.mode(int mode){ switch (mode){ case ΓMMEDIATE.MODE: case IMMED.L . MODE: case IMMED.R.MODE: return TRUE; default: return FALSE; }} II is.dϊrect.mode // Returns TRUE if arsument addressinε mode is direct mode. // BOOLEAN ϊs_direct_mode(int mode){ return (mode == ABSOLUTE.MODE);} //phantom.name // Returns TRUE if name string follows phantom name convention. // BOOLEAN phantonι_name(string name) { return (name[0] = PHANTOM.PREFIX); } II int o.c.string // Convert an integer number to a C string, returning a pointer to it. M-458 // This string should be copied or othei'wise used before the next call, since // as single static area holds the string. char* int_to_c.string(int i){ static char i_chars[ITOA_LIMIT]; // get strings for input number itoa(i, i . chars, 10); return i.chars; } II check.osti.-eam // Make sure there is no error condition in an output stream. // If there is, output a message and exit immediately. void check_osϋream(ostream& s){ int state; state = s.rdstateO; if (state == .fail II state == _bad){ cerr « "Fatal error trying to write an output fileΛn"; exit(-l); } } } /* utility.h // C-callable utility routines header // T. Montlick // 10/31/89 */ /* source code control: @(#)utility.hl.56 10/7/91 */ #define UTILITY.DEF #ifndef ERR_STR_DEF #include "err_str.h" #endif /* use function prototypes for C++ */ #ifdef cplusplus externint error.lineO; externint check_error_count(); externvoid out.headerO; externvoid out_err_header(char* msg_num); externvoid out_warn_header(char* msgjium); externint yyerror(char* s); M-459 externint error_w.string(char* msg_num, char* strl, string* str2, char* str3); externint other_error(char* msg_num, char* s); externint warnϊng(char* msgjium,. char* s); externint yywrapO; externdouble check.O _r(double val) ; externdouble check_10_r(double val); externlong round(double x); externdouble divide(double a, double b); externdouble logn (double x, double n); externdouble expn(double x, double n); externBOOLEAN is_conά jump_opcode(int opcode); externBOOLEAN isJump_opcode(int opcode); externBOOLEAN is_source.op_opcode(int opcode); externBOOLEAN is_dest_op_opcode(int opcode); externBOOLEAN is_indexed.mode(int mode); externBOOLEAN is_ϊmmediate_mode(int mode); externBOOLEAN is_direct_mode(ϊnt mode); externchar* ϊnt_to_c_string(int i); externvoid check_ostream(ostream& s); #else externint error.lineO; externint check_error_count(); externvoid out.headerO; externvoid out.errJieaderO; externvoid out_warn_header(); externint yyerror(); externint error.w.stringO; externint other.errorO; externint warning(); externint yywrapO; externdouble check_0.rO; externdouble check.lO _r(); externlong roundO; externdouble divide(); externdouble logn(); externdouble expr > (); externBOOLEAN is.condjump.opcodeO; externBOOLEAN isjump.opcodeO; -460 externBOOLEAN is_source_op_opcode() ; externBOOLEAN is_dest_op_opcode() ; externBOOLEAN is_indexed_mode() ; externBOOLEAN is_immediate_mode() ; externBOOLEAN is.direct.modeO; externchar* int.to.c.stringO; externvoid check_ostream(); #endif externint line; /* line number for current place in parse */ externint instrjine; /* line # of current instruction */ // utility, hxx // C-callable utility routines header // T. Montlick // 10/31/89 /* source code control: @(#)utility.hxxl.56 10/7/91 */ #define UΗLITY.DEF #ifndef FIELDS_DEF #include "fields.h" #endif #ifndef STAND ARD.DEF #include "standard, hxx" #endif #ifnde STRING_DEF #include "string.hxx" #endif #ifndef INTRFACE.DEF #include "intrface.hxx" #endif #ifndef ERR . STR.DEF #include "err.str.h" #endif // max # of errors printed #define MAX . ERROR.COUNT10 #define PHANTOM.PREFIX'.' extern "C" { externint error.lineO; externint check_error_count(); externvoid out.headerO; externvoid out_err_header(char* msg_num); -461 externvoid out.warn _header(char* msg_num); externint yyerror(char* s); externint error_w_string(char* msg_num, char* strl, string* str2. char* str3); externint other_error(char* msg_num 5 char* s); externint warnϊng(char* msg_num, char* s); externint yywrapO; externdouble check.O_r(double val); externdouble check.IO_r(double val); externlong round(double x); externdouble divϊde(double a, double b); externdouble logn(double x, double n); externdouble expn(double x, double n); externBOOLEAN is.cond Jump_opcode(int opcode); externBOOLEAN ϊs ump_opcode(ϊnt opcode); externBOOLEAN ϊs_source.op_opcode(int opcode); externBOOLEAN ϊs_dest_op_opcode(int opcode); externBOOLEAN ϊs_indexed_mode(int mode); externBOOLEAN ϊs_ϊmmediate.mode(int mode); externBOOLEAN is_direct_mode(int mode); externchar* iπt o_c_strϊng(ϊnt i); externvoid check_ostream(ostream& s); // test to see if name follows phantom name convention externBOOLEAN phantom_nanιe(string name);} // zone.hxx // zone class //T. Montlick // 1/29/90 // source code control: @(#)zone.hxxl.56 10/7/91 #define ZONE.DEF extern "C" { #include "mystdlib.h"} #ifndef STAND ARD.DEF #include "standard.hxx" #endif #imdef STRTNG_DEF #ϊnclude "strϊng.hxx" #endif #ifndef INT.ARR AY.DEF M-462 #include "int . arr.hxx" #endif #ifndef LONG . ARRAY . DEF #include "long . arr.hxx" #endif ■ #ifndef INST . ARRAY . DEF #include "inst.arr.hxx" #endif #ifndef STRG . ARRAY . DEF #include "strg . arr.hxx" #endif ffifndef INTRFACE . DEF #include "intrfacε.hxx" #endif #ifndef ZONE.ARRAY.DEF #include "zone.arr.hxx" #endif #ifndef SCHEDULER . DEF #include "schedule.hxx" #endif #ifdef SZ #undef SZ #endif #defineSZ 4 // default array and hash table size // define strings for phantom block names and pieces of names #defineTURNSTILE_STR ".turnstile" #defineFREE_SEG_STR "Jϊee . seg" #define COPY.STR'Jcopy" #defineWAIT_FOR_FLAGS_STR"_wait_for_flags" #define JUMP_TO_STR"Jump_to" #define SEPARATOR.STR"." #define IN_FIFO_STR"_in_fifo_" #define OUT.FIFO.STR'Jout.fifo . " #define IN_PTR_STR"in_ptr" #define OUT_PTR_STR"out_ptr" #define LOOP_STR"_$loop" #define PORT_STR"_%port_" #defineGSP_START_STR"_$start_gsp" #defineCOPY_CONSTANT_STR"_copy_constanl" M-463 #defineCOPY_ADDRESS_STR"_copy_address" #defineWAIT_SEG_FLAG_STR"_waϊt_seg_flag" #definelJNπ _ARR_PTR_STR"_inϊt_arr_ptr" #defineZONE_STR ".zone." #define SEG.STR "_seg_" #defineSTR_LENGTH (2*ITOA_LΓMIT)+20 #define LCOUNTER_STR"Jcounter_" #define USER_TOP_NAME"top" //register names in io.sdf: #defineIN_PORT_BUF_LEN_STR"_%seriaI_ϊn_port_buf_len_" #defineIN_PORT_FrFO_rX_STR"_%serial_in_port_fifo_ix_len_" #defineIN_PORT_FrFO_START_STR"_%seriaI_in_port_fifo_staι-t_" #defineIN_PORT_CONHG_STR"_ seriaI_in_port_config_" #defineOUT_PORT_BUF_LEN_STR"_%serial_out_port_buf_len_" #defineOUT_PORT_FrFO_START_STR"_%serial_out_port_fifo_start_" #defineOUT_PORT_CONHG_STR"_%serial_out_port_config_" #defineOUT_PORT_DECIMAπθN_STR"_%serϊal_out_port_decimation_" #defineOUTJPORT_ENABLE_STR"_%serial_out_port_ι-un_" #defineOUT_PORT_WAIT_MASK_STR"_%seriaI_out_port_wait_mask_" #define PROBE_FιFO_STR"_%probe_fifo_0" #definePROBE_FTFO_BUF_LENl #definePROBE_FιFO_LEN_STR"_%probe_fifo_len_0" #defineIN_CLOCK_STR"_%serial_in_port_int_clk_" #defineOUT_CLOCK_STR"_%seriaI_out_ρort_ϊnt_clk_" fdefine rN_CLOCK_VAL_STR"_%in_clk_val_" #define OUT_CLOCK_VAL_STR"_ out_clk_val_" #define GPIO_REGISTER"_%gpϊo_register" #defineGPIO_OUTPUT.FIELD"_ gpϊo_output_field'' #defineOUT_CLOCK_DEFAULT7 #define DEPTH.STR'Jdepth" #defineARRAY_PREFIX_STR"_arr$" #defineTO_ARRAY_PTR_STR"_tptr$" #defineFR_ARRAY_PTR_STR"_fptr$" #define TO_PHANT_ARR_STR"_to_phant_array" #define FJλ_PHANT_ARR_STR"_fr_phant_array" #define UP_FR_PH_ARR_STR"_up_fr_ph_array" #defineDOWN_FR_PH_ARR_STR"_down_fr_ph_array" #define DUPE_PHANT_ARR_STR"_dupe_ph_array" #define WAIT_NON0_COMP_STR"_waϊt_nonz_comρute" -464 #define POLL_COMP_STR"_poll_compute_line" #define COMPUTE_CTR_STR"_comρute_count" #define PR_RESET_STR"_pr_reset" #define PR_SIGNAL_STR"_&probe_signal" #definePR_SIGNAL_INIT_VALl // amount to add to fifo sizes to fix hardware problem #defineFIFO_SIZE_FUDGE2 // initial value of max_seg_cycles before we examine ports #define MAX.SEG.CYCLES 10000 // class used by zone class to handle processing input wires to a zone class wire_inputs{ inst.arraypendingjnstances;// current input instances for partition int_arraypending_wires;// current input wires for partition inst.arrayusage.instances;// instances for usage count int.arrayusage.wires;// wires for usage count int.arrayusage.count;// usage count of # of inputs using wires int.arrayusage.loop.flags;// TRUE if above wire need for loop phantom inst.arrayloop.source Jnst;// instance which generated the loop wire int.arrayloop.source.io;// I/O index for this source public: wire.inputsO; -wire.inputsO; instance*pending_instance(int i) { return pending Jnstances[i]; } int pending_wire(int i){ return pending.wires[i]; } int pending_size(){ return pending_wires.size(); } void add_input(instance* inst, int wire); void remove_input(instance* inst, int wire); void add_wire.usage_count(instance* inst, int wire, int count); void decrement_usage_count(instance* inst, int wire); BOOLEANtest_usage_count(instance* inst, int wire); void set_wire_loop_flag(instance* inst, int wire, instance* output.inst, int output.io); BOOLEANtest_wire_loop_flag(instance* inst, int wire); void free.loop.wiresO; instance*source_for_loop(instance* inst, int wire); wire_inpuιs&operator+=(wire_inputs&); }; // ports class, which stores common info about input and output ports M-465 class ports { ϊnt.arrayport.nums; // port #s for zone inputs ϊnt . arraytriggers; // trigger sources long_arrayconfigurations;// configuration words strg.arrayfi o.names; // hierarchical name for start of fifo ϊnt.arrayfifo.buf.len-// fifo buffer length int.arrayfifo . depth; // fifo depth ϊnst.arrayport.instances;// instances for actual ports public: porιs(); ~ports(); ϊnt size() { return port_nums.size(); } ϊnt which.port(ϊnti){ return port_nums[i]; } void set_port(int ϊ, int port, int trigger, long config); void set _fifo(int ϊ, string* name, int depth) ; void set_fifo_buf_Ien(int ϊ, int len) { fifo_buf_len[il = len; } string* fif o_πame(int i) { return fif o.names [i] ; } ϊnt fifo_size(inti) { return fifo_buf.len[i]*fifo_depth[i]*2; } int fifo_buf_length(int ϊ) { return fifo.buf.lenp]; } int fifo_buffers(inti) { return fifo_depth[i]; } long get_configuration(int i) { remrn configurations[i]; } ϊnt getjriggerrint i) { return triggers[ιj; } void set.port_ϊnstance(int i, instance* inst) { port.instancesp] = inst; } instance*port_instance(ϊnt i) { return port_instances[i]; } }; // derived classes from ports class in.ports : public ports { int.arrayinput.ϊs.compute;// TRUE if input is really compute line in τ _arrayinput.fifo_in_ptrs / index in inst. for in fifo in ptrs insi.arrayinput.fifo.in.inst;// instance for above ϊnt.arrayϊnput.fifo.out.ptrs;// index in inst. for in fifo out ptrs -466 inst.arrayinput.fifo.out.inst;// instance for above public: in_ports(); ~in_ports(); void set_in.port(int i, int port, int trigger, long config, int fifo.ptr, instance* inst); void set_in_compute(int i, int port); void set_in_fifo(int i, string* fifo.name, int depth, int out . ptr.index, instance* out.ptr . inst); BOOLEANadd_input_port(int port, int fifo.ptr, instance* inst, int trigger, long config, int entry.size); B OOLE ANadd.compute _input(int port) ; BOOLE ANis_compute_input(int i){ return input_is . com pute[i]; } void fifo_in_pu-(int i, int* ptr, instance** inst); void fifo_out.ptr(int i, int* ptr, instance** inst); void add_in_portJnst(instance* port.inst); }; class out.ports : public ports { int.arrayoutput.fifo.ptrs;// index in instance for out fifo ptrs inst.arrayoutput.fifo.inst;// instance for above int.arrayoutput.fifo.enable;// index in top inst for fifo flag enable inst.arrayoutput.mstances;// parent wire instances for output ports int.arrayoutput.wires;// wires for output ports public: out.portsO; ~out_ports(); void add_wire(instance* inst, int wire, instance* port.inst); BOOLEANadd_output_port(int port, int trigger, long config, int entry.size); void set_out.fifo(int i, string* fifo.name, int depth, int ptr, instance* inst); void fifo_ptr(int i, int* ptr, instance** inst); int fifo_ptr_no_inst(int i) { return output_fifo_ptrs[i]; } instance*output_instance(int i) { return outpu t_instances[i]; } int outpu t_wire(int i) { return output_wires[i]; } int get_fifo_enable(int i) -467 { remrn output_fifb_enable[i]; } }; // special trigger value which signals no trigger for signal source #define NO.TRIGGER-1 // special trigger value which signals trigger wait instance supplied by user #defineTRIGGER_INST_SUPPLT£D-2 // special port value which signals no port (compute line) for signal source #define NO_PORT-l // return values for process.zone.ϊo #defineERROR_STATUS-l #defineNO_INPUTS-100 // base class of the zone class which handles inputs to the zone class zone_ϊnputs{ protected: in.portsϊnputs; // port inputs to zone BOOLEANcompute.wait . inst;// TRUE if a compute line wait instantiated public: zone.inputsO; -zone.inputsO; BOOLEANadd_zone_compute.input(intport) { return inputs.add_compute_input(port); } ϊnt n.zone_inputs(){ return ϊnputs.sϊzeO; } void set_zone_ϊnput_fifb(int i, string* fifo.name, int depth, int out.ptir.ϊndex, instance* ptr.inst) { inputs.se t_in_fifo(i, fifo.name, depth, out.ptr.index, ptr . inst); } string* zone_input_fifo_name(ϊntl) { return inputs, fifo.name© ; } void add_ϊnput.inst(instance* port . inst) { inputs.add_ϊπ_port.inst(port_inst); } instance*ϊnput_port_instance(int ϊ) { return ϊnputs.port_instance(i); } void set.compute.wait . instO { compute.waϊt . inst = TRUE; } BOOLEANis_compute_waϊt_ϊnst.set() { return compute.waϊt.inst; } int get_input_trigger(intϊ) { return ϊnputs.get_trigger(i); } }; M-468 // base class of the zone class which handles outputs from the zone class zone_outputs{ protected: out.portsoutputs; // port outputs from zone public: zone_outputs(); ~zone_outputs(); int n_zone_outputs(){ return outputs. size(); } instance*output.instance(int i) { return outputs.output . instance(i); } int output_wire(int i){ return outputs.output.wire(i); } instance*output_port_instance(int i) { return outputs.port.instance(i); } int output_size(){ return outputs. size(); } void add_output_wire_and_inst(instance* inst, int wire, instance* port.inst) { outputs.add_ ire(inst, wire, port.inst); } BOOLEANadd_zone_output(int port, int trigger, long config, int entry.size) { return outputs.add_output_port( port, trigger, config, entry . size); } int zone_output_port(int i) { return outputs. which . port(i); } int zone.outpu _ . fifo_ptr(int i) { return outputs.fifo_ptr . no _inst(i); } void set_zone_output_fifo(int i, string* fifo.name, int depth, int ptr, instance* inst) { outiputs.se t_out_fifo(i, fifo.name, depth, ptr, inst); } string* zone_output_fifo_name(int i) { return outputs, fif o.name(i); } int get_output_trigger(int i) { return outputs.getjrigger(i); } }; // base class of the zone class which manages pending wires (wires which are // inputs for as-yet unpartitioned blocks) class zone_pending_wires{ protected: wire_inputspending_wires;// wire inputs which are pending for zone public: zone_pending_wires() ; -469 ~zone_pendϊng_wiresO ; ϊnstance*pendϊng _ϊnstance(int i) { retom pendϊng_wires.pending_instance(ϊ); } int pendϊng_wire(int i){ return pending_wϊres.pending_wire(i); } int pending_size(){ return pendϊng_wϊres.pendϊng_sϊze(); } void add_ϊnput(instance* inst, int wire) { pending_wires.add_ϊnput(inst, wire); } void add_wire_usage_count(instance* insζ int wire, int count) { pending_wires.add_wire_usage_count(inst, wire, count); } }; // base class of the zone class which maintains topological info on the // connections between zones class zone.topology{ zone.arraynext.zones; // succeeding zones in zone topology zone_arrayprevious_zones;// previous zones in zone topology public: zonejopologyO; -zone.topologyO; void add_next_zone(zone* z) { next.zones.append(z); } void add_prey_zone(zone* z) { prevϊous.zones.append(z); } ϊnt n.ne t_zones(){ return next_zones.sϊze(); } zone* next_zone(ϊnt i) { return next_zones[i] ; } BOOLEANnext_zone_present(zone* z) { return (next_zones.find(z) >= 0); } ϊnt n_prev_zones(){ remrn previous.zones.sϊzeO; } zone* prev.zone(inti){ return previous_zones[iJ; } B OOLE ANprev_zone_present(zone* z) { return (previous.zones.find(z) >= 0); } }; class zones;// defined later class zone : public zone.inputs, public zone.outputs, public zone_pendϊng_wϊres, public zone_topology{ ϊnt zone.number; string* zone.name; double zone.rate; ϊnt seg.number; M-470 char zone_chars[STR_LENGTH]; char seg_chars[STR_LENGTH]; long max_seg_cycles; long_arrayseg_cycles_used;// # cycles used in each segment • long_arrayoverhead_cycles;// # overhead cycles allowed for long init_cycles; // once- only cycles for zone strg_arrayseg_flag_names;// names for all this zone's seg flags long zone.flags.mask;// timing source for this zone BOOLEANuser.triggered; // TRUE if user supplies wait for flags inst BOOLEANderived; // TRUE if this is a derived sub-zone BOOLEANis . master; // TRUE if has derived sub-zones long repeat . count; // repeat count for scheduling zone BOOLEANforced . boundary;// TRUE to force a zone boundary instance*las t.in.zone.parent;// parent of last sequenced in zone int last.in.zone.seq-// child sequence # of last in zone BOOLEANdo_compute_polling;// TRUE if must poll compute line instance*compute_ctr_inst;// parent instance for compute ctr storage int compute_ctr_index;// index in parent for compute ctr storage zones* zones_contained_in;// zones class instance which hold this zone protected: void set_as_sub_zone(){ derived = TRUE; } BOOLEANadd_zone_input(int port, int fifo_ptr,instance* inst, int trigger, long config, int entry_size); BOOLEANse t_zone_rate(double rate, long gsp.rate); BOOLEANinit_port(int portjium, int buf Jen, int indexjen, string* fifojiame, long por t_setup, int decim_count, long enable, long wait_mask); public: zone(int zone.num, zones* zones_ptr); ~zone(); virtualchar*get_zone.chars(){ return zone.chars; } virtualchar*true_zone_chars(){ return zone.chars; } virtualchar*get_seg_chars() { return seg_chars; } virtualvoid bump_segment(); virtualint zone_num(){ return zone_number; } virtualint seg_num() { return segj mber; } virtuallong max.cyclesO { return max_seg_cycles; } void set_max_cycles(long i) { max_seg_cycles = i; } virtualvoid add_cycles(long i){ seg_cycles_used[seg_number] += i; } 1 virmaUong cycles.usedO { remrn seg_cycles_used[seg_number]; } virtuallong cycles_used_in_seg(int i) { return seg_cycles_used[i]; } virtualvoid add.init_cycles(long i) { inϊt.cycles += i; } virtuallong get_init_cycles(){ return ϊnit.cycles; } virtualvoid set.overhead . allowed.forfjong ϊ) { overhead_cycIes[seg_number] = i; } virtuallong overhead.allowed.forJn_seg(int i) { return overhead_cycles[i]; } virmalint n_segments(){ return seg_number; } virtualstring*seg_flag.name(int i); vϊrmalstring*make_segment.flag(ϊnt*index_ptr); string* loop_counter_name(int i); string* make_loop_counter(int* index_ptir, instance** ϊnst.ptr); BOOLE ANset_zone_name(string* name); void override_zone_name(string* name) { zonejiame = name; } string* get_zone_name() { return zone.name; } double get_zoπe_rate() { remrn zone rate; } ϊnt process.zone.inputsO; int process_zone_outputs(); int dojemporal.partitionO; BOOLEANfixup_feedback.inputs(instance* this.inst); int evaIuate_zone_inputs(instance* this.inst); BOOLEANevaIuate_child_zone_inputs(instance* parent, int which.child, instance* child, int* n.ϊnputs.ptr); int evaIuate_zone_outputs(instance* this.inst); BOOLEANget.fifo_ptr_for.port(instance* this.inst, BOOLEAN is . output); BOOLE ANallocate_trigger_source(instance* this.inst); BOOLEANevaIuate_port_timezone(ϊnstance* this.inst); BOOLE ANevaluate _timezone_name(instance* this.inst) ; BOOLEANevaluate_source_infb(instance* this.inst, int* num, ϊnt* trigger, long* config, int* entry.size); string* build_ϊn.fifo_name(int i); string* build_in_fifo_out_ptr_name(int ϊ) ; string* build_out_fifc_name(int i); stiing* build_out.fifo_ϊn_ptr_name(ϊnt ϊ); int get_ϊn_fifo_buffer.size(int i); int get_out_fifo_buffer_size(int i); BOOLE ANmake . phantom.wiresO; BOOLE ANmake_phantom_wires(int_array* top.of.nex t_copy); BOOLEAN modify_pending_in(int i, instance* this.inst); long get_wait_mask(int i, BOOLEAN is_output); long get_port_setup(int i, BOOLEAN is.output); B OOLE ANinit.port.registersO ; BOOLEAN init_hardware_register(string* reg_name, expr* value); void set_zone_mask(long m){ zone.flags.mask = m; } long zone_mask() { return zone.flags . mask; } void set.zone . user . triggeredO { user.triggered = TRUE; } BOOLEANis.user.triggeredO { return user.triggered; } int gsps_used(){ return n.segments() - 1; } virtual int get_gsp_count(doub!e* fractional.count.ptr); BOOLEANis.sub_zone(){ return derived; } void free_pending_loop_wires() { pending_wires.free_loop_wires(); } BOOLE ANis_compute_input(int i){ return inputs.is.com pute . input(i); } int input_fifo_size(int i) { return inputs.fifo.size(i); } string* input_fifo_name(int i) { return inputs, fif o.name(i); } int input_fifo_buf_length(int i) { return inputs.fifo.buf . length(i); } int input_fifo_depth(int i) { return inputs.fifo.buffers(i); } int output_fifo_size(int i) { return outputs.fifo_size(i); } string* output_fifo_name(int i) { return outputs, fif o_name(i); } void output_fifo_ptr(int i, int* ptr, instance** inst) { outputs.fifo_ptr(i, ptr, inst); } void input_fifo_in_ptr(int i, int* ptr, instance** inst) { inputs.fifo_in_ptr(i, ptr, inst); } void input_fifo_out_ptr(int i, int* ptr, instance** inst) { inputs.fifo_out_ptr(i, ptr, inst); } int which_input_port(int i){ return inputs. which_port(i); } int get_output_fifo_enable(int i) { return outputs.get_fifo_enable(i); } M-473 void set_as_master_zone(){ ϊs.master = TRUE; } BOOLEANϊs_master_zone0{ remrn is.master; } void set_repeat_count(long 1) { repeat_count = 1; } long get_repeat_countO{ remrn repeat.count; } virtual zone*original_zone(double* rel.rate.ptr); virtual zone*origϊnaI_zone(); BOOLEANprocess_gpios(instance* inst); BOOLEANprocess_rts(instance* inst); zone& operator+=(zone&); virtualvoid force_a_boundary(){ forced.boundary = TRUE; } virtualBOOLEANboundary_forced(){ remrn forced.boundary; } virtualvoid clear.forced_flag(){ forced.boundary = FALSE; } void set.last_in_zone(ϊnstance* parent, int seq) { last.in . zone.parent = parent; last.in.zone.seq = seq; } instance*getJast_in_zone(int* seq_ptr) { *seq_ptr = last.in.zone.seq; return last.in.zone.parent; } BOOLEANanalyze.compute.counter.pollingO; virtual BOOLEANcompute.polIingO { if (segjiumber = 1) remrn do.compute.polling; else return FALSE; } virtual int get_compute_ctr(instance** ϊ.ptr) { *i_ptr = compute.ctrjnst; return compute.ctr Jndex; } zones* get.zones.which.contaϊnsO { return zones.contained.in; } }; // misc functions called: block* find_block(string* prototype.name); BOOLEAN translate_zone_name(expr* name.expr, instance* this.inst, string** namejptr); // derived class of the zone class which handles decimated/interpolated zones // derived from master zone class sub.zone : public zone{ zone* derived.from; // which zone immediately derived from int decimation.factor;// factor with respect to orginal zone trig. long ratio; // decimation/interpolation ratio for deriv. BOOLEANdecϊmatiπg; // TRUE if decimating from derived public: sub_zone(int zone.num, zones* zones.ptr); ~sub_zone(); char* get_zone_chars()// refer all zone # and seg stuff to orig. { return origina l_zone()->get_zone_chars(); } char* true_zone_chars(){ return zone: :get_zone_chars(); } char* get_seg_chars() { return original_zoneO->get_seg_chars(); } void bump . segmentO { original_zone()->bump_segment(); } int zone_num() { return original_zone()->zone_num(); } int seg_num() { return original_zone()->seg_numO; } void add . cyclesQong i) { original_zone()->add_cycles(i); } long cycles.usedO { return origina l_zone()->cycles_used(); } long cycles_used_in_seg(int i) { return origina l_zone()->cycles_used_in_seg(i); } void add_init_cycles(long i) { original_zone()->add_init_cycles(i); } long get.init.cyclesO { return original_zone()->get_init_cycles(); } void set_overhead_allowed_for(long i) { original_zone()->set_overhead_allowedjOr(i); } long overhead_allowed_for_in_seg(int i) { return original_zone()->overhead_allowed_for_in_seg(i); } int n_segments() { return original_zone()->n_segments(); } string* seg_flag_name(int i) { return original_zone()->seg_flag_name(i); } string* make_segment.flag(int* index.ptr) { return original_zone()->make_segment_flag(index_ptr); } void force_a_boundary(){ original_zone()->force_a.boundary(); } BOOLEANboundary.forcedO { return original_zone()->boundaryJOrced(); } void clear_forced.fi ag(){ original_zone()->clear_forced.flag(); } void set_decimation(int i){ decimation.factor = i; } int decimation (){ return decimation . factor; } zone* derived_from_zone(){ return derived Jrom; } void set_sub_zone(zone* prev.zone, long r, BOOLEAN decim) { derived.from = prev.zone; ratio = r; decimating = decim; } M-475 BOOLEANϊs.decimatingO { return decimating; } long get_ratio() { return ratio; } zone* origϊnal_zone(double* reljrate.ptr); zone* original.zoneO; int * get_gsp_count(double* frac.ptr) { return original_zoneO->zone::get_gsp_count(frac_ptr); } long max.cycIesO { return original_zone()->zone::max_cycles(); } BOOLEANcompute.pollingO { return original_zone()->zone::compute_pollϊng(); } ϊnt get_compute_ctr(ϊnstance** ptir) { return origϊnal_zone()->zone::get_compute.ctr(i_ptr); } }; // class to do temporal partitioning class temporal { friend class multi.temporal; string* flag.string;// ptr to name of current segment flag zone* this.zone; // zone for partitioning instance*this_inst;// current instance being partitioned BOOLE ANadding nit;// TRUE if adding init blocks BOOLEANis.multi.temporal;// TRUE if derived multi-temporal class protected: static zone*last.zone_for.partitionϊng; static long compute.ctr.wai t.mask;// saved copy of wait msk string* loopback Jabel;// hierarchical label for top of main loop BOOLEANmake_phantom_instance(string* prototype_name, instance** inst.ptr.ptr); BOOLEANmake_phantom_instance(string* prototype_name, instance** inst.ptr.ptr, ϊntinser t.index); BOOLEANmake.ρhantomJnst_with_args(char* block_name, int n os, ϊnt* ϊo.wires, Instance** io . instances, ϊnt n.params, expr** param.values, instance** inst.ptr.ptr); BOOLEANmake_phantom_inst_wϊth_args(char* block.name, ϊnt n.ϊos, int* io.wires, instance** io.instances, int n_params, expr** param.values, instance** inst . ptr.ptr, ϊnt ϊnsert.index); BOOLEANmake_phantomJnst_wϊth_args(char* biock_name, ϊnt n.ϊos, int* ϊo.wires, instance** io.instances, ϊnt n.params, expr** param.values)// version without instance -476 { instance* inst.ptr; return make_phantom_inst_with.args(block_name, n . ios, io.wires, io.instances, n.params, param.values, &inst_ρtr); } BOOLEANmake_wait_for_flags_block(long wait . mask); BOOLEAN make_wait_nonzero_compute_block(long wait.mask, instance* ctr jnst, int ctr.index); BOOLEAN make_poll_compute_block(long wait.mask, instance* ctr . inst, int ctr Jndex); BOOLEANmake_turnstile(string* the_flag_string, int seg_number); BOOLEANmake_free_segment(string* flagjname); BOOLEANmake.copy.blocksO; BOOLEANmake_phantom_copy_block(int i); BOOLEANmake_copy_constant_block(string* flag.name, long constant); BOOLEAN make_copy_addr_block(int addr.size, string* addr_name,int ptr.index, instance* ptr . inst); BOOLEANmake.init_arr_ptr_block(int addr.size, int addr . index, instance* addr.inst, int ptr.index, instance* ptr . inst); BOOLEANmake_init_arr_ptr_block(int addr.size, int addr . index, instance* addr.inst, int ptr.index, instance* ptr.inst, int place); BOOLEANmake_wait_seg_flag.block(string* fiagjiame, long value); BOOLEANmake.pr . reset . blockO; public: temporal(zone* z, instance* i, string* flagjiamejptr, zone* prev.z = NULL); -temporalO; BOOLEANmake . input.fifoO ; BOOLEANmake_input_fifo_instance(int i); BOOLEANadd_input_fifo_info(int depth); virtual BOOLEAN partition(BOOLEAN* ok, int* duration.ptr); BOOLEANfind_input_and_create_segment_0(); virtual BOOLEANcreate_segment_0(); virtual BOOLEANinit_for_partition(); virtual BOOLEAN create_new_segment(int duration); virtual void out_sample_period_msg(ostream& out); BOOLE ANverifyJnputsO ; BOOLEANverify.end.zone . fitO ; BOOLEANmake.output . fifoO ; BOOLEANadd_parameters(int n.params, static string param_names[], expr* param.valsG); M-477 virtual BOOLEANadd_output_fifo_info(); virtual BOOLEAN make_zone_finish(); BOOLEAN generate_GSP_init_code(in n_segments, string* zeiOth_seg_name, string* loopback Jabel); virtual B OOLE AN run.time Jnput_port_init() ; virtual BOOLEANinit_input_fifo_ptrs(); virtual BOOLEANinit_output_fifo_ptrs(); BOOLEANfixup_feedback_inputs(instance* i) { return this_zone->fixup_feedback_ϊnputs(i); } BOOLEANmake ump.block(string* addr.name) ; virtual int ending_overhead(); virtual BOOLEANadd_thϊs_block_duration(int* dur . ptr); BOOLEANtest_block_duration(int duration) ; virtual long get.this.block.durationO; virtual BOOLEANadd_block_duratϊon(string* prototype.name, instance*^ inst_ptr); virtual long end.zone_cycles(); BOOLEAN end_zone_fits(); }; // misc functions called: ϊnt get_bIock_duration(char* name); int get_bIock_duration(char* name, int n.params, expr** param.values); // derived class from temporal class which does multi-rate temporal partitioning // with a master zone and its decimated/interpolated sub-zones // Defines for states used in multijemporaI::analyze_phantom_nιulti_copies. // Don't do an enumerated type because this way we can use an ordinary // integer array to hold values // common: #defineNOTHTNG 0 // bottom.of.last.copy: #defineNORMAL_COPY_TO_ARRAYl #define ORDINARY_COPY_TO_WIRE2 // toρ_of_next_copy: #defineNORMAL_COPY_FROM_ARRAYl #defineUPSAMPLE_COPY_FROM_ARRAY2 #defineDOWNSAMPLE_COPY_FROM_ARRAY3 #defineLOOP_BOTTOM_STR "Joop.bottom" #define LOOP_RPT_STR"_$rpt_looρ" M-478 class multi jemporal : public temporal { static BOOLEANin_repeat_code;// TRUE if in code blocks being repeated static string*las tjoop.counter.name;// name for current loop static zone*top_ofJoop_zone; static instance*seg_bound_inst; static int seg_bound_ind; static int since Jast.poll;// cycles since last poll block static int loop.counter.index; // = parent wire index for loop ctr static instance* loop . counter.instance;// = parent instance for loop ctr static string*loopJabel_name;// name for top of curr. loop label protected: BOOLEANmake.loop.topO ; BOOLEANmake_loop_bottom(zone* loop_zone); public: multi_temporal(zone* z, instance* i, string* flag_name_ptr, zone* prev.z = NULL); -multijemporalO { } BOOLEANinit.for.partitionO; BOOLEANadd.output.fifoJnfoO; B OOLE ANrun_time_input_port_init() ; BOOLE ANinit.input.fif o . ptrsO ; BOOLEANinit.output.fifo.ptrsO; BOOLE ANadd_this_block.duration(int* dur . ptr); BOOLEANpoll_block_required(int duration); void poll_block_accounting(int duration); BOOLEANsegment_would_follow_poll(int duration); BOOLEANsegment_would_follow_boundary(int duration); BOOLEANadd_poll_block() ; int poll.block.cyclesO; long get.this.block . durationO; int ending_overhead(); long end.zone.cyclesO; BOOLE ANcreate.segment.OO ; BOOLEANcreate_new_segment(int duration); BOOLE ANcreate.zone.boundaryO; int boundary . overheadO; BOOLEAN make.zone . finishO; BOOLEANpartition(BOOLEAN* ok, int* duration.ptr); BOOLEANmakeJoop.init . blockO; 9 BOOLEANanalyze_phantom_multϊ_copϊes(zone* before_zone,zone* after_zone, int.array* bottom.of . last.copy, int.array* top.of_next.copy); BOOLEANmake_phantom_arrays(); BOOLEANmake_to_phantom.array_ptrs(int_array* bottom.of.last.copy) ; BOOLEANmake_from_phantom_array_ptrs(int_array* top.of_next.copy) ; BOOLEANmake_non_phantom_arrays(int_array* bottom.of.last.copy); BOOLEANdupe . phantom.arraysO; BOOLEANn_dupe_phantom_arrays_cycles(ϊnt *n_cycles_pύr) ; BOOLEANmake_to_phantom_arr_copys(ϊnt_array* bottom.of.last.copy, zone* before.zone, zone* after.zone); BOOLEANn_to_phantom_arr.copy_cycles( int.array* bottom.of.last.copy, ϊnt *n.cycles_ptr); BOOLEANmake_from_phantom_arr_copys(int_array* top_of_next_copy, zone* before.zone, zone* after.zone); BOOLEANn_from_phantom_arr.copy_cycles(int.array* top_of_next_copy, int *n_cycles_ptr); BOOLEANmake_normal_to_phantom_arr_copy(int i) ; BOOLEANmake_downsample_from_phantom.arr_copy(inti, zone* before.zone, zone* after.zone); BOOLEANmake_normal_fiOm_phantom.arr_copy(inti); BOOLEANmake_upsample_from_phantom.arr_copy(ϊnt i, zone* before.zone, zone* after.zone); BOOLEANmake.to_phant_arr_ptr_resets(ϊnt_array* bottom.of.last.copy); BOOLEANn_to_phant.arr_ptr_resets(int.array* bottom.of.last.copy, ϊnt *n_cycles_ptr); BOOLEANmake.to_phant_arr.ptr _reset(int i) ; BOOLEANmake_fr_phant_aκ_ptr_resets(mt.array* top.of_next.copy); BOOLEANn_fr_phant_arr_ptr_resets(int_array* top_of_next_copy, int *n_cycles_ptr); BOOLEANmake_fr_phant_arr_ptr_reset(int ϊ) ; BOOLEANlevel_for_latest_array(inti, int* level.ptr); BOOLEANlevel_fOr.previous_array(int i, int level, int* level.ptr); void set_in.repeat_code(){ in epeat.code -TRUE; } void setjιot_ϊn_repeat_code(){in_repeat.code = FALSE; } void save_segment.boundary(instance* inst, int ϊndex); ϊnstance* get_segment.boundary(int* index.ptr); void out_sample_period_msg(ostream& out); BOOLEANadd_block_duration(string* prototype.name, instance*& inst.ptr); M-480 }; // zone.schedule class // determines the schedule for a decimated/interpolated time zone class zone.schedule { schedulerthe.scheduler;// scheduler class to compute schedule zone* master . zone;// original zone for signal input int n.zones; // total # of zones, including dec. & interp. zone . arrayzone.ptrs;// ptr to each zone for this scheduling long_arrayperiods;// sample period for each task private: void find . connected . zonesO; void compute.sample.periodsO ; BOOLEANset_scheduler_connections(); public: zone.schedule (); ~zone_schedule(); BOOLEANcompute_schedule(zone* first.zone); int get.n_zones(){ return n.zones; } long ge t_task_firings_and_zone(int i, zone** zone . ptr . ptr) { *zone_ptr_ptr = zone_ptrs[i]; return the.scheduler.ge tjempor l.repeats(i); } }; // zones class class zones { zone.amiy timezones ; int firs t.sub.zone;// 1st # for sub-zones, which are at end long gpio_reg_value;// configuration val for gpio register public: zones (); ~zones(); zone* add_new_zone(string* name, BOOLEAN make . sub.zone); int n_zones() { return first.sub.zone; } int n_including_sub_zones() { return timezones.size(); } BOOLEANidentify_zones(instance* this.inst, int* n.ptr); int create_and_partition_zones(int* n.zones . ptr, int.array* n_gsps_ptr, double* exact_gsps_ptr); int compute.zone.scheduler.repeatsO; int create_time_zones(int* n.zones.ptr); NM81 ϊnt partition_created_tϊme_zones(int . array* n_gsps_ptr, double* exact gsps.ptr); t initialϊze_port_regϊsters() ; int initialize_all_fifO_ϊnfo() ; long zone_mask(zone* z) { return timezones[timezones.find(z)]->zone_mask(); } hit decϊmation(zone* z) { int i = timezones.find(z); if (tϊmezones[ϊ]->is_sub_zone()) return ((sub . zone*) timezones[i])->decϊmation(); else return 1; } string* gel_zone.name(ϊnt ϊ) { return timezones[i]->get_zone_name(); } zone* get_zone(ϊnt ϊ){ return timezones[i]; } mt find_zone(zone* z){ return timezones.find(z); } zone* add_zone.ϊf_not.present(string* name) ; int n_segments(ϊntϊ) { return tmιezones[i]->n_segments(); } long cycles_used_in_seg(int ϊ, intj) { return timezones[i]->cycles_used_ϊn_seg(j); } long max_cycles(int i) { return timezones[ϊ]->max_cycles(); } long overhead_allowed_for_ϊn_seg(mt i, intj) { remrn timezones[i]->overhead_allowed_for_in_seg(j); } zone* make_sub_zone(zone* in.zone.ptr, long ratio, BOOLEAN decimating); BOOLEANzones_at_same_rate(zone* zonel, zone* zone2); BOOLEANlater.zone(zone* zonel, zone* zone2); BOOLEAN make.probe.fifoO; BOOLEANinit_ϊdle_gsps(); BOOLEANtry_to_collapse_zones(zone* zl, zone* z2); void or_wϊth_gpϊo_reg(Iong val) { gpϊo_reg_value 1= val; } }; // related function: long compute_fifo_size(Iong depth); long compute_probe_fifo_size(long depth); fdefine HRST_FLAG_NAME"_%port_0_flag" // class to globally allocate the 24 "wait" flags class flags { int.arrayallocated; // non-zero for allocated flags int first . flagjndex;// wire index for first flag public: flagsO; -flagsO; BOOLEANallocate(int flag, int* wire, string** name); BOOLEANallocate_any(int* flag, int* wire, string** name); }; // class to globally allocate the gpio and rts i o bits class io_bits{ int.arrayallocated; // non-zero for allocated bits public: io_bits(){ } -io_bits(){ } BOOLEANallocateGnt bit) { if (allocatedfbifj) return FALSE; else { allocated[bit] = TRUE; return TRUE; } } }; // class to globally allocate the GSPs class gsps{ int next_gsp; // next available gsp number public: gsρs(); ~gsps(); int ge tjiext gspO { return next_gsp++; } int current_gsp() { return next_gsp; } }; // zonel.cxx // functions for zone class // T. Montlick // 1/29/90 // source code control: static char SccsID[] = "@(#)zonel.cxxl.56 10/10/91"; #ifndef ZONE_DEF #include "zone.hxx" M-483 #endif #undef DEBUG Ifwire.inputsclass /* This class handles processing input wires to a zone. It keeps a list of wires which are pending for the zone, i.e., wires which are needed as input to as yet unpartitioned blocks. These wires must be kept around until no block requires them, so that phantom wires will get created for each new time zone segment and any block using this wire will get the correct sample in time for the wire. A usage count is maintained of the number of block inputs using this wire. When a block is processed, the appropriate usage counts are decremented. When a usage count for a wire goes to zero, then that wire can be deleted from the list of pending wires. One exception is when a wire is part of a feedback loop. Then, it must be kept around until the creation of the next segment. This assures that a first level phantom exists for the wire (unit delayed with respect to the original). This delayed output can now be used for feedback in a feedback loop "fixup" pass. */ If wire_ϊnputs::wire_inputs // Constructor. wire_inputs::wire_inputs() {} If wire_ϊnρuts::~wire_inputs //Destructor. wire_inputs::~wire_inputs() { } II wire_inputs::add_input // Add wire and instance inputs, provided they are not already present. M-484 void wire_inputs::add_input(instance* inst, int wire){ BOOLEANnew.wire = TRUE; int i; for (i=0; i<pending_wires.size(); i++){ if (pending _instances[i] == inst && pending_wires[i] == wire) new_wire = FALSE; } if (new_wire){ // wire not here, so add to end of arrays i = pending_wires.size(); pending_instances[i] = inst; pending_wires[i] = wire; #ifdef DEBUG string* hier.name; hier.name = inst->prototype()->hier_storage_name_at_index(wire) ; cerr « "added pending input: " « *hier_name « "\n"; #endif } } II wire_inputs::remove_input // Remove a set of inputs. void wire.inputs::remove_input(instance* inst, int wire){ ϊnt i; // scan pending inputs for this one for (i=0; i<pending_wires.size(); i++){ if ( pending_instances[i] == inst && pending_wires[i] == wire ) { pendingjnstances.remove(i); pending_wires.remove(i); } } } // wire_inputs::add_wire_usage_count // Add a usage count for a new wire and instance for the wire. // If the wire and instance already existed, just update the count. void wire_inputs::add_wire_usage_count(instance* inst, int wire, int count) { -485 83 ° BOOLEANnew.wire = TRUE; ϊnt ϊ, index; for (ϊ=0; i<usage_wires.size(); i++){ if (usage.instancesp] = inst && usage_wires[i] = wire) { new_wire = FALSE; index = i; }} if (new_wire){ // wire not here, so add to end of arrays index = usage_wires.sϊze(); usage.instancesfindex] = inst; usage.wirespndex] = wire; usage . loop.flagspndex] = FALSE; usage.countpndex] = 0;} usage_count[index] += count;} // wire.inputs::decrement_usage_count // Decrement the usage count for a wire and instance for tiie wire. // If the count goes to zero, remove the wire and instance, // and return TRUE. If the count is cuπently zero, set a count of -L // This is to support feedback loops, where we can use a wire before it was // generated. void wϊre_inputs::decrement_usage_count(instance* inst, int wire){ ϊnt ϊ; BOOLEANfound = FALSE; for (i=0; i<usage_wires.sϊze(); i++){ if (usage.instancesp] = inst && usage_wires[i] = wire) { found = TRUE; if (usage_count[fJ) ~usage_count[ϊ]; if (usage_count[iJ = 0) { // only remove if loop flag not set if (lusage_loop_flags[i]) -486 // remove the input since usage count is 0 remove_input(usage_instances[i], usage_wires[i]); } } break; } } ϊf (!found){ // not found wire, so add it and set count of -1 add_wire_usage_count(inst, wire, -1); } } II wire .inputs: :test_usage_count // Returns TRUE if wire has non-zero usage count. BOOLEAN wire_inputs::test_usage_count(instance* inst, int wire){ BOOLEANfound = FALSE; int i, index; for (i=0; i<usage_wires.size(); i++){ if (usage_instances[i] == inst && usage_wires[i] == wire) { found = TRUE; index = i; } } if (found) return (usage_count[index] > 0); else return FALSE;} II wire nputs: :set_wire _loop_flag // Set the wire loop flag for a wire and instance of the wire. void wire_inputs::set_wire _loop_flag(instance* inst, int wire, instance* outputjnst, int outpu t_io){ BOOLEANnew_wire = TRUE; int i, index; for (i=0; i<usage_wires.size(); i++){ if (usage_instances[i] == inst && M-487 usage_wϊres[i] = wire) { new.wϊre = FALSE; index = i; }} if (new.wϊre) { // wire not here, so add to end of arrays index = usage.wires.sizeO; usage . ϊnstancespndex] = inst; usage_wires[index] = wire; usage_count[ϊndex] = 0;} usage_loop_flags[index] = TRUE; // remember who generated the loop wire loop_source_ϊnst[ϊndex] = output.ϊnst; loop_source_io[index] = output . io;} //wϊre_inputs::test_wire_loop_fiag // Test the wire loop flag for a wire and instance of the wire. BOOLEAN wire_ϊnputs::test_wϊre_loop_flag(instance* inst, ϊnt wire){ BOOLEANnew.wire = TRUE; int i, index; for (ϊ=0; i<usage_wires.size(); i++){ if (usage.instances[i] = inst && usage.wiresp] = wire) { new.wire = FALSE; index =i; }} if (Inew.wϊre) return usage_loop_flags[ϊndex]; else return FALSE;} II wire.ϊnputs::free_loop_wϊres // Clear any loop wires that are set, and delete them if the usage count is // zero. iuimimiuiiiiu imnimuuu mim u ni iiπmiii void wire_ϊnputs::free_loop_wϊres() { M-488 int i; for (i=0; i<usage_wires.size(); i++){ if (usage _loop_flags[i]) { usage_loop_flags[i] = FALSE; if (usage_count[i] == 0) { // usage count is zero // so delete wire as a pending wire input remove_input(usage_instances[i], usage.wires[i]); } } } } II wire_inputs::source.for_loop // Return the instance which generated the given loop wire. // Returns NULL if no such instance. instance* wire_inputs::source_for_loop(instance* inst, int wire){ instance*return_val = (instance*) NULL; int i; for (i=0; i<usage_wires.size(); i++){ if (usage_instances[i] == inst && usage_wires[i] == wire) { return_val = loop_source_inst[i]; } } return return.val; } II operator+= // Add another set of wire inputs to this set. // Used when partitioning over multi-rate zones, this function // adds partitioning state variables from one zone to the current zone. wire_inputs& wire_inputs::operator+=(wire_inputs& w){ // Add his pending instances and wires to ours. // Don't calling our intelligent array classes to do the work with // there "+" (concatenation) operator because although this is nifty // we could have duplicate wires! M-489 // Add them individually using the add.input member function so that // no duplicates are added. for (ϊnt ϊ=0; i<w.pending_wϊres.size(); ϊ++) add_ϊnput(w.pendϊng_instances[i], w.pending_wϊres[i]); return *this;} II ports class I* The ports class is the base class for input and output ports connected to this time zone. It keeps port numbers, configuration parameters, and fifo information on each port. */ IIports::ports //Constructor. ports::ports() {} iiifiiiiiiiifiiriiiiiiiiiiiiiiiiiiiiiiiifiiiiiiiiifiiiiiiiriiiiiiiiiiiiiiiriiii II ports::~ports // Destructor. ports: :~ports() { } II ports::set_port // Set a port, consisting of a port number, and a config word for the port. void ports::set.port(int i, int port, int trigger, long config) { port.numsp] = port; triggers[i] = trigger; configurations!!] = config;} II ports::set_fifo // Set info for a fifo: its hiearchical name, buffer length, // and fifo depth. M-490 void ports::set_fifo(int i, string* fifo.name, int depth) { fifo_names[i] = fifo.name; fifo_depth[i] = depth;} II in.ports class I* This derived class of the ports class maintains a set of input ports for this time zone. It adds to the base class capabilities maintainance of input and output pointers for fifos. It also permits any inputs to be from compute lines, rather than serial inputs, in which case fifos and port configuration parameters are not used. */ IIin.ports::ϊn_ports //Constructor. in_ports:;in_ports() {} IIin.ports::~in.ports //Destructor. in_ports::~in_ports() {} IIin.ports::set_in_port //// voidin_ports::set_in_port(inti, intport, inttrigger,longconfig, int fifo.ptr, instance* inst){ set.portø, port, trigger, config); input_fifo_in_ptrs[i] = fifo_ptr; input_fifo_in_inst[i] = inst; input_is_compute[i] = FALSE;} M-491 // in_ports::set . in_compute //// wiuiiii nuiiiinriiiiiiiiiiiiiiiiHiiiiiiiinuiiiiii ii nii iiii void in_ports::set_ϊn.compute(int i, ϊnt port){ set_port(i, port, port, 0); ϊnput_is_compute[ϊ] = TRUE;} II ϊn_ports::set_in_fifb void ϊn_ports::set_in_fifo(ϊnt i, string* fifo.name, ϊnt depth, int out.ptr.index, instance* out.ptr . ϊnst) { set_fifo(i, fifo.name, depth); input.fifo.out.ptrsp] = out_ptr_ϊndex; ϊnput . fifo.out.ϊπstpl = out.ptr.inst;} II in_ports::add_input // Add a new input port, consisting of a port number and a fifo pointer // storage index in the top instance. // Also add the configuration word for the port. // Make sure a port is legal to add, making sure there is not already a compute // line trigger for this time zone. // Returns error code if the port was already allocated or already a compute // line trigger. BOOLEANin_ports::add_ϊnput_port(int port, int fifo.ptt, instance* inst, int trigger, long config, int entry_size) { ϊnt ϊ; // scan pending inputs for this one for (i=0; ϊ<size(); ϊ++){ if (whϊchjportfi) = port) { user_top_instance->out_error("ZON001", cerr, FALSE); cerr « "Attempt to add a second port " « port «".\n"; return FALSE; } // make sure there is not already a compute line with a trigger if (input_is_compute[i] && (which_port(i) != NO_TRIGGER)) { user_top_instance->out_error("ZON002", cerr, FALSE); cerr « "You cannot have both a port and a compute line " « "triggering a timezoneΛn"; return FALSE; } } // make sure this is a legal input port number if ((port < first Jn.port) II (port >= (firs t_injport+n_injports))){ user_top_instance->out_error("ZON502", cerr, FALSE); ceπ « "This SPROC chip has no input port " « port « "Λn"; return FALSE;} // port not here, so add to end of arrays i = size(); set_in_port(i, port, trigger, config, fifo . ptr, inst); set_fifo_buf_len(i, entry . size); return TRUE;} II in.ports::add_compute_input // Add a new compute line input, consisting of a port number. // Error if there is already another trigger, either a port or a compute // input. // Returns FALSE and output an error message we have other trigger. BOOLEANin_ports::add_compute_input(int port){ int i; //just check for conflict if trigger was specified if (port != NO_TRIGGER){ for (i=0; i<size(); i++) { // its ok if this compute line was already allocated if (which.port(i) == port) II make sure there is not already a different compute line else if (which_port(i) != NOJTRIGGER) { if (input_is_compute[iJ) { user_top_instance->out_error("ZON003", cerr, FALSE); ceπ « "You cannot have more than one compute line triggering " « "a timezoneΛn"; return FALSE; M-493 } else { user_top_instance->out_error("ZON004", cerr, FALSE); cerr « "You cannot have both a port and a compute line " « "triggering a timezoneΛn"; return FALSE; } } }} // add new compute input port to end of arrays ϊ = size(); set_ϊn_compute(i, port); return TRUE;} i πiiπmrniiiiiπiniii i ii ii iiiiiπiii uiiiii riiiiii II in_ports::fifo_in_ptr // Return ptr and instance for the fifo in ptr. void in_ports::fifo_ϊn_ptr(ϊnt i, int* ptr, instance** inst){ *ptr = ϊnput_fifo_in_ptrs[i] ; *ϊπst = ϊnput_fifo_ϊn_inst[i];} II ϊn_ports::fifb_out_ptr // Return ptr and instance for the fifo out ptr. void ϊn_ports::fifo_out_ptr(int i, ϊnt* ptr, instance** inst){ *ptr = input_fifo_out_ptrs[i]; *ϊnst = input.fif o.out _inst[i] ; } If ϊn_ports::add_ϊn_port.inst // Add the instance for the port for this input. void in_ports::add_ϊn.port_inst(instance* port.inst) { ϊnt ϊ; // we lasted added a port, so get last added port inidex ϊ = size() - 1; // call base class to record instance of this port set_port_ϊnstance(i, port.inst);} -494 // out.ports class /* This derived class of the ports class maintains a set of output ports for this time zone. It adds to the base class capabilities maintainance of input pointers for fifos, as well as the flags which trigger the reading of the fifos by the serial ports. It also hold information abount the wires which connect to the output ports. */ IIout.ports::out.ports // Constructor. out.ports: :out_ports() { } II out_ports::~out_ports // Destructor. out_ports::~out_ports() { } II out.ports: :add_wire // Add wire and instance outputs, whether or not already present. // Also add the instance for the port for this output. void out_ports::add_wire(instance* inst, int wire, instance* port_inst){ int i; i = outpu t_instances.size(); outpu t_instances[i] = inst; outpu t_wires[i] = wire; // call base class to record instance of this port set_port_instance(i, port.inst); } II out.ports::add_output_port // Add a new output port, consisting of a port number. // Also add the config word for the port. M-495 // An enable location index in the top instance for this port is derived and // stored, too. // Returns FALSE if error. BOOLEANout_ports::add_output_port(int port, int trigger, long config, int entry.size) { int i; string* name; char* port.num.str; int index; // scan output ports for this one for (ϊ=0; i<size(); i++){ if (whϊch_port(ϊ) = port) { user_top_ϊnstance->out_error("ZON005", cerr, FALSE); cerr « "Attempt to add a second output " « port « "Λn"; return FALSE; }} // port not here, so add to end of arrays ϊ = sϊze(); set_port(ϊ, port, trigger, config); set_fifo_buf_len(ϊ, entry_size); // make sure this is a legal output port number if ((port < first.out.port) If (port >= (first_out_port+n_out_ports))) { user_top_ϊnstance->out_error("ZON501", cerr, FALSE); cerr « "This SPROC chip has no output port " « port « "Λn"; return FALSE;} // synthesize a name for the fifo enable location // get a C string for the port number port.num.str = int_to_c_string((ϊnt) (port - first.out.port)); name = new string(OUT_PORT_ENABLE_STR); *name = *name + port.num.str; if (!top_instance->prototypeO->look_up_storage_name(name, &index)) { user.top_instance->out_error("ZON006", cerr, FALSE); ceπ « "Couldn't find the output enable register named '" « *name « "'Λn" « "Is your 'initisdl' file cmrrent?\n"; return FALSE;} -496 output_fifo_enable[i] = index; return TRUE;} II out.ports: :se t.out.fifo // Set info for an output fifo: its hiearchical name, buffer length, // and fifo depth. Also set fifo input ptr. /////////////////////////////////////////////////////////////////////////////// void out.ports: :set_out_fifo(int i, string* fifo.name, int depth, int ptr, instance* inst){ set_fifo(i, fifo . name, depth); output_fifo_ptrs[i] = ptr; outpu t_fifo_inst[ϊJ = inst; } II out_ports::fi o_ptr // Return ptr and instance for the fifo ptr. void out_ports::fifo_ptr(int i, int* ptr, instance** inst){ *ptr = output_fifo_ptrs[i]; *inst = output_fifo_inst[i];} II flags class /////////////////////////////////////////////////////////////////////////////// /* This class handles allocation of the 24 "wait" flags. Either a specific flag or any available flag can be requested for allocation. */ II flags::flags // Constructor. flags::flags(){ string* s; first_flag_index = 0; // record wire number in top level instance for first flag if (top_instance){ s = new string(FIRST_FLAG_NAME); top_instance->prototype()-> M-497 look_up_storage_name(s, &first_flag_index); delete s; }} //flags::-flags // Destructor. iinmiiiiimmiimtmmmmmuimmiiiiimuiMiMiitiMiiii flags::~flags() 0 If flags-allocate // Allocate the given flag, returning the wire index in top instance that // the flag is in, plus the name of the flag. // Flag numbers are in the range 0-23. // Returns FALSE if the flag is not available. BOOLEANflags::allocate(int flag, int* wire, string** name){ // make sure we found the first flag if (!first_fiag_index) return FALSE; // chekc for legal flag value & not already allocated if (flag < 0 II flag >= flagjocs) return FALSE; ϊf (allocated[flag]) return FALSE; // flag is available, so allocate it allocated[flag] =TRUE; // get its index in top level instance *wϊre = first.flagjndex + flag; *name = top_instance->prototype()->storage_name.at_index(*wire); return TRUE;} II flags::aliocate_any // Allocate any available flag, returning the wire index in top instance that // the flag is in, plus the name of the flag. // Flag numbers are in the range 0-23. // Returns FALSE if no flag is available. BOOLEANfiags::aIlocate_any(int* flag, int* wire, string** name){ M-498 int i; BOOLEANfound = FALSE; // find a free flag for (i=0; i< flag Joes; i++){ if (!allocated[i]) { found = TRUE; break; } } if (found) { *flag = i; return allocated, wire, name);} else return FALSE;} II zone_inputs::zone_inputs // Constructor. zone_inputs::zone_inputs() { compute.wait.inst = FALSE;} II zone _inputs::~zone_inputs // Destructor. zoneJnputs::~zone_inputs() { } II zone_outputs::zone_outputs // Constructor. zone_outputs::zone_outputs() { } II zone_outputs::~zone.outputs // Destructor. zone_outρuts::~zone_outputs() { } M-499 //zone_pending_wires::zone.peπding_wires // Constructor. zone_pending_wires::zone_pending_wires() {} //zone_pending_wires::~zone_pending_wires // Destructor. zone_pendϊng_wires::~zone_pendϊng_wiresO { } fiiiiiiiiiiiiiiifiiiriiiiiiiiiiiiiiiiiiiiiiirffiifiiffififiiifiriifiiiiifffiiif II sub_zone::sub_zone // Constructor. sub_zone::sub.zone(intzone_num, zones* zones.ptr) : zone(zone_nun , zones.ptr) { derived.from = (zone*) NULL; set_as_sub_zone(); decimation.factor- 1;} II sub_zone::~sub_zone // Destructor. sub_zone::~sub_zone() { } II zone_topology::zone_topoIogy // Constructor. zone_topology::zone_topology() { } II zone.topology::~zone_topology //Destructor. zone_topoIogy::~zone_topoIogy() {} II zone class I* This class supports partitioning and I/O for a time zone. */ /////////////////////////////////////////////////////////////////////////////// IIzone::zone // Constructor. zone::zone(int zone.num, zones* zones.ptr) { char i_chars[ITOA_LIMIT]; // store zone number & pu- to zones class instance which contains us zonejnumber = zonejium; zones_contained Jn = zones.ptr; seg_number = 0; max_seg_cycles = MAX.SEG.CYCLES; seg.cycles_used[0] = 0; init.cycles = 0; derived = user tri2gered = is.master = FALSE; repeat_count = 1; zone_flags_mask = OL; // get string for ".zone.n" strcpy(zone_chars, ZONE_STR); itoa(zone_num, i_chars, 10); strcat(zone_chars, i.chars); // get string for "_seg_0" strcpy (seg_chars, SEG_STR); itoa(0, i_chars, 10); strcat(seg_chars, i_chars); zone_name = (string*) NULL; zone.rate = 0.0; forced.boundary = FALSE; do.compute.polling = FALSE; } II zone::~zone // Destructor. -501 zone::~zone() 0 II zone::bump_segment // Advance the segment number, creating a new segment string. void zone::bump_segment(){ char i arsITJOAJJMrri; // advance segment number and zero the cycles used seg_number++; seg_cycles_used[seg_number] = 0; // get string for "_seg_n" strcpy(seg_chars, SEG_STR); itoa(seg_number, i.chars, 10); strcat(seg_chars, i.chars); // clear the flag to force a new segment in case it was set clear.f orced.flagO ; } II zone::set_zone_name // Sets the zone name. Remrns FALSE if already set to something else. BOOLEANzone::set_zone_name(string* name) { if (zonejiame) { if (*name = *zone_name) return TRUE; else remrn FALSE;} zone.name = name; return TRUE;} II zone::se t.zone.rate // Sets the zone rate, adjusting by the effective gsp rate. Returns FALSE //if already set BOOLEANzone::set_zone_rate(double rate, long gsp_rate){ if (rate == 0.0) return TRUE; if (zone.rate){ if (rate = zone .rate) return TRUE; else return FALSE; } zone.rate = rate; max_seg_cycles = (long) ((gsp.rate/zone.rate) * (1.0 - clock.error/100.0)); return TRUE;} II process.zone.inputs // Process the input blocks for this zone. // Finds the input blocks creates necessary fifo info. // Returns nonzero if error. int zone::process_zone_inputs(){ instance* top; int status = 0; // initialize context to top block top_instance->push_context() ; // get ptr to our child, which is the user's top level block top = top.Jnstance->get.child(users_top_block_index); // evaluate the inputs to this zone if (Istatus) status = evaluate.zone.inputs(top); top_instance->pop_context() ; return status;} II process.zone.outputs // Process the output blocks for this zone. // Finds the output blocks and creates necessary fifo info. // Returns nonzero if error. int zone::process_zone_outputs(){ instance* top; int status = 0; // initialize context to top block top_instance->push_context() ; // get ptr to our child, which is the user's top level block top = top nstance->get_child(users_top_block Jndex); // ditto for outputs if (Istatus) M-503 status = evaluate . zone.outputs(top); top_instance->pop_context(); return status;} iiiiiiiiiififiiiiiiiiiiiifiiiiiiiiiiiiiiiiiiiiiinifffiinififffifiifiinifiifi II dojemporal . partition // Called to do temporal partitioning for a zone. // Returns nonzero if error. ϊnt zone::do_temporal_partitionO { string* flag_string = new stringC'"); BOOLEAN dummy.l; int dummy_2; instance* top; BOOLEAN status = TRUE; temporal* partitioning / ptr to class to do partitioning int ϊ; ϊnt child; // push top instance context on stack top_instance->push_context(); // get the user's top level block top = user op.ϊnstance; // copy sequence to partitioned sequence for top instance // which does not get done in partitioning for (i=0; ϊ<top_instance->get_n_childrenO; ϊ++){ child = top_instance->get_sequence(i); top_ϊnstance->append_partitioned(child) ; } // see if we need to do compute line counter polling, and set up if yes status = analyze_compute_counter.polling(); // create an object of the correct temporal partitioning class // depending on if we need to handle multiple sample rates if (is_master_zoneO) partitioning = new nιulti_temporal(thϊs, top, flag_string); else partitioning = new temporal (this, top, flag_string); // create the zero'th segment, which is the extra segment for partitioning // which is inserted in instance which has first input to zone if (status) status = partitionϊng->find_input_and_create.segment_0(); // do required initialization before we partition M-504 if (status) status = partitioning->init_for_partitionO; // do temporal partitioning for this zone if (status) status = partitioning->partition(&dummy_l, &dummy_2); // make sure zone has valid inputs if (status) status = partitioning->verify_inputs(); // make sure output fifo blocks and zone finish blocks will fit in segment if (status) status = partitioning->verify_end_zone_fitO; if (status) status = partitioning->add_output_fifo_info(); // add phantoms at the end of the zone if (status) status = parti tioning->make_zone_finishO; if (status) status = partitioning->fixup_feedback_inputs(top); // done with partitioning class delete partitioning; // restore previous block context toρ.instance->pop_context() ; return (Istatus);} /////////////////////////////////////////////////////////////////////////////// // analyze.compute.counter.polling // If this (first) zone gets decimated (has a non-unity repeat count) // and gets a compute line input, then we must set up to poll this compute // line periodically so we do not lose polls in the multi-period first segment. // NOTE: This function cannot be properly supported by SPROC 1 and so // a fatal error message will be given. BOOLEAN zone::analyze_compute_counter.polling() { int i; int compute.ctr.wire; BOOLEANstatus = TRUE; BOOLEANhas.serial.inputs = FALSE; string* ctr.name; if (repeat.count > 1){ // if there are serial inputs, no need to do compute line polling 5 for (i=0; ϊ<ϊnputs.sϊze(); ϊ++) { if (linputs.is.compute_ϊnput(ϊ)) has . serial.inputs = TRUE; } if ( 'has.serial.inputs) { for (i=0; i<ϊnputs.size(); i++) { if (inputs.ϊs_compute_ϊnput(i)) { // we found a compute input, so declare compute polling do . compute.polling = TRUE; // make the memory counter to keep track of # of computes // make the name ctr.name = new sϋring(COMPUTE_CTR_STR); // add this counter location to top instance status = user Jop_ϊnstance->add_phantom_storage_name( ctr.name, NULL, &conιpute_ctr_wϊre, ); // save counter location compute_ctr_ϊnst = userjopjnstance; compute.ctr.index = compute.ctr.wire; if (Istatus) { user op_instance->out_error("ZON088", cerr, FALSE); cerr « "A phantom wire named '" « *ctr_name « '" aheady exists l\n"; } break; } } }} // if need to do compute line polling, issue error message if (do.compute.polling) { user_top_instance->out_error("ZON288", cerr, FALSE); cerr « "Decimation and/or interpolation without any " « "serial input is nofλn supported by the SPROC chipΛn"; status = FALSE;} -506 return status;} II fixup . feedback.inputs // Scan the zone for any blocks containing feedback. If found, fix up // the feedback inputs of their children so they use the first phantom for // their wire, not the original wire. // This assures that if the writer to the wire is in a different segment, // he cannot overwrite the value that we want. // This routine recursively calls itself for children. /////////////////////////////////////////////////////////////////////////////// BOOLEAN zone::fixup_feedback_inputs(instance* this . inst) { BOOLEANstatus = TRUE; int i, j; int phantomjevel; instance*child; hier_block*hier_ptr; instance * which Jnstance ; int which.wire; block* prototype . ptr; block* child.proto; block_ref*ref_ptr; int inpu t_seg, output_seg; instance*loop_source; // save cuπent block context and set instance info in block this _inst->push_context() ; // save pointer to block prototype prototype_ptr = this_inst->prototype(); if (prototype_ptr->is_leaf_block()) else if (prototype.ptr- >does_block_have_loops()){ // save pointer to our prototype as a hier block pointer hier.ptr = (hier.block*) prototype.ptr; // we are hierarchical block, so call children for (i=0; i<this.inst->get_sequence_size(); i++) { child = this.inst- >get_child(i); child.proto = child->prototype(); ref.ptr = hier_plr->get_child_block_ref(i); // ignore if no ref . ptr (could be phantom block) if (ref.ptr 1= (block . ref*) NULL) { // scan the child's I/O to see if any inputs are loop inputs for 0=0; j<child_proto->io_table_sϊze(); j++) { if (!child.proto->ϊo_is_output(j) && ref_ptr->is _loop_io(j)) { // found a loop input! // point the loop input to the first phantom, if present if (child->get_wire_for.io(i, 1, &which_ϊnstance, &whϊch_wire)) phantomjevel = 1; // no first phantom, so try original else if (child->get_wire_for_io(i, 0, &which Jnstance, &which_wire)) phantomjevel = 0; else { // no wire, so error! child->out_error("ZON901", cerr, FALSE); cerr « "INTERNAL ERROR - Bad wire while " « "fixing up feedback ϊnputsΛn"; status = FALSE; break; } chϊld->set_phantom_io_level(|, phantomjevel); // get segment number for loop input input.seg = child->get_seg_number(); // see who generated this loop wire // make sure to get original, not phantom child->get.wire_for.ϊo(i, 0, &which_instance, &whϊch.wire); loop.source = pending_wires.source_for_loop( whichjnstance, whϊch.wire); if (loop_source) { // get seg number for loop output outputjseg = loop_source->get_seg.number(); M-508 // if not in same segment, output warning if (output . seg != input.seg) { child->out_warning("ZON008", cerr, TRUE); cerr « "This partitioning created " « (output.seg - input.seg + 1) « " unit delays to " « "feedback loop input '" « *child_proto->io_name_at_index(i) « '"Λn"; } } } } } // call routine recursively if (Istatus) status = fixup.feedback.inputs(child); // if error, get out if (istatus) break; } } // restore previous block context this_inst->pop_context(); return status;} II add.zone.input // Call inputs class to add an input to the zone. BOOLEAN zone::add_zone_input(int port, int fifo.ptr.instance* inst, int trigger, long config, int entry . size) { BOOLEANstatus = TRUE; status = inputs.add_input_port(port, fifo.ptr, inst, trigger, config, entry.size); return status;} II evaluate.zone.inputs M-509 // Find the input blocks // and evaluate the port info. Set the port info in our time zone, including // the evaluated sample rate. // Add the input blocks output wires to the list of pending input wires // for the zone. // If no errors, returns 0. //If error, remrns a value of ERROR.STATUS. // If no inputs for partitioning, remrns a value of NO.INPUTS. ϊnt zone::evaluate.zone_inputs(ϊnstance* this.inst) { // save cuπent block context and set instance info in block this_inst->push_context() ; for (ϊ=0; ϊ<this nst->get.n_children(); i++){ // get next child in sequence which is in this zone whϊch.chϊld = thϊs_inst->get_sequence(i); child = thϊs_mst->get_child(which_child); if ('(status = evaluate_child_zone.inputs(thisJnst, which.child, child, &n_inputs))) break;} // make sure we really found some inputs if (status) { if (n .inputs = 0) { if (this_ϊnst->prototypeO->is_autosequence()) { thϊs_inst->out_error("ZON009", cerr, FALSE); cerr « "Your design has no inputs, so we cannot " « "partitionΛn"; status = FALSE; } M-510 no . inputs = TRUE; } else { // we have at least 1 input, so scan them, making sure there's //just one trigger source, and use this as the trigger for the // zone for (i=0; i<inputs.size(); i++) { inpu tjrigger = inputs.ge tjrigger(i); if (input.trigger != NO.TRIGGER) { // just allow one trigger source for a zone if (zonejrigger != NOJTRIGGER && zonejrigger != inputjrigger) { // For now, allow multiple triggers until we can accomodate another // field in Oread. // this _inst->out_error("ZON010", cerr, FALSE) ; // cerr « "You tried to declare more than one trigger " // « "source for timezone '" // « *zone_name « "Λn"; // status = ERROR.STATUS; // break; //*** } else { zonejrigger = inputjrigger; input.for.triggering = i; } } } // if no triggers provided, use any port number available if (input . for.triggering == NO.TRIGGER) { for (i=0; i<inputs.size(); i++) { M-511 if (!inputs.is_compute_input(i)) { ϊnput.trigger = inputs. which.port(i); if (ϊnput.trigger != NO.PORT) { input.for.triggering = i; thϊs_ϊnst->out_warnϊng("ZON011", ceπ; FALSE); cerr « "No explicit trigger for timezone '" « *zone_name « "' given, so port " « ϊnput.trigger « "will be used.\n\n"; break; } } } } // if trigger for zone, set it (will check for one later provided // this zone is not actually a decimated or interpolated one, // in which case it will get collapsed with the derived zone) if (input.for . triggering != NO.TRIGGER) { // user cell may have taken responsibility for trigger // so if so, just stick something into zone mask so we // know it is triggered if (zonejrigger != TRIGGER.INST.SUPPLIED) set.zonejnask(get_wait_mask(input_ or jrϊggering, FALSE)) ; else set.zone.user .triggered () ; } }} // restore previous block context thϊs_ϊnst->pop_context(); if (.'status) return ERROR.STATUS; else if (no.ϊnputs) return NO.TNPUTS; else return 0;} -512 // evaluate.child . zone.inputs // Recursively evaluate all zone input info for children. // Also process gpio and rts. // Returns FALSE if error. BOOLEAN zone "evaluate . child.zone.inputs (instance* parent, int which . child, instance* child, int* n.inputs . ptr) { BOOLEANstatus = TRUE; int which_grandchild; instance*grandchild; // save cuπent block context and set instance info in block child->ρush_context(); // evalute input if a sproc input and if labeled as being in our zone if (child->prototype()->is_sproc_input() && child->is_zone_present(this)){ (*n_inputs_ptr)++; // evaluate port's timezone // this sets the integer sample rate value for the zone status = evaluate_por tjimezone (child); if (child->prototype()->is_serial_port()) { // add input block's output wires to pending input wires if (status) status = modify . pending _in(which.child, parent); // evaluate input port and make an input fifo from it // also adding it to the time zone if (status) status = get_fifo_ptr_for_port(child, FALSE); } else { // input is a simple signal source, so add trigger to zone if (status) status = allocate _trigger_source(child); } // add input port instance to zone if (status) add.input.inst(child); } // take this opportunity to process gpios and rts', both // input and output M-5Ϊ3 if (child->prototype()->has_gpio()) { if (status) status = process_gpios(chϋd); } if (chϊld->prototype()->has_rts()) { if (status) sta s = process.rts(chϊld);} //recursively call ourself for children if (status) { for (int ϊ=0; i<child->get_n_children(); i++) { // get next child in sequence which is in this zone which randchild = child->ge t_sequence(ϊ); grandchild = child->get_child(which_ grandchild); if (!(status = evaluate_child.zone_inputs(child, which_grandchϊld, grandchild, n.inputs . ptr))) break; } } // restore previous block context child->pop_context() ; return status;} II evaluate.zone.outputs // Find the output blocks, // and evaluate the port info. Set the port info in our time zone, and // output wires to the zone. int zoπe::evaluate.zone_outputs(instance* this.inst) { ϊnt i; BOOLEANstatus = TRUE; ϊnt which.child; ϊnstance*child; insιance*whϊch_ϊnstance; ϊnt which.wire; // save current block context and set instance info in block thϊs_ϊnst->push_context(); for (ϊ=0; i<thϊs_inst->get_n_children(); !++){ // get next child in sequence which is in this zone which.child = this_ϊnst->get_sequence(i); child = this_inst->get.child(whϊch_child); M-514 if (child->is_zone_present(this)) { if (child->prototype()->is_sproc_output()) { // evaluate output port and allocate a fifo ptr for it status = get_fifo_ptr_for.port(child, TRUE); if (Istatus) break; // get wire and instance for this output's input wire // we assume there's only one I O and its an input if (!child->get_wire_for.io(0, 0, &which Jnstance, &which_wire)) { child->out_error("ZON902", ceπ, FALSE); cerr « "INTERNAL ERROR - Bad wire for " « "output blockΛn"; status = FALSE; break; } add_output_wire_and_inst(which_instance, which_wire, child); } } } // restore previous block context this_inst->pop_context() ; return (istatus);} II get.fifo_ptir_for.port // This block is an input or output port, so get a fifo pointer for it. // Get port info, and set it in the zone. // Returns FALSE if error. BOOLEAN zone::get_fifo_ptr_for_port(instance* thisjnst, BOOLEAN is.output) { int portjium; // port characteristics: int trigger; // hardware trigger source long config; // configuration word int entry.size; // fifo entry size int flagjndex; string* name; M-515 BOOLEANstatus = TRUE; if (!evaluate_source_info(this Jnst, &port_num, &trigger, &config, &entry_size)) return FALSE; // allocate port's fifo flag if (!fifo.flags->allocate(port_num, &flag_index, &name)){ thϊs_inst->out_error("ZON013", cerr, TRUE); cerr « "Port" « portjium « " has already been used by another input blockΛn"; return FALSE;} // add new port #, info, and fifo ptr index to this zone if (is.output) { if (!add_zone.output(port_num, trigger, config, entry.size)) status = FALSE;} else{ if (!add_zone_ϊnput(por t.num, flagjndex, top.instance, trigger, config, entry.size)) status = FALSE;} return status;} II allocate.trigger.source // This block is a signal source triggered by some trigger flag (or // NO TRIGGER), so get its number. // It could just refer to a timezone name, which should then be set for // the timezone. // Returns FALSE if error. BOOLEAN zone::allocate_trigger_source(instance* thisjnst) { ϊnt port.number; ϊnt trigger.source;// port characteristics (not used): long config; // configuration word int entry.size; // fifo entry size BOOLEANstatus = TRUE; // there must be a timezone for a source if ( !evaluate_tϊmezone_name(this_ϊnst)) return FALSE; // get trigger source number if (!evaluate_source_iιιfo(thϊs_inst, &port.number, &trigger_source, -516 &config, &entry_size)) return FALSE; // add the compute input (which could have an unspecified trigger) to the // zone status = add_zone_compute_input(trigger_source); return status;} II evaluate.por tjimezone // For this port block, evaluate the timezone and place it into our // current zone class. // Returns FALSE if this conflicts with another port's timezone. BOOLEANzone::evaluate_port_timezone(instance* thisjnst) { BOOLEANstatus = TRUE; expr* name.expr; expr* rate . expr; string* name; double rate; block* prototype.ptr; zone* zonejptr; // assume we are working with current zone zone.ptr = this; prototype.ptr = this_inst->prototype(); // save current block context and set instance info in block this_inst->push_context(); // get timezone info if (status) { if (!prototype_ptr->get_timezone(&name_expr, &rate.expr)) { this_inst->out_eπor("ZON014", cerr, TRUE); cerr « "Serial port does not have a timezone !\n"; status = FALSE; } } // evaluate the timezone name if (status) { if (translate_zone_name(name_expr, this . inst, &name)) { if (iset.zone.name(name)) { 17 // already a zone identified, so add a new one and identify // this block as in the zone zonejptr = the_zones->add_zone_if_not_present(name); // mark the zone in the child input instance this_inst->add_zone(zone_ptr); } } else { this_inst->out_error("ZON016", cerr, TRUE); cerr « "Attempt to define a timezone without a valid nameΛn"; status = FALSE; }} // evaluate the timezone rate if (status) { rate = real_value(rate_expr); if (rate < 0.0) { this_inst->out_error("ZON017", cerr, TRUE); cerr « "Illegal negative rate of " « rate « " for timezone "' « *name « "\\n"; status = FALSE; } // rate of 0 is ok because it means that some other source cell will set else if (rate = 0.0) else if(!zone_ptr->set_zone.rate(rate, chϊp_gsp_irate)) { thϊs_ϊnst->out_error("ZON018", cerr, TRUE); cerr « "Attempt to redefine the rate of timezone "' « *name « '" from " « get_zone_rate() « "to " « rate « ".\n"; status = FALSE; }} // restore previous block context M-518 this_inst->pop_context() ; return status;} II evaluate . timezone . name // For this port block, evaluate the timezone and place it into our // current zone class. // Returns FALSE if this conflicts with another port's timezone. BOOLEANzone: :evaluate_timezone_name(instance* this.inst) { BOOLEANstatus = TRUE; expr* name.expr; expr* rate.expr; string* name; block* prototype.ptr; prototype.ptr = this Jnst- >pro to type(); // save cuπent block context and set instance info in block thisjnst- >push_context(); // get timezone info if (status) { if (!prototype_ptr->get_timezone(&name_expr, &rate_expr)) { this_inst->out_eπor("ZON019", ceπ, TRUE); cerr « "Source does not have a timezone !\n"; status = FALSE; } } // evaluate the timezone name and set this as timezone name if (status) { if (translate_zone_name(name_expr, thisjnst, &name)) { if (!set_zone_name(name)) { this_inst->out_error("ZON020", cerr, TRUE); cerr « "You cannot name this timezone '" « *name « '" because it already\nhas the name '" « *ge t.zone.nameO « '"Λn"; status = FALSE; } M-519 } else { this_inst->out_error("ZON021" ) cerr, TRUE); cerr « "Source does not have a valid timezone name!\n"; status = FALSE; } } //restore previous block context this_inst->pop_context() ; return status;} II translate.zone.name // Evaluate the zone name expression in the current instance context // (which must be set) and return a ptr to the translated name if // a name could be found. Otherwise return FALSE. iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifriiiiiiiifiiiiiiiiiifiiiiiiiimini BOOLEAN translate_zone_name(expr* name.expr, instance* thisjnst, string** name.ptr){ block* prototype.ptr; string* name; prototype.ptr = this.inst->prototype(); // zone name cannot evaluate to a real if (name_expr->is_real_valued()) return FALSE; // it may be an integer if (name_expr->ϊs_int_valuedO){ // is integer, so make a string from it ϊnt dummy; name = new string( ϊnt_to_c_string((int) name_expr->int_value(&dummy,&dummy))) ; *name_ptr = name; return TRUE;} // else it must translate to a string // get string for name expression if (name_expr->eval_to.symbol(&name)) { // translate this string to a name expression, and evaluate if (name.expr = prototype_ptr->translation(name)) name_expr->eval_to_symbol(&name); *name_ptr = name; M-520 return TRUE;} return FALSE;} /////////////////////////////////////////////////////////////////////////////// // evaluate.source.info // For this signal source block, evaluate the source number and trigger. // Returns FALSE and output error if could not evaluate. // If port number expression is NULL, then this is a serial port. // If this block in a serial port, evaluate its configuration info. BOOLEANzone: :evaluate_source_info(instance* thisjnst, int* num, int* trigger, long* config, int* entry.size) { BOOLEANstatus = TRUE; BOOLEANis.compute.line = FALSE; expr* expr_ptr; int triggerjium; int portjium; block* prototype_ptr; prototype.ptr = this_inst->prototype(); // save current block context and set instance info in block this_inst->push_context(); if (status) { // see if port number is present // if not, this is a compute line expr.ptr = prototype_ptr->port_number_expr(); if (expr.ptr == (expr*) NULL) is.compute.line = TRUE; else { if (!expr.ptr->has_int_value()) { this_inst->out_eπor("ZON025", cerr, TRUE); ceπ « "Illegal value of '" « *expr_ptr « '" for a port numberΛn"; status = FALSE; } else { port.num = (int) int.value(expr.ptr); 1 *num = portjium; } } } // get trigger source # if (status) { expr.ptr = prototype_ptr->trigger_source.expr(); if (expr . ptr = (expr*) NULL) { this_ϊnst->out_error("ZON022", cerr, TRUE); cerr « "Null trigger for this signal source block!\n"; status = FALSE; } else if (!expr_ptr->has_in t_value()) { this_inst->out_error("ZON023", cerr, TRUE); cerr « "Trigger source has an illegal value of "' « *expr_ptr « "' for its port numberΛn"; status = FALSE; }} // make sure trigger number is legal if (status) { trigger.num = (ϊnt) int.value(expr_ptr); *trigger = trigger.num; // allow triggers anywhere between first port and last compute line if ( (trigger.num >= first.serial.port && trigger.num <=Iast_compute Jine) If trigger.num = NO.TRIGGER) > // compute line number may also have special value indicating trigger // instance supplied by user else if ( fis.compute.line II trigger.num !=TRIGGER_rNST_SUPPLIED ) { this_inst->out_error("ZON024", cerr, TRUE); cerr « "Signal source has an illegal trigger number of " « trigger_num « ".\n"; status = FALSE; } } if (status) { // if not compute line, check for legal value of part number if (is.compute Jine) else if. (port.num < firs t . serial.port II port.num > las t.serial . port) { this_inst->out_eπor("ZON026", ceπ, TRUE); ceπ « "Serial port has an illegal value of '" « port . num « '" for its port numberΛn"; status = FALSE; } } // get port configuration if (status && !is_compute_line){ expr.ptr = prototype_ptr->por t_config_expr(); if (!expr_ptr->has_in t_value()) { this_inst->out_eπor("ZON027", ceπ, TRUE); ceπ « "Serial port has an illegal configuration word of '" « *expr_ptr « '"Λn"; status = FALSE; } } if (status && !is_compute_line) *config = in t_value(expr_ptr); // get fifo entry size if (status && !is_compute_line){ expr_ptr = prototype_ptr->port_entry_size_expr(); if (!expr_ptr->has_int.value()) { this_inst->out_eπor("ZON097", ceπ, TRUE); ceπ « "Serial port has an illegal fifo entry size of '" « *expr_ptr « '"Λn"; status = FALSE; } } if (status && tis.compute Jine) *entry_size = (int) int.value(expr.ptr); -523 // restore previous block context this _ϊnst->pop_contextO ; return status;} //process_gpios // Allocate gpios for this block instance, verifying that the numbers // are legal and have not been multiply allocated. iiriiiiiiiiiiiiiiiriiriiiiiiiiiiiiifiiiiiiiiiiiiiiiifiifiiiiifiiiifiiiiiiiiirii BOOLEANzone::process _gpios(instance* this nst) { BOOLEANstatus = TRUE; expr* expr.ptr; ϊnt num; block* prototype . ptr; BOOLEANϊs.output; int ϊ; long gpϊo_config_bits = 0; long gpio.output.field; prototype.ptr = thϊs_ϊnst->prototype(); // save cuπent block context and set instance info in block this_ϊnst->push_context(); // scan for each gpio declared for (1=0; ϊ<prototype_ptr->n_gpios(); i++){ // get expression for gpio number expr.ptr = prototype_ptr->gpϊo_expr(i, &is_output); if (expr.ptr = (expr*) NULL) { thϊs_inst->out_eπor("ZON022", ceπ, TRUE); cerr « "Null gpio number for this instance!\n"; status = FALSE; break; } else if (!expr_ptr->has_int_value()) { thϊs_ϊnst->out_eπor("ZON023", ceπ, TRUE); cerr « "Gpio has an illegal value of '" « *expr_ptr « '" for its numberΛn"; status = FALSE; break; M-524 } // make sure its a legal number if (status) { num = (int) int.value (expr . ptr); if (num >= 0 && num <= max_gpio_number) else { this_inst->out_eπor("ZON024", cerr, TRUE); ceπ « "Illegal gpio number of " « num « "Λn"; status = FALSE; break; } } // allocate gpio number if (!gpios->allocate(num)) { this_inst->out_eπor("ZON013", ceπ, TRUE); ceπ « "Gpio " « num « " has already been used by another blockΛn"; status = FALSE; break; } // set bit for direction of gpio if its an output if (is_output) * { ^ // get bit position for gpio #0 if (get_config_constant(GPIO_OUTPUT_FIELD, &gpio_output_field)) { status = FALSE; break; } // or-in bit in our copy of the gpio config register gpio_config_bits = 1; gpio_config_bits = gpio_config_bits « (num+gpio_output_field); -525 get_zones_whϊch_contains()->or_wϊth_gpio.reg(gpϊo_config_bits); }} // restore previous block context thϊs_inst->pop_contextO ; return status;} II process . rts // Allocate rts' for this block instance, verifying that the numbers // are legal and have not been multiply allocated. iiiiiiiiiiiiiifiriiifiiifiifiiiiiiiiiiiiiiiriiiiiiiiiiiffiiiiiriiiiiiiiiiiiiiii BOOLEANzone::process _rts(instance* this.inst) { BOOLEANstatus = TRUE; expr* expr_ptr; ϊnt num; block* prototype.ptr; BOOLEANis . output; ϊnt i; prototype.ptr = this_ϊnst->prototype(); // save cuπent block context and set instance info in block this_inst->push_context(); // scan for each rts declared for (i=0; ϊ<prototype_ptr->n_rts(); i++){ // get expression for gpio number expr.ptr = prototype_ptr->rts_expr(i, &is_output); if (expr.ptr = (expr*) NULL) { thϊs nst->out_error("ZON022", cerr, TRUE); cerr « "Null rts number for this instance!\n"; status = FALSE; break; } else if (!expr_ptr->has_ϊnt_value()) { thϊs.inst->out_error("ZON023", cerr, TRUE); cerr « "Rts has an illegal value of '" « *expr_ptr « "' for its nuniberΛn"; status = FALSE; break; -526 } // make sure its a legal number if (status) { num = (int) in t.value (expr . ptr); if (num >= 0 && num <= max_rts_number) else { this_inst->out_eπor("ZON024", cerr, TRUE); ceπ « "Illegal rts number of " « num « "Λn"; status = FALSE; break; } } // allocate rts number if (!rts->allocate(num)) { this_inst->out_error("ZON013", ceπ, TRUE); ceπ « "Rts " « num « " has already been used by another blockΛn"; status = FALSE; break; } } // restore previous block context this_inst->pop_context(); return status;} II get.port.setup // get a value for the port setup for the given input or output port index. long zone::get_port.setup(int i, BOOLEAN is.output) { long result; if (is.output) result = outputs.get . configuration(i); else M-527 result = ϊnputs.get.configuratϊon(i); return result;} II is.output.portjiumber // Returns TRUE if the given port number is an output port. BOOLEAN is_output_port.number(int port.num) { return (port.num >= first.out.port && port.num < (first.out.port+n.out.ports));} iiiiπiiiiiiiiiiiiπiiiiimiiiiii iriπii πiiiiiiiiiiimirrπiiiiiiiii II inϊt_port // Set initialization for the registers for a serial port. BOOLEAN zone::ϊnit_port(ϊnt port.num, int buf Jen, int index.len, string* fifo.name, long port.setup, int decim.count, long enable, long wait.mask) { string* name; expr* value; char* port.num.str; BOOLEANis.output; // determine if input or output based on port number // and modify port number for creating register name if (is.output = is_output.port_number(port.num)) portjium = (int) (port.num - first.out.port); else port.num = (int) (port.num - first_in_port); // get a C string for the port number port_num_str = int_to_c_string(port_num); // create name strings and value expressions and init the registers if (is.output) { name = new string(OUT_PORT_BUF_LEN_STR); buf Jen = index.len; } else name = new string(IN_PORT_BUF_LEN_STR); *name = *name + port.num.str; value = new expr((long) buf Jen); if (!ϊnιt_hardware_register(name, value)) return FALSE; if (tis_outpuf){ M-528 name = new string(IN_PORT_FIFO_IX_STR); *name = *name + port_num_str; value = new expr(Qong) index Jen); f if (!init_hardware.register(name, value)) »• return FALSE; } - ' if (is . output) name = new string(OUT_PORT_FIFO_START_STR); else name = new string(IN_PORT_FIFO_START_STR); *name = *name + port . num . str; value = new expr(fifo . name); if (!init_hardware_register(name, value)) return FALSE; if (is.output) name = new string(OUT_PORT_CONFIG_STR); else name = new string(IN_PORT_CONFIG_STR); *name = *name + port.num.str; value = new expr(flong) port.setup); if (!init_hardware_register(name, value)) return FALSE; if (is_output){ name = new string(OUT_PORT_DECIMATTON_STR); *name = *name + port . num . str; value = new expr(Qong) decim.count); if (!init_hardware_register(name, value)) return FALSE; name = new string(OUT_PORT_ENABLE_STR); *name = *name + port . num . str; value = new expr(Qong) enable); if (iini t_hardware_register(name, value)) return FALSE; name = new sιring(OUT_PORT_WArT_MASK_STR) ; *name = *name + port . num . str; value = new expr((long) wait . mask); if (!init_hardware_register(name, value)) return FALSE;} return TRUE;} M-529 // ini t.por ..registers // Set initialization for all port registers in use. BOOLEAN zone::init_port_registers() { BOOLEANϊs.output; string* name; string* valuejiame; expr* value.expr; long value; ϊnt trigger; BOOLEANstatus = TRUE; // scan all inputs to zone is.output = FALSE; for (i=0; ϊ<n_zone_ϊnputsO; i++){ // ignore compute lines if (!inputs.ϊs_compute.input(i)) { // get all config info port.num = inputs.whϊch_port(i); // set buf.len at run-time so input port doesn't start on download buf.len = 0; index.len = 2'// index length is always 2 = double buffering // include user top block instance in fifo name! fifo.name = new string(USER_TOP_NAME); *fifo_name = *fifo_name + "." + *(ϊnputs.fifo_name(i)); port.setup = get_port_setup(i, is.output); wait.mask = 0; decϊm.count = 0; enable = 0; if (!mit_port(por tjium, buf.len, index.len, fifo.name, M-530 port . setup, decim_count, enable, wai tjnask)) { status = FALSE; break; } } } if (istatus) return status; // scan all outputs from zone is_output = TRUE; for (i=0; i<n_zone_outputs(); i++){ // get all config info port.num = outputs.which.port(i); buf.len = outputs.fifo.buf.length(i); // for output fifo, index is really fifo length! // make sure to add fudge factor to fix hardware - NOT ANYMORE! // index.len = outputs.fifo.size(i) + FIFO.SIZE.FUDGE; index.len = outputs.fifo.size(i); // include user top block instance in fifo name! fifo.name = new string(USER_TOP_NAME); *fifo_name = *fifo_name + "." + *(outputs.fifo_name(i)); port.setup = getjpor t_setup(i, is.output); enable = 0; // set decimation factor, which is 1 for a master zone // but may be >1 for a subzone if (is_sub_zone()) decim.count = ((sub.zone*) this)->decimation(); else decim.count = 1; // get any trigger for the output port, else use input trigger for zone trigger = outputs.ge tjrigger(i); if (trigger != NO.TRIGGER) wait.mask = get.wai t_mask(i, TRUE); else wait.mask = zone_mask();// trigger on mask for zone timing if (!init_port(por tjium, bufjen, indexjen, fifojiame, port.setup, decim.count, enable, wait.mask)) { status = FALSE; break; } } // set default values for the port clock rates for (i=0; i<n_ports; i++){ • if (is.output = ϊs_output_port_number(i)) port_num = (int) (i - first.out_port); else port_num = (int) (ϊ - first.in.port); if (is.output) name = new string(OUT_CLOCK_STR); else name = new string(TN_CLOCK_STR); *name = *name + iπt_to_c_strϊng(port_num); // look up values supplied in io.sdf if (is.output) value.name = new string(OUT_CLOCK_VAL_STR); else value.name = new string(TN_CLOCK_VAL_STR); *value_name= *value_name + intjo_c_string(port_num); ϊf (get_config_constant(*value_name, &value)) { status = FALSE; break; } value.expr = new expr(value); if (. r ϊnϊt_hardware_regϊster(name, value.expr)) { status = FALSE; break; } } return status;} If ϊnϊt.hardwarejregister // Add the initialization for a hardware register with the given name. // Called with an expression for the initialization; //// m///////// ////ι///////// ///// ////ιι/ιι/// /f f///ιιιι BOOLEAN zone::init.hardware_register(string* regjiame, expr* value) { ϊnt index; if (!top_instance->prototype()->look_up_storagej ame(reg_name, &index)) { M-532 user_top_instance->out_error("ZON036", cerr, FALSE); cerr « "Couldn't find the hardware register named '" « *reg.name « '" to do initializationΛn" « "Is your 'initsdl' file cuπent?\n"; return FALSE;} top_instance->prototype()->add_storage_init(index, value); return TRUE;} II build . in . fifo.name // Build the name string for input fifo i. string* zone::build_in_fifo_name(int i){ string* name; name = new string(true_zone_chars()); *name = *name + IN . FIFO . STR + int_to_c_string(i); return name; } II build.in . fifo . out.ptr.name // Build the name string for output ptr for input fifo i. string* zone::build_in_fifo_out_ptr_name(int i){ string* name; name = new string(tirue_zone_chars()); *name = *name + IN.FIFO.STR + OUT.PTR.STR + SEPARATOR.STR + int_to_c_string(i); return name;} II build.out.fifo.name // Build the name string for output fifo i. string* zone::build_out_fifo_name(int i){ string* name; name = new string(true_zone_chars()); *name = *name + OUT_FIFO_STR + int_to_c_string(i); return name;} /////////////////////////////////////////////////////////////////////////////// // build_out_fifo_in.ptr.name // Build the name string for input pointer to output fifo i. M-533 string* zone::buiId_out_fifo_ϊn_ptr_name(int i) { string* name; name = new string(tirue_zone_charsO); *name = *name + OUT.FIFO.STR + IN.PTR.STR + SEPARATOR.STR + intjo_c_string(i); return name;} iiiπmiuπiimiiiniuimimmmimuumiiiπmuiuiiiiimiiiiiii II get.in . fifo.buffer.size // Get the size for input fifo ϊ. // If error, output msg and return 0. int zone::get_in_fifo_buffer_sϊze(int i) { ϊnstance*inst; block* proto.ptr; int wire; expr* e; ϊnt entry.size; // evaluate the fifo input buffer width inst = pending_instance(i); proto.ptr = inst->prototype(); wire = pending.wire(i); e = proto_pti»storage_entry_size(wire); if (e->has_int_value()){ entry.size = (ϊnt) int_value(e); if (entry.size <= 0) { inst->out_error("ZON037", cerr, FALSE); cerr « "Input wire "' « *proto_ptr->storage.name_at_index(wire) « '" has an illegal width of " « entry.size « "Λn"; return 0; } else if (entry.size > 1) { inst->out_eπor("ZON038" τ cerr, FALSE); cerr « "Input wire '" « *proto_ptr->storage.name_at_index(wire) M-534 « "' has a width of " « entry . size « "Λn Vector inputs are not yet supportedΛn"; return 0; } } else{ inst->out_eπor("ZON039", cerr, FALSE); cerr « "Input wire '" « *proto_ptr->storage_name_at_index(wire) « '" has an unknown widthΛn"; return 0; } return entry.size;} II get.out_fifo_buffer.size // Get the size for output fifo i. // If error, output msg and return 0. int zone: :get_out.fifo_buffer_size(int i) { instance *inst; block* proto_ptr; int wire; expr* e; int entry_size; // evaluate the fifo input buffer width inst = outputjnstance(i); proto.ptr = inst->prototype(); wire = outpu t_wire(i); e = proto_ptr->storage.entry_size(wire); if (e->has_int_value()){ entry.size = (int) int . value(e); if (entry.size <= 0) { inst->out_error("ZON040", ceπ, FALSE); ceπ « "Output wire '" « *proto_ptr->storage_name_at_index(wire) « '" has an illegal width of " « entry_size « "Λn"; return 0; } -535 else if (entry.size > 1) { inst->out_eιτor("ZON04r, cerr, FALSE); cerr « "Output wire "' « *proto_ptr->storagejname_at_index(wire) « " « has a width of " « entry_sϊze « "Λn. Vector inputs are not yet supportedΛn"; return 0; }} elsc{ inst->ou _.crror("ZON042 , \ cerr, FALSE); cerr « "Output wire "' « *proto_ ptr->storage_name„at_index(wire) « '" has an unknown widthΛn"; return 0;} return cntry_size;} II make_phantom_wires // Make a new level of phantom wire for each pending input //Returns FALSE if failed to make phantom wire. BOOLEAN εone::make_phantom_wiresO{ ml I; int level; instance*inst; int wire; int index; int newjndex; siring* name; string* newjname; BOOLEANstatus = TRUE; char type; for (M ) ; i<pcnding_sizeO; i++) { inst * pendingjnstaπce(i); wire = pending_wire(i); // get wire index for last phantom for this wire index * inst->getJast_phantom(wire , &level); // get name of this wire, and type name = inst->prototype()->storage_name_at_index(index); type = inst->prototype()->get_storage_type(index); // prepend a "_" to the name for the new wire name new.name = new stringC'."); *new_name = *new_name + *name; // add this wire to the instance status = inst->add_phantom_storage_name(new_name, NULL, &new_index, type); if (Istatus) { inst->out_error("ZON054", cerr, FALSE); cerr « "A phantom wire named '" « *new_name « '" already exists !\n"; break; } // make a link from the previous wire to the new wire // also, duplicate any timezone for the wire to its phantom. inst- >set_phantom_link_and_zone(index, newjndex, inst->get_zone_for_wire(index));} return status;} II make.phantom.wires // Make a new level of phantom wire for each pending input, // but only if used in next code section. // Returns FALSE if failed to make phantom wire. BOOLEAN zone::make_phantom_wires(in t.array* top_of_next.copy){ int i; int level; instance*inst; int wire; inl index; int newjndex; string* name; suing* new_name; BOOLEANstatus = TRUE; char type; for (i=0; i<pending_size(); i++){ if ((*top_of_next_copy)[i] != NOTHING) M-537 { inst = pending_instance(i); wire = pending_wire(i); // get wire index for last phantom for this wire index =inst->get_last_phantom(wir , &level); // get name of this wire, and type name = inst->prototype()->storage_name_at_index(index); type = inst->prototypeO->get_storage_type(ϊndex); // prepend a "_" to the name for the new wire name new.name = new stringC'."); *new.name = *new_name + *name; // add this wire to the instance status = inst->add_phantom_storage.nanιe(new_name, NULL, &new Jndex, type); if (Istatus) { inst->out_error("ZON054", cerr, FALSE); cerr « "A phantom wire named '" « *new.name « " c already exists I\n"; break; } // make a link from the previous wire to the new wire // also, duplicate any timezone for the wire to its phantom. inst->set_phantom_link_and_zQne(index, newjndex, inst->get_zone_for_wire(index)); }} return status;} iiiiiiiiiiiiiiiiiiiiiiiiiiifiiiiirririiiiiiiiiiiiiifiiiiiiiifiiriifiiiiifiiiiii // find.block // Find a block prototype name. // If not found, output an error message and return NULL, else return // a pointer to the block. block*find_bIock(string* prototype . name) { block*proto_ptr; if (!prototype_blocks.fmd(*prototype_name, &proto_ptr)){ user_top_instance->out_error("ZON055", cerr, FALSE); cerr « "Unable to find '" « *prototype_name « "' block.\n" M-538 « "Is your 'initsdl' file current?\n"; return NULL;} return proto.ptr;} II seg_fiag_name // Return the name of the given segment flag. Names are kept in an array so // that they don't have to be reconstructed. string* zone::seg_flag_name(int i){ string* name; if (seg_flag_names[i] == (string*) NULL){ // build the segment name name = new string(get.zone_chars()); *name = *name + SEG.STR + int_to_c.string(i); seg_flag_names[i] = name;} return seg_flag_names[i];} /////////////////////////////////////////////////////////////////////////////// // make se g ment flag // Make a new segment (turnstile) flag for the given zone and segment, in the // current instance, and return its string. // Also return the wire index for the flag in our instance. // Returns NULL if could not make this flag. string* zone::make_segment_flag(int* index_ptr){ string* name; // get the segment name name = seg _flag_name(seg_num()); // add this flag as a wire to the user's top instance so we can locate it // from anywhere! if (luserjop Jnstance- >add_phantom_storage_name(name, NULL, index.pti-, )){ user_top_instance->out_error("ZON056", cerr, FALSE); cerr « "A phantom wire named '" « *name « "' already exists!\n"; name = NULL; } return name; } II loop.counter.name // Return the name of the given loop counter. M-539 string* zone::loop_counter_name(int i){ string* name; // build the loop counter name name = new string(get_zone_chars()); *name = *name + LCOUNTER.STR + int o_c_string(i); return name;} iiui uπnim iiiπππiπiπii iiiiiiiiinuiiiiπi iπiiiiiiiiii If make.loop.counter // Make a new loop counter for the given zone and segment, in the current // instance, and return its string. // Also return the wire index for the counter in our instance. // Returns NULL if could not make this counter. string* zone::make_loop_counter(int* index.ptr, instance** ins t_ptr){ string* name; static inti=0; // get the next loop counter name name = loop_counter_name(i++); // add this counter as a wire to the user's top instance so we can locate it // from anywhere! if (!user_top_instance->add_phantonι_storage.name(name, NULL, index.ptr, )){ user_top_instance->out_error("ZON057", cerr, FALSE); cerr « "A phantom wire named "' « *name « "' already exists!\n"; name = NULL;} // return instance for wire *inst_pιr = user op.instance; //return the name return name;} II modify_pendϊng_in // Call with the index of the child just processed in partitioning, this // function adds pending inputs as required to the list of pending inputs, // and removes any which are no longer needed. // NOTE: If the child is a zone output, its input is left alone so that // it will be c.j ied until the end f the zone M-540 // Returns FALSE if error. /////////////////////////////////////////////////////// /////////////////////// BOOLEAN zone::modify_pending_in(int i, instance* this . inst) { int ii; instance *child; block* prototype . ptr; hier_block*hier_ptr; block* child.proto type; instance*which_instance; int which.wire; block_ref*ref_ptr; zone* wire_zone; BOOLEANalways.process; // add any new outputs to pending list child = this_inst->get_child(i); child.proto type = child->prototype(); #ifdef DEBUG cerr « "modifying pending in: " « *child->hier_name.string() « "\n"; #endif // always process all I/Os for an indivisible block always.process = child_prototype->is_indivisible_block(); // save pointer to block prototype prototype . ptr = thisjnst- >prototype(); // save pointer to our prototype as a hier block pointer hier.ptr = (hier.block*) prototype.ptr; ref.ptr = hier_ptr->get_child_block_ref(i); // if this is an output block, don't modify pending wires if (child_prototype->is_sproc_output()) return TRUE; for (ii=0; ii<child->get_io_sizes_size(); ii++){ // get wire and instance for next child VO (original, not phantom) if (!child->get_wire_for_io(ii, 0, &which_instance, &which.wire)) { child->out_error("ZON059", cerr, FALSE); cerr « "INTERNAL ERROR - Bad input for parti tioningW; return FALSE; } M-541 // if higher level block, only process wire if it is in our zone! // process wire with no zone info because these are zone inputs wire.zone = which_instance->get.zone_for.wire(which_wire); // if ( (wire.zone == this) II (wire.zone == (zone*) NULL) ) if ( (wire.zone = this) II always_process ) { if (child_prototype->io_is_output(iϊ)) { // child VO is an output, so add to pending wires add_input(which_instance, which.wire) ; #ifdef DEBUG cerr « "adding input " « *which_instance->prototype()-> hier_storage_name.at.index(which_wire) « "\n"; #endif // If the output is part of a loop, set the "wire loop flag" // for this wire. // This assures us of a phantom wire being created, which we // need for the input from the loop. // When we hit the next segment, clear all wire loop flags // that have been previously set. // ignore if no ref_ptr (could be phantom block) if (ref.ptr != (block_ref *) NULL) { if (ref_ptr->is_loop_io(ϋ)) { //found a loop input! // set a loop flag for him, so the wire will stay around // long enough for a phantom wire to be created which //will provide a unit delay to the input pending_wires.set_wire_loop.flag(which_instance, which_wire, child, ii); } } } else { // This child VO is an input, so see if it uses one of our M-542 // wires. // The idea is to determine if he is the last // input which uses this wire or block input. If so, // he is removed from pending inputs list. pending_wires.decrement_usage.count( whichjnstance, which.wire); #ifdef DEBUG cerr « "decrementing usage count for " « *which_instance->prototype()-> hier.storage.name.at . index(which.wire) « "\n"; #endif } } } return TRUE;} II ge t_wai t_mask // Returns the wait mask for the trigger of the given zone input. long zone::get_wait_mask(int i, BOOLEAN is.output) { int trigger . num; long mask; // get port number for this input or output if (is . output) trigger.num = outputs.get_trigger(i); else trigger.num = inputs.ge tjrigger(i); // compute mask such that port 0 = 1, port 1 = 2, port 2 = 4, etc mask = 1; return (mask « trigger.num);} II get_gsp_count // Returns the integer number of gsps required for this zone. // Also returns an exact fractional count of the number of gsps required. int zone::get_gsp_count(double* fractional_count_ptr){ int i; int segment.count; int gsp_count; double exact; M-543 // get number of segments used segment.count = n_segments(); // compute exact gsps by summing cycles in each segment exact = 0.0; for (i=0; i<=segment_count; i++) exact += cycles.used_in_seg(i); // divide by max cycles/zone to get fractional gsp count exact /= max.cycIesO; gsp.count = (int) (exact + 0.99999999); // return to info caller *fractional_count.ptr = exact; return gsp.count;} II origϊnal.zone // Returns pointer to original zone (ourself), plus relative rate of 1.0. //This function gets overloaded in derived sub.zone class. iiiiiiiiifiiiiiiiiiiiiriiiifiiiiiiiiifiiiiriiiiiiifiriiiiiiiiiiiiifiiiiriiiiiii zone* zone::originaI_zone(double* rel.rate_ptr){ *rel_rate_ptr = 1.0; return this;} ' II original.zone // Same, but without relative rate. // This function gets overloaded in derived sub.zone class. zone* zone::original_zone(){ double rel.rate; // ignore rate return original.zone(&rel_rate);} //operator+= // Add another zone to this zone. //Used when partitioning over multi-rate zones, this function // adds partitioning state variables from one zone to the current zone. limiiiumimuiimmiumiuuitiiuiiumuiimumminimiiim zone& zone::operator+=(zone& z){ // add his pending wires to ours M-544 pending_wires += z.pending_wires; return *this;} /////////////////////////////////////////////////////////////////////////////// // original.zone // Traces derived sub-zone back through chain of decimation/interpolation // to its original zone. Returns a pointer to the original zone, plus // the (floating point) sample rate of this zone relative to the original // sample rate. zone* sub_zone::original_zone(double* rel.rate.ptr) { long long.ratio; double rel_rate = 1.0; zone* zone.ptr; zone . ptr = this; while (zone.ptr- >is_sub.zone()) { long_ratio = ((sub.zone*) zone_ptr)->get_ratio(); if (((sub.zone*) zone_ptr)->is_decimating()) rel.rate /= long_ratio; else rel.rate *= longjratio; zone.ptr = ((sub.zone*) zone_ptr)->derived_from_zone();} *rel_rate_ptr = rel.rate; return zone.ptr; } II original.zone // Same, but without relative rate. zone* sub.zone ::original_zone(){ double rel.rate; // ignore rate return origina l_zone(&rel_rate); } // zone2.cxx // functions for zone class // T. Montlick // 1/29/90 // source code control: static char SccsID[] = "@(#)zone2a.cxxl.56 10/7/91"; #ifndef ZONE_DEF #include "zone.hxx" M-545 #endif #undef DEBUG #ϊfdef DEBUG BOOLEANdebug; #endif // following should logically be in temporal class, but produces link error then static int.hash phantom.usage(lθ);// usage count of phantom prototypes II temporal class I* This class does temporal partitioning of an instance over a time zone. Partitioning is done hierarchically, with temporary temporal objects created from child instances. The class scans the sequenced blocks and inserted required phantom blocks and phantom storage to accomplish temporal partitioning at the given sample rate. */ II temporal::temporal // Constructor. temporaI::temporal(zone* z, instance* i, string* flag_s, zone* prev.z) { NOREF(prev.z);// used by derived multi-temporal constructor this.zone = z; thisjnst = i; flag_string = flag_s; adding . init = FALSE; is.multi.temporal = FALSE; } II temporal::-temporal //Destructor. temporal::~temporal() {} II partition // Called recursively to do temporal partitioning for an instance. M-546 // Passed pointers to a list of input wires, plus the corresponding // instances which these wires are in. Also cycles used in segment so // far and max cycles for a segment. // This function automatically inserts phantom instances and phantom wires // for all input wires to create extra segments. II Returns FALSE for the variable "ok" if this is a leaf block and adding // it would overfill the current segment. BOOLEAN temporal: :partition(BOOLEAN* ok, int* duration_ptr){ BOOLEANstatus = TRUE; int i; int which_child; instance*child; hier_block*hier_ptr; instance*which Jnstance; int which_wire; int count; BOOLEANchild.ok; block* prototype . ptr; tenιporal*child_temporal;// ptr to class to do child partitioning int duration; // save current block context and set instance info in block this_inst->push_context(); // assume we won't overfill *ok = TRUE; // save pointer to block prototype prototype.ptr = this_inst->prototype(); // Input wires are specified as a wire index in a parent, and a parent // instance pointer. // If we introduce a new segment, we must copy these input wires to // new phantom wires. // We can remove a wire from the input list only // if no other child block needs it. We determine this by keeping // our own copy of the input count for each wire (the number of inputs // from this wire), a decrementing that count when an input from the // wire is used. When the count goes to zero, we remove the wire from // the input list. // There is a similar count for child inputs from our block inputs. if (prototype_ptr->is_leaf_block()) { M-547 // we leaf block, so see if adding us would bump to next segment if (*ok = add_this_block.duration(&duration)) { ffifdef DEBUG string* hier.name; hier.name = this_inst->hier_name_string(); cerr « "partitioned " « *hier_name « "\n"; #endif // child ok for this segment, so mark this for the instance this_inst->set.seg_number(this_zone->seg_num()); // save last zone partitioned last_zone_for_partitioning = this.zone; // We must set all inputs to use phantom wires as necessary, // rather than ordinary wires that this block was compiled with. // We do this by getting the current "phantom level" for each // input, then recording this in the phantomjevel array for // this instance. for (i=0; i<prototype_ptr->io_table_sizeO; i++) { if (!prototype_ptr->io_is_output(i)) { // get phantom level 0 wire info for this input this_inst->get_wire_for_io(i, 0, &which_instance, &which_wire); // ask this instance current phantom level for wire // and set as phantom VO level this_inst->set_phantom_io_Ievel(i, which_instance->get.phantom_wire_level(which_wire)); } } // if this is a sproc output, must also make output fifo info //for it if (prototype_ptr->is_sproc_output()) status = make_output_fifo(); // ditto for sproc input Λ Ise if (prototype_ptr->is_sproc_input()) status = make.input.fifoO; } //return block duration used/required M-548 *duration_ptr = duration; } // not a leaf block, so see if we are otherwise indivisible // and block will not fit in segment else if (prototype.ptr- >is_indivisible_block() && !test_block_duration( (int) get_this_block_duration())) *ok = FALSE;// return "won't fit" status else{ // save pointer to our prototype as a hier block pointer hier.ptr = (hier . block*) prototype . ptr; // make copy of wire usage counts from our prototype // first tally from ordinary wires for (i=0; i<prototype_ptr->storage_table_size(); i++) { count = hier_ptr->get_wire_use_count(i); this_zone->add_wire_usage_count(this_inst, i, count); } // next tally from this block's I/O (higher level blocks' wires) for (i=0; i<prototype_ptr->io_table_size(); i++) { count = hier_ptr->get_input_use_count(i); this_inst->get_wire_for_io(i, 0, &which_instance, &which_wire); this_zone->add_wire_usage.count(which Jnstance, which . wire, count); } #ifdef DEBUG cerr « "checking children for zone " « *this_zone->get_zone.name() « "\n"; #endif // we are hierarchical block, so call children for (i=0; i<this_inst->get_sequence_size(); i++) { // get next child in sequence which.child = this Jnst- >get_sequence(i); child = this_inst->get_child(which_child); // process child only if he has our time zone if (child->needs_partitioning(this_zone)) { #ifdef DEBUG string* h.name; 89^ M-549 h.name = child->hier_name_string(); cerr « "trying to partition seq # " « i « tt. a « *h_name « "\n"; #endif // Create a temporal object from child in this scope // so we can partition it. // create an object of our type if (is.multi.temporal) childjemporal =new multi emporal(this_zone, child, fiag_string); else childjemporal = new temporaI(this_zone, child, flag_string); // call it, stopping if we need to create a new segment status = child emporaI->temporal::partition(&child.ok, &duration); // if error, get out if (Istatus) break; else if (Ichild.ok) { // must create a new segment before this child status = create_new_segment(duration); if (Istatus) break; // call child again for the freshly added segment status = child_temporal->temporal::partition(&child_ok, &duration); //if error, get out if (Istatus) break; else if (Ichild.ok) { // swap instance so we can correctly get block // duration, which may be overloaded for decim/interp whichjnstance = this.inst; thisjnst = child; M-550 child->out_error("ZON007", cerr, TRUE); cerr « "The sample rate is too highΛn"; out_sample_period_msg(cerr); cerr « ", but this block needs\n" « get.this.block . durationO « " cycles and " « (ending_overhead() + this.zone->cycles_used()) « " phantom cycles are needed to finish " « "the segmentΛn"; status = FALSE; thisjnst = whichjnstance; break; } } // child has been processed, so dispense with inputs wires // as necessary, and add output wires status = this_zone->modify.pending _in(which_child, thisjnst); if (istatus) break; // done with child partitioning object delete childjemporal; // append child to end of partitioned sequence this_inst->append_partitioned(which_child); #ifdef DEBUG string * hier.name; hier.name = child->hier_name_string(); cerr « "Appending " « *hier_name « " at position " « thisjnst- >get_partitioned_size() ; hier.name = thisjnst->hier_name_string(); cerr « " of seq. for " « *hier_name « "\n"; #endif // record last child partitioned in zone // but only if its a non-hierarchical block if (child->prototype()->is_indivisible_block()) this_zone->set_last_in.zone(this_inst, i) ; // record fact that child was partitioned in this zone M-551 child->set_partitioned(this.zone) ; } }} II restore previous block context this_inst->pop_context() ; return status;} II verify.end.zone.fit // Verify that all the end of zone phantom blocks will fit in the current // segment Otherwise, create anew segment. luiiiimmimmumimmuiπiuiiiimmiiinmiimmiimitimii BOOLEAN temporal::verify_end_zone_fit() { BOOLEANstatus = TRUE; ϊnt duration = 0;// for compatibility with partitioning // save current block context and set instance info in block tIιis_inst->push_context(); if (!end_zone_fits()) status = create_new_segment(duraιion); //restore previous block context fhis_inst->pop_contextO ; return status;} miimπimiimimmnimiimiimimuπiiimumiiiimimuiim //find.ϊnput.and.create.segment.O //We must create the zero'th segment directly before the first input to the // zone, so we must hierarchically scan for this input instance. //Then call create.segment.O to create the segment within this instance. // Returns TRUE if segment created by ourselves or from recursive call. MtiMiuiuiimmuimiπimininmitmnmuπiiiumπiiiumiii BOOLEANtemporal::find_iπput_and.create_segment_0(){ block* prototype.ptr; mt 1; int which.child; instance*child; BOOLEANstatus = FALSE; instance*previous_inst; // save current block context and set instance info in block this_inst->push_context() ; //call children for (i=0; i<this_inst->get.sequence_sizeO; i++){ M-552 // get next child in sequence which.child = thisjnst- >get_sequence(i); child = this_inst->get_child(which_child); // process child only if he has our time zone & not found input yet if (child->is_zone_present(this_zone) && istatus) { // save pointer to child block prototype prototype.ptr = child->prototype(); // if this child is sproc input, create the O'th segment here if (prototype_ptr->is_sproc_input()) status = create.segmen t_0(); // else call child if he is hierarchical else if (!prototype_ptr->isJeaf_block()) { // first set child instance as current one previous . inst = thisjnst; thisjnst = child; status = find_input_and_create_segment_0(); thisjnst = previous.inst; } } } // restore previous block context thisjnst- >pop_context() ; return status;} II create.segment.O // Segment 0 is created at the start of temporal partitioning. // We must: // 1. Create a label for loop back from the end of the time zone. // 2. Create segment flag phantom wires for segments 0 and 1. // 3. Instantiate a ".turnstile" block to wait for segment 1 free. // 4. Instantiate a ".free.seg" block to free segment 0. BOOLEANtemporal::create_segment_0(){ int seg Jndex; // wire index for new segment string* zeroth.flag_string; strine* first flag strins; string* label; BOOLEANstatus = TRUE; -553 // // save current block context and set instance info in block // this_inst->push_context(); // create the label for GSP loop back // tie it to the next instance, which will be a fifo or flag wait block label = new string(LOOP_STR); *label = *IabeI + this_zone->get_zone_chars(); // set this label (hierarchically named) in the temporal class loopbackjabel = new stringC"'); *loopback_label = *loopback_label + *this_inst->hier_name_string() + "." + *label; if (!this_inst->add_phantom Jabel_name(label, this_inst->get.n.children())) { this_inst->out_error("ZON032", cerr, TRUE); cerr « "The phantom label '" « *label « '" already exist!\n"; status = FALSE;} // make a segment flag for the 0th segment if (status) { zeroth_flag_string = this_zone->make_segment_flag(&seg Jndex); if (!zero _flag_string) status = FALSE;} // make a segment flag for the first segment if (status) { // turnstile code exists in O'th segment, but account for it in first, // since we always have O'th as an extra segment and it would not get // otherwise accounted for (we would not add a segment after the // first at the correct number of cycles). this_zone->bump_segment() ; first_flag_string = this_zone->make.segment_fiag(&seg Jndex); if (!first_flag_string) status = FALSE;} // instantiate a turnstile for the first segment if (status) { #ifdef DEBUG cerr « "making turnstile for zone " « *this_zone->get_zone_name() « "\n"; #endif if (!make u stae(first_flag_string, 1)) status = FALSE;} // we have now officially entered the first segment, so M-554 // instantiate a free.segment block for segment 0 if (status) { if ( !make_free_segment(zeroth_flag_string)) status = FALSE;} // set contents of temporal class' flag string to first flag string if (status) *flag_string = *first_flag_string; // // restore previous block context // this_inst->pop_context(); return status;} II ini t.for.partition BOOLEANtemporal: :init_for_partition() { // insert a make probe reset block at the top of main loop if (!make_pr_rese t.blockO) return FALSE; return TRUE;} II create.new.segment // It was determined that a new segment should be added. // We must: // 1. Create a segment flag phantom wire for the new segment. // 2. Instantiate a ".turnstile" block to end the current segment. // 3. Create phantom wires for all pending inputs. // 4. Instantiate ".copy" blocks to copy to these phantom wires. // 5. Instantiate a "Jree.seg" block. BOOLEANtemporal::create_new_segment(int duration) { int seg Jndex; // wire index for new segment string* new_flag_string; NOREF(duration); // set overhead cycles we had to allow for in this segment this_zone->set_overhead_allowed_for(ending_overhead()); // advance to next segment this_zone->bump_segment(); // (1) create a new segment flag, and return its name new.flag.string = this_zone->make_segment_flag(&seg Jndex); if (!new_flag_string) M-555 return FALSE; // (2) instantiate a turnstile for this new segment if (!make_turnstile(new_flag_string, this_zone->seg_num())) return FALSE; // (3) create phantom wires for all pending inputs if (!this_zone->make_phantom_wires()) return FALSE; // (4) instantiate copy blocks for wires if (Imake.copy.blocksO) return FALSE; // free any wires that are hanging around because they are loop inputs this_zone->free.pending_loop_wiresO; // (5) instantiate a free.segment block, passing current flag name if ( !make_free_segment(flag_string)) return FALSE; // set contents of temporal class' flag string to new flag string *flag_string = *new_flag_string; if (fhis_zone->cycles_used() > this_zone->max_cycles()){ thisJnst->out_error("ZON033", cerr, TRUE); cerr « 'The sample rate is too highΛn"; ou t_samρle_period_msg(cerr) ; cerr « ", but " « this_zone->cycles_used() « " overhead cycles are required to create a new segmentΛn"; return FALSE;} return TRUE;} If out.sample_period.msg // Output a msg giving the cycles in one sample period. // Overloaded by multi-temporal class to output cycles in N sample periods // for decimation/interpolation. void temporal::out_sample_period_msg(ostream& out){ out « "One sample period provides " « thϊs_zone->max_cycles() « " cycles";} II make.zone .finish // Add the turnstile and jump blocks at the end of a zone. M-556 // Called after the ending fifo blocks are instantiated. // /////////////////////////////////////////////////////////////////////////////// BOOLEAN temporal: :make_zone_finish() { string* zeroth.seg jiame; BOOLEANstatus = TRUE; int n.segments; // save current block context and set instance info in block this_inst->push_context(); // get # of segments partitioned n . segments = this_zone->seg_num(); // get segment flag string for the Oth segment zeroth_seg_name = this.zone->seg_flag.name(0); // instantiate a turnstile to wait for the zeroth segment // but first advance to next segment this_zone->bump_segment(); if (!make.turnstile(zeroth_seg_name, 0)) status = FALSE; // instantiate a free.segment block, passing current flag name if (status) { if (!make_free_segment(flag_string)) status = FALSE;} if (status) { if (!make ump_block(loopback_label)) status = FALSE;} if (status) status = generate_GSP_init_code(n_segments, zeroth_seg_name, loopback Jabel); // restore previous block context this Jnst- >pop_context() ; return status;} II generate.GSP.init.code // Create code to initialize each GSP, including initializing FIFO pointers. BOOLEAN temporal: :generate_GSP_init_code(int n.segments, string* zeroth_seg_name, string* loopback.label) { int n_gsps; double dummy; string* label; string* seg_name; instance*child; int ϊ,j; BOOLEANstatus = TRUE; // generate the initialization code for each GSP // set us in "adding init blocks" mode, so we do separate cycle // accounting which doesn't count toward gsps or segment limit addingjnit = TRUE; // get # of gsps required for this zone n_gsps = this_zone->get_gsp_count(&dummy); for (i=0; i<n_gsps; i++){ // create the label label = new string(GSP_START_STR); // use next available GSP number, allocating this *Iabel = *label + mtjo_c_string(gsp_allocator->ge t_next_gsp()); // tie it to the next child to be added if ( !this_inst->add_phantom_labeI_name(label, this_inst->get_n_childrenO)) { this_inst->out_error("ZON034", cerr, TRUE); cerr « "Phantom label '" « *label « '" already exist!\n"; status = FALSE; break; } // create the code // First set the number of gsps as the initial value for segment 0 // turnstile flag. This gets decremented by each successive gsp // so that the last one leaves it as zero, and the segment is // therefore free. if (Kstatus = make_copy_constant.block(zeroth_seg_name,(long) n_gsps))) break; // next init the rest of the segment flags to zero for (j=l; j<=n_segments; j++) { seg_name = this_zone->seg_flag_name(j); if (Kstatus = make_copy_constant_block(seg_name, (long) 0))) break; } if (istatus) break; // set block as an init block for our info // block is last child index child = this_inst->get_child(this_inst->get_n_children()-l); child->set_init(); // 0th GSP must init all fifo pointers if (i =- 0) { if (Kstatus = initJnput.fifo.ptrsO)) break; if (! (status = init_output_fifo_ptrs())) break; // do run-time init of input port registers if (! (status = run _time . input.port _init())) break; } else { // every other GSP must wait for its respective flag value // which is n_gsps-i if (! (status = make_wait_seg_flag_block(zeroth_seg_name, (long) (n_gsps-i)))) break; // set block as an init block child = thisjnst- >get_child(this_inst->get_n_children()-l); child->set_init(); } // finally, initial jump to start of loop if (Kstatus = make ump . block(loopbackjabel))) break; // set block as an init block child = this_inst->get_child(this_inst->get_n_children()-l); child->set_init();} return status;} II runjime.input.por t . init 90k -559 // Generate the code for the run-time portion of the input port initialization, // Le. initialization that should not be done via a static download. uimimuπ π miiuuiui πiiii ii i iiiiiiiiπiiiiiiiiuiii BOOLEAN temporal::ran_time_input_port nitO { int * buf.len; char* port_num_str; string* name; BOOLEANstatus = TRUE; instance*child; // scan all inputs to zone for (int j=0; j<this_zone->n.zoneJnputs(); j++){ // ignore compute lines if ( !this_zone->is . compute _input(j)) { // get fifo buffer length for run-time initialization buf.len = this_zone->input_fifo_buf JengthQ)". // name name string for the fifo buffer length port register name = new string(TN_PORT_BUF_LEN_STR); // get a C string for the port number port.num.str = int.to_c.string((int) (this_zone->which_input_port(j) -first.in.port)); *name = *name + port.num.str; // instantiate block to set the fifo buffer length if ({(status =make.copy_constant_block(name, (long) buf.len))) break; // set block as an init block child = this_inst->get_child(this_inst->get_n_children()-l); child->set_init(); }} return status;} wiiiiiiπii iiiuiuiiiiuiiniiniπiiiiiiiiiiiiiiiiiiiii iπiiiiiiiii If init_input.fifo.ptrs // Generate the initialization code to init the input fifo ptrs. BOOLEAN temporaI::ϊnit_input_fifo_ptrsO { ϊnt fifo.sϊze; suing* fifo.name; BOOLEANstatus = TRUE; int ptr . index; instance*ptr_inst; instance*child; // scan all inputs to zone for (int j=0; j<this_zone->n_zone_inputs(); j++){ // ignore compute lines if (!this_zone->is_compute_input(j)) { fifo . size = this_zone->input_fifo_size(j); fifo.name = this_zone->input_fifo_name(j); if (fifo.name == (string*) NULL) { user_top_instance->out_error("ZON903", cerr, FALSE); cerr « "INTERNAL ERROR - No input fifo " « "for zone input " «j « ".\n"; status = FALSE; break; } // make copy fifo addr to input fifo input ptr this_zone->input_fifo_in_ptr(j, &ptr_index, &ptr_inst); if ([(status = make_copy_addr_block( fifo.size, fifo . name, ptr . index, ptr . inst))) break; // set block as an init block child = this_inst->get_child(this_inst->get_n_children()-l); child->set_init(); // make copy to input fifo output ptr this_zone->input_fifo_out_ptr(j, &ptr_index, &ptr_inst); if (! (status = make_copy_addr_block( fifo . size, fifo.name, ptr . index, ptr.inst))) break; // set block as an init block child = this_inst->get_child(this_inst->get_n_children()-l); child->set_init(); } } return status;} M-561 II inϊt.output.fifo.ptrs // Generate the initialization code to init the output fifo ptrs. BOOLEAN temporal::init_output_fifQ_ptrsO { ϊnt fifo.size; string* fifo.name; BOOLEANstatus = TRUE; int ptr.index; instance*ptr_ϊnst; instance*child; // scan all outputs from zone for (int j=0; j<this.zone->n_zone_outputs(); j++){ fifo.size = thϊs_zone->output_fifo_sϊze(j); fifo.name = this_zone->output_fifo.name(j); if (fifo.name = (string*) NULL) { user_top_instance->out_error("ZON904", cerr, FALSE); cerr « 'TNTERNAL ERROR ~ No output fifo " « "for zone output " «j « ".\n"; status = FALSE; break; } // make copy to output fifo ptr this_zone->output_fifo_ptr(j, &ptr_index, &ptr_inst); //zero cycles used so we don't get screwed up by init blocks if (Kstatus = make_copy_addr_block(fifo_size, fifo.name, ptr.index, ptr.inst))) break; // set block as an init block child = mϊs_mst->get_chπd(ι s_inst->get_n.chϊldren()-l); child->set _init();} return status;} II make.ϊnput.fifo // Makes an input fifo for the current input block instance. // Also create buffer input pointers for each fifo. // Also create buffer output pointers for each fifo. M-562 // Returns FALSE if failed to make any fifo. /////////////////////////////////////////////////////////////////////////////// BOOLEAN temporal: :make_input_fifo() { int i; string* fifo_name; string* out.ptr.name; BOOLEANstatus = TRUE; int fifo.size; expr* fifo.size . expr; int entry.size; int fifo . wire; int out_ptr_wire; int depth; // input fifo depth is repeat count for the zone depth = (int) this_zone->get_repeat_count(); // find the fifo which corresponds to this port instance for (i=0; i<this_zone->n_zone_inputs(); i++){ if (istatus) break; if ( this_zone->input_port_instance(i) == thisjnst) { // make fifo if not a compute line if (!this_zone->is_compute_input(i)) { // get the fifo name fifo.name = this_zone->build_in_fifo_name(i); // get fifo entry size (buffer length) which we found when // we evaluated port info // we need this only to compute fifo size entry.size = this_zone->input_fifo_buf_length(i); // make a size expression for the fifo fifo.size = entry_size*depfh*2; fifo.size.expr = new expr((long) fifo.size); // add this fifo to our top instance status = user_topJnstance->add_phantom_storage_name(fifo_name, fifo . size.expr, &fifo.wire, T); if (istatus) { this_inst->out_error("ZON043", cerr, FALSE); M-563 cerr « "A phantom wire named '" « *fifo_name « '" already exists!\n"; break; } // build the input fifo output ptr name out.ptr.name = this_zone->build_in_fifo_out_ptr_name(i); // add this to the top instance status = user op.instance-> add_phantom_storage_name(out_ptr_name, (expr*) NULL, &out_ptr_wire, 'h'); if (Istatus) { this_inst->out_error("ZON044", cerr, FALSE); cerr « "A phantom wire named '" « *out_ptr_name « '" already exists!\n"; break; } // save this and other fifo info this_zone->set_zone_input.fifo(i, fifo.name, depth, out.ptr.wire, user.top.instance); } if (status) status = make_input_fifo_instance(i); }} return status;} II make nput.fifo.ϊnstance // Instantiate the input fifo instance, or compute line instance. // If no fifos or compute line inputs, report an error. // Returns FALSE if error. BOOLEAN temporal::make_input.fifo_instance(int i){ string* fifo.name; BOOLEANstatus = TRUE; long fifo.size; ϊnt entry.size; instance*inst; ϊnt out.ptr.wire; string* out.ptr.name; M-564 int in . ptr.wire; string* in_ptr_name; long wait_mask; int depth; instance*our_inst = thisjnst; if (this_zone->is_compute_input(i)){ // compute line, so do special thing // make sure this is a real trigger number, that trigger instance // is not supplied by user, and that this the first compute wait // instance to instantiate // if (this_zone->which_input_port(i) != NO . TRIGGER if ( !this_zone->is_user_triggered() && !lhis_zone->is_compute_wait_inst_set()) { // // get mask for this compute line // wait.mask = this_zone->get_wait_mask(i, FALSE); // get input mask for this zone wai t_mask = this_zone->zone_mask(); // if we must do compute line polling, make special block if (this_zone->compute_pollingO) { // (just need to do once) if (compute_ctr_wait_mask == OL) { intctrjndex; instance*ctr_inst; compute_ctr.wait.mask = wait.mask; ctr.index = ιhis_zone->get_compute_ctr(&ctr.inst); // make block at same level as us, so must // pop up to parent thisjnst = this_inst->parent(); if (!make_wait_nonzero_compute_block(wait_mask, ctrjnst, ctr.index)) status = FALSE; thisjnst = our.inst; } } else { M-565 // instantiate a.wai t.for.flags block this.inst = this nst->parent0; #ifdef DEBUG string* hier.name; hier.name = this_inst->hier_name_stringO; cerr « "making a wait for flags block in " « *hϊer.name «"\n"; #endϊf if (!make_wait_for_flags_block(wait_mask)) status = FALSE; this.inst = our.inst; // record fact that we have instantiated a wait for // compute line instance so we don't accidentally make // another one this_zone->set_compute_wait_inst(); }} else{ //input port // get size of one fifo buffer entry.size = this_zone->ϊnput_fifo_buf _length(i); // get depth of fifo depth = this_zone->input.fifo_depth(i); // compute size for the fifo fifo.size = (long) entry_size*depth*2; // get input fifo output ptr wire index, then name thϊs_zone->ϊnput_fifo_out_ptr(i, &out_pιr_wire, &inst); out.ptr.name = inst->prototype()-> hϊer_storage_name_at_ϊndex(out_ptr_wire); // get input fifo input ptr wire index, then name this_zone->input_fifo_in_ptr(i, &in.ptr_wϊre, &inst); in_ptr_name = inst->prototypeO-> hier_storage_name_at_index(in_ptr_wire); // get the fifo name fifo.name = this_zone->ϊnput_fifo_name(ϊ); // now create the symbols required by this input block instance // create array of parameter expressions expr* param_vals[4]; param_vals[0] = new expr (fifo.size); param_vals[l] = new expr(fifo_name); M-566 param_vals[2] = new expr(out_ptr_name); param_vals[3] = new expr(in_ptr_name); // static array of parameter names (no static string arrays allowed) static char* names_chars[] = { "fifo_size", "fifo", "out_ptr", "in.ptr"} ; string param_names[4]; param_names[0] = names_chars[0]; param_names[l] = names_chars[l]; param_names[2] = names_chars[2]; param_names[3] = names_chars[3]; // add parameter names and expressions to override parameter if (!add_parameters(4, param_names, param_vals)) status = FALSE;} return status;} II verify.inputs // Make sure there are valid inputs from ports or compute lines. // Returns FALSE if error. BOOLEAN temporal: :verify_inputs() { int i; BOOLEANstatus = TRUE; BOOLEANno.trigger = FALSE; int inputs . count = 0; // first scan zone for any compute lines for (i=0; i<this_zone->n_zone_inputs(); i++){ if (this_zone->is_compute_input(i)) { // make sure this is a real trigger number if (this_zone->which_input_port(i) != NO . PORT) // tally this input inputs_count++; else no .trigger = TRUE; } else // tally this input inputs_count++; } // check for no inputs to zone M-567 if (status && (inputs . count = 0)){ if (nojrigger) { this_inst->out_error("ZON045", cerr, FALSE); cerr « "There is a signal source but no trigger for this" « "block's time zoneΛn"; } else { this_inst->out_error("ZON046", cerr, FALSE); cerr « "This block's time zone has no signal source.\n"; } status = FALSE;} return status;} iiiiiifiiiiiiiiiiiififiiiiiiifiiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiriiiifinir II add.input.fifo.info // When manually partitioning: // Add input fifo info for each pending input. // Returns FALSE if failed. BOOLEAN temporal::add_input_fifo_info(int depth){ ϊnt i; string* name; BOOLEANstatus = TRUE; int out.ptr.wire; for (i=0; i<this_zone->pendϊng_size(); ϊ++){ // add the new fifo info to this zone // build the output ptr name name = this_zone->build_in.fifo_out_ptr_name(i); // look up its wire index if (!this_inst->prototype()->look_up_storage_name(name, &out_ptr_wire)) { this_inst->out_error("ZON047", cerr, FALSE); cerr « "Unable to find the input fifo out ptr '" « *name « '"Λn"; status = FALSE; break; } // get the fifo name M-568 name = this_zone->build_in_fifo_name(i); // save this and other fifo info this_zone->set_zone_input.fifo(i, name, depth, out.ptr.wire, this nst);} return status; } II make.outpu t.fifo // Makes an output fifo for the current output block instance. // Also create buffer input pointers for each fifo. // Returns FALSE if failed to make the fifo. BOOLEAN temporal: :make_output_fifo() { int i; string* fifo.name; string* fifo.ptr.name; BOOLEANstatus = TRUE; long fifo.size; expr* fifo.size.expr; int entry.size; block* proto.ptr; int fifo.wire; int in.ptr.wire; int depth; int dummy; string* depth.symbol.name; expr* depth.expr; double exact_gsps; int out.enable; string* enable.name; // depth of output fifos is # of gsps times repeat count for zone depth = this_zone->get_gsp_count(&exact_gsps); // make sure to count # of cycles that fifos will add exact_gsρs += ((double) end_zone_cycles())/this_zone->max.cycles() ; depth = (int) ( (int) (exact_gsps + 0.99999999) * this_zone->get_repeat_count()) ; depth.expr = new expr((long) depth); // find the fifo which corresponds to this port instance for (i=0; i<this_zone->n_zone_outputs(); i++){ if (istatus) 91k break; if ( this_zone->output_port_iπstance(i) = this nst) { // build the fifo name fifo.name = this_zone->build_out_fifo_name(i); // Add the symbol for the fifo depth, which is used by // add.output.fifo.info depth.symbol.name = new stringC'"); *depth_symbol_name = *depth.symbol_name + *fifo_name + DEPTH_STR; // see if symbol exists as override in true top instance proto.ptr = top_instance->prototype(); if (proto_pιr->Iook_up_symbol_name(depth_symbol_name, &depth_expr) ) { int dummy 1, dummy2; depth = (int) depth_expr->ϊnt_value(&dummyl, &dummy2); } else { // put it in user top instance proto.ptr = user_top_instance->prototype(); status = proto_ptr->add_symbol_name(depth_symbol_name, &dummy); if (status) status = proto_ptr->add_expression_name(deplh.symbol_naιne, depth.expr); else { if (proto_ptr->look_up_symbol_name(depth_symbol_name, &depth_expr)) { int dummyl, dummy2; depth = (int) depth_expr->int_value(&dummyl, &dummy2); } } } // make sure valid fifo depth, since user may have supplied it if (depth < 1) { this_inst->out_errorC'ZON077", cerr, FALSE); cerr « "Depth for fifo '" « *fifo_name « '" is " « depth « ", but it must be at least lΛn"; status = FALSE; break; } // get the output buffer width if ((entry.size = this_zone->get_out_fifo_buffer.size(i)) == 0) { status = FALSE; break; } // make a size expr. for the fifo fifo.size = compute_fifo_size((long) enuy_size*depth); fifo.size . expr = new expr(fifo.size); // add this fifo to our instance status = user.top Jnstance->add_phantom.storage_name(fif o.name , fifo.size.expr, &fifo_wire, 'f'); if (istatus) { this_inst->out_error("ZON048", cerr, FALSE); cerr « "Tried to create a second fifo named '" « *fifo_name « '"!\n"; break; } // build the output fifo in ptr name fifo.ptr.name = this_zone->build_out_fifo_in_ptr_name(i); // add this to the top instance status = userjop_instance->add_phantom.storage_name(fifo_ptr.name, (expr*) NULL, &in_ptr_wire, 'h'); if (istatus) { this_inst->out_error("ZON049", cerr, FALSE); cerr « "A phantom wire named '" « *fifo_ptr_name « '" already exists !\n"; break; } // now create the symbols required by this output block instance // the last name we need is for the output enable location out.enable = this_zone->get.output_fifo_enable(i); M-571 enable . name = top _instance->prototype()-> hier_storage_name_at_index(out_enable); // create array of parameter expressions expr* param_vals[4]; param_vals[0] = fifo . size.expr; param_vals[l] = new expr(fifo_name); param_vals[2] = new expr(fifo_ptr_name); param_vals[3] = new expr(enable_name); // static array of parameter names (no static string arrays allowed) static char* names_chars[] = { "fifo.size", "fifo", "buffer.ptr", "sync.addr" }; string param_names[4]; param_names[0] =names.chars[0]; param_names[l] =names_chars[l]; param_names[2] =names_chars[2]; param_names[3] =names_chars[3]; // add parameter names and expressions to override parameter if (!add_parameters(4, param.names, param.vals)) { status = FALSE; break; } }} return status;} II add.parameters // Add parameter expressions by name to the current instance. // Returns FALSE if failed. BOOLEAN temporal::add.parameters(int n_params, string param.namesG, expr* param_valsQ){ int ϊ; exρrjιash*parameters; ϊnt dummy; BOOLEANstatus = TRUE; // get the hash table of expressions for the parameters parameters = this_ϊnst->get_overrides(); for (i=0; i<n_params; ϊ++){ // make sure this parameter name is present in prototype M-572 if (!thisJnst->prototype()->look_up_param_name(param_names[i], &dummy)) { status = FALSE; this_inst->out_error("ZON078", cerr, FALSE); cerr « "Block doesn't have a parameter named '" « param_names[i] « '", which is required." « "\n Is your library current?\n"; } else parameters->add(param_names[i], param.vals[i]);} return status;} II add.output.fifo Jnfo // Add output fifo info for each output. // Returns FALSE if failed. BOOLEAN temporal: :add_output_fifo JnfoQ { BOOLEANstatus = TRUE; // int entry.size; int in.ptr.wire; long depth; // save current block context and set instance info in block thisjnst- >push_context(); for (i=0; i<this_zone->n_zone_outputs(); i++){ // add the new fifo info to this zone // // first get the buffer size for the fifo // if ((entry.size = this_zone->get_out_fifo_buffer_size(i)) == 0) // { // status = FALSE; // break; // ) // build the output ptr name name = this_zone->build_out_fifo_in_ptr_name(i); // look up its wire index if ( !this_inst->prototype()->look_up_storage_name(name, &in_pu_wire)) { this_inst->out_error("ZON052", cerr, FALSE); cerr « "Unable to find the output fifo in ptr '" SUBSTITUTE SHEET -573 « *name «"'Λn"; status = FALSE; break; } // build the fifo name name = this_zone->build_out.fifo_name(i); // Look up the symbol for the fifo depth, which would have been // added automatically in partitioning, or supplied by the user // for a manual design. depth.symbol.name = new stringC'"); *depth_symbo l . narne = *depth_symboI_name + *name + DEPTH_STR; if (get_user_config_constant(*depth.symbol_name, &depth)) { status = FALSE; break; } // save this and other fifo info this_zone->set_zone_output_fifo(i, name, (int) depth, in_ptr_wire, this.inst);} thϊs_inst->pop_context() ; return status;} ff make.phantom.ϊπstance // Make a block instance within the current instance. // Passed the block prototype name, this just creates and inserts the instance // without dealing with VO or parameters. // Returns FALSE if failed. BOOLEAN temporal::make_phantomJnstance(string* prototype.name, instance** ins t_ptr_ρtr){ string* ϊnst.name; ϊnt inst.index; block* proto.ptr; int inst.number; BOOLEANstatus = TRUE; ϊnstance*ϊnst.ptr; // look up ptr to block prototype if (Kproto.ptr = find_block(prototype_name))) return FALSE; M-574 // get the instantiation count of this phantom to used as unique number if (!phantom_usage.find(*prototype_name, &inst_number)) ins t . number = 0; // build the instance name ins t . name = new string(this_zone->get_zone_chars()); *inst_name = *inst_name + *prototype_name + SEPARATOR.STR + int_to_c_string(ins t.number); // increment the instance number & record it phantom_usage.add(*prototype_name, -H-instjiumber); // get which index he will be in us inst . index = thisjnst- >get_n.children(); // create the instance inst . ptr = new instance(proto_ptr, *inst_name, this . inst, inst . index); // phantoms are aheady partitioned inst_ptr->set_partitioned(this_zone); // add him to our children this_inst->add_new_child(inst_ptr); // insert this block at the end of the partitioned sequence thisjnst- >append_partitioned(inst_index); #ifdef DEBUG string* hier.name; hier . name = inst.ptr->hier_name_string(); cerr « "Appending phantom " « *hier_name « " at position " « this_inst->get_partitioned_size() ; hier.name = this_inst->hier_name_string(); cerr « " of seq. for " « *hier_name « "\n"; #endif // set fact that this block has phantom blocks this_inst->set_has_phantoms(); // mark this zone for the instance ins t_ptr->add_zone(this_zone) ; // return instance ptr *inst_ptr_ptr = inst.ptr; return status;} II make.phantom.instance // Make a block instance within the current instance. SUBSTITUTE SHEET M-575 // Inserts at a specific place rather than at end of partitioned sequence. //Passed the block prototype name, this just creates and inserts the instance // without dealing with VO or parameters. // Returns FALSE if failed. BOOLEAN temporal::make_phantom _ϊnstance(string* prototype.name, instance** inst.ptr.ptr, ϊnt insert.index) { string* ins t.name; int inst.index; block* proto.ptr; int inst.number; BOOLEANstatus = TRUE; instance*ϊnst_ptr; // look up ptr to block prototype if (Kproto.ptr = find_block(prototype_name))) return FALSE; // get the instantiation count of this phantom to used as unique number if (!phantom_usage.find(*prototype_name, &ins t.number)) inst.number = 0; // build the instance name ins t.name = new string(this.zone->get_zone_chars()); *ins t.name = *ϊns t.name + *prototype_name + SEPARATOR.STR + in t_to_c_string(ins t.number); ' // increment the instance number & record it phantom_usage.add(*prototype_name, ++inst_number); // get which index he will be in us inst.index = thϊs_ϊnst->get.n_children(); // create the instance ϊnst_ptr = new ϊnstance(proto_ptr, *ins t.name, thisjnst, inst.index); // phantoms are already partitioned ϊnst_ptr->set_partitioned(this_zone) ; // add him to our children this_ϊnst->add_new_child(inst_ptr); // insert this block in the middle of the partitioned sequence this_ϊnst->ϊnsert_partitioned(ϊnsert_index, instjndex) ; #ϊfdef DEBUG string* hϊer_name; hier.name = ϊnst_ptr->hier.name.stringO; cerr « "Inserting phantom " « *hier_name M-576 « " at position " « insert . index; hier . name = this_inst->hier_name_string(); cerr « " of seq. for " « *hier.name « "\n"; #endif // set fact that this block has phantom blocks thisjnst- >se tJias.phantomsO ; // mark this zone for the instance inst.ptr->add_zone(this_zone); // return instance ptr *inst_ptr_ptr = inst_ptr; return status;} II make.phantom Jnst.with.args // Create a phantom instance, plus insert its I/O signals and parameters. // VO is specified by wire index plus a possible bypass parent instance // (in case the connection is not actually from the parent but from someone // higher up). Parameters are specified by name and expression. // Returns FALSE if failed. BOOLEAN temporal::make_phantom_inst_with_args(char* block_name, int n.ios, int* io.wires, instance** io.instances, int n_params, expr** param.values, instance** inst.ptr.ptr) { string* prototype.name; instance*inst_ptr; block* proto.ptr; // ptr to block prototype expr.hash *parameters ; string* param.name; static intinst.number = 0; int i; // create name for block prototype prototype.name = new string(block.name); if (!make_phantonι_instance(prototype_name, &inst_ptr)) return FALSE; // iterate on I/O signals for (i=0; i<n_ios; i++){ // set his I/O to point to given wire inst.ptr->set_io_to_wire_in_parent(i, io_wires[i]); M-577 // if there is a "bypass parent" instance, set it too if (io.instances != (instance**) NULL) { if (io_instances[ιJ != (instance*) NULL) ϊnst_ptr->se t_bypass_parent(ϊ, ϊo_instances[i]); }} //next, iterate on parameters, if present if (n_params){ // get ptr to block prototype, which we name for setting parameters proto.ptr = inst_ptr->prototype(); // create a hash table of expressions for the parameters parameters = new expr_hash(π_params); for (i=0; i<n_params; i++) { // get parameter name for this parameter index // from the prototype (must of course specify parameters // in their declared order) param.name = proto_ptr->param_name_at_index(i); parameters->add(*param_name, param_values[i]); } // set parameter table as override symbol table for this instance ϊnst_ptr->set_o verrides(parameters) ; } // evaluate and add duration after everything added if (!add_block_duration(prototype_name, inst.ptr)) return FALSE; // return instance ptr *ϊnst_ptr_ptr = inst.ptr; return TRUE;} iiiuiuiuiuii iiπiπiuiiiπiiπiiiiiiiiiiiiiiiπiiiiiiiiiiiπit iiiiii II make.phantom.inst.wϊth.args // Create a phantom instance, plus insert its VO signals and parameters. // Version which inserts in a specific place in partition sequence. II VO is specified by wire index plus a possible bypass parent instance // (in case the connection is not actually from the parent but from someone // higher up). Parameters are specified by name and expression. // Returns FALSE if failed. BOOLEAN temporaI::make_phantom_inst.with_args(char* block.name, ϊnt n.ios, int* io.wires, instance** io.instances, int n.params, expr** param.values, instance** inst.ptr.pti-, int insert.index) { string* prototype.name; instance *inst_ptr; block* proto.ptr; // ptr to block prototype expr_hash*parameters; string* paramjiame; static intinst.number = 0; int i; // create name for block prototype prototype.name = new string(block.name); if (!make_phantom_instance(prototype_name, &inst_ptr, insert . index)) return FALSE; // iterate on I/O signals for (i=0; n.ios; i++){ // set his VO to point to given wire inst.ptr->set_io_to_wire_in.parent(i, io_wires[i]); // if there is a "bypass parent" instance, set it too if (io . instances != (instance**) NULL) { if (io_instances[i] != (instance*) NULL) inst_ptr->set_bypass_parent(i, io_instances[i]); } } // next, iterate on parameters, if present if (n.params) { // get ptr to block prototype, which we name for setting parameters proto.ptr = inst_ptr->prototype(); // create a hash table of expressions for the parameters parameters = new expr.hash(n.params); for (i=0; i<n_params; i++) { // get parameter name for this parameter index // from the prototype (must of course specify parameters // in their declared order) param.name = proto_ptr->param_name_at_index(i); parameters->add(*param.name, param_values[i]); } // set parameter table as override symbol table for this instance inst_ptr->set _overrides(parameters) ; } TIT H E 92k M-579 // evaluate and add duration after everything added if (!add_block_duration(prototype.name, inst.ptr)) return FALSE; // return instance ptr *inst_ptr.ptr = inst_ptr; return TRUE;} II make.wait.for _fiags_block // Make a block to wait for flags for this GSP. // Returns FALSE if failed. BOOLEAN temporal::make_wait_for_flags_block(Iong wait_mask){ // create array of parameter expressions expr* param.valsfl]; param_vals[0] = new expr(wait_mask); return make_phantom_inst_wϊth_args(WAIT_FOR_FLAGS_STR, 0, (ϊnt*) NULL, (instance**) NULL, 1, param.vals);} iiimimiπππiiiiiiiiiniiiiiiiiimirnπiiπiiiiiiiiiiiiπiiiiiiiiii II niake.wait.nonzero.compute.block // Make a block to wait for a non-zero compute count. // Returns FALSE if failed. iiiiniiimmiimmimmmniimimmuminiimmiimiiiimuu BOOLEAN temporal: :make_waϊt_nonzero_compute_block(long wai t_mask, instance* ctrjnst, int ctr.index) { // create array of parameter expressions expr* param_vals[l]; param_vals[0] = new expr (waϊt_mask); // create array of VO wire indices intϊos[l]; ϊos[0] = ctr.index; // create array of I/O wire instance pointers instance* ϊo_insts[l]; ϊo_insts[0] = ctrjnst; return make_phantom_ϊnst_wim_args(WAIT_NON0_COMP_STR, 1, ios, io.insts, I, param.vals);} II make.poll.compute.block // Make a block to poll compute count. // Returns FALSE if failed. M-580 BOOLEAN temporal: :make_poll_compute_block(long wait . mask, instance* ctrjnst, int ctr . index) { // create array of parameter expressions expr* param_vals[l]; param.vals[0] = new expr(wait.mask); // create array of I/O wire indices int iosfl]; ios[0] = ctr.index; // create array of I/O wire instance pointers instance* io_insts[l]; io_insts[0] = ctrjnst; return make_phantom_inst_wit.h_args(POLL.COMP_STR, 1, ios, io.insts, 1, param.vals);} II make ump.block // Make a block to jump to the given address name. // Returns FALSE if failed. BOOLEAN temporal::make ump_block(string* addr_name){ // create array of parameter expressions expr* param_vals[l]; param_vals[0] = new expr(addrjιame); return make_phantom_inst_with_args(JUMP_TO_STR, 0, (int*) NULL, (instance**) NULL, 1, param_vals);} II make_copy_constan t_block // Make a copy_constant block to initialize the given segment flag. // The segment flag must exist before calling. // Returns FALSE if failed. BOOLEAN temporal: :make_copy_constant_block(string* flag_name, long constant) { int wire.index; instance*wire Jnstance; // locate segment flag for him if (!this_inst->find_wire_name(flag_name, &wire_index, &wire_instance)){ this_inst->out_error("ZON906", cerr, FALSE); cerr « "INTERNAL ERROR - Unable to find the location '" « *flag_name « '"Λn"; SUBSTITUTE SHEET M-581 return FALSE;} // create array of VO wire indices intios[l]; ios[0] = wire.index; // create array of VO wire instance pointers instance* io.insts[l]; io_ϊnsts[0] = (instance*) wirejnstance; // create array of parameter expressions expr* param_vals[l]; param_vals[0] =new expr(constant); return make_phantonι_inst_with_args(COPY_CONSTANT_STR, 1, ios, io.insts, 1, param.vals);} uiiπunuiπiiiiiiimiiiπiiiiiiπuiiiii iiiππiiπiiππiiiii iπii II make.copy.addr.block //Make a copy.address block to copy an address to a pointer location. // This is used to copy a fifo address to a fifo pointer. // The address must exist before calling. // Returns FALSE if failed. BOOLEAN temporal::make_copy_addr_block(int addr.size, string* addr.name, int ptr.index, instance* ptr . inst) { int wire.index; instance*wire_instance; // locate address to copy if (!thϊsjnst->find_wirejrιame(addr_name, &wire_index, &wire.instance)){ this_inst->out_error("ZON907", cerr, FALSE); cerr « "INTERNAL ERROR ~ Unable to find the fifo '" « *addr_name « '"Λn"; return FALSE;} // create array of 170 wire indices ϊntios[2]; ios[0] = wire.index; iosfl] = ptr.index; // create array of I/O wire instance pointers instance* io.insts [2]; io_insts[0] = wire.instance; ϊo_insts[l] = ptr.inst; // create array of parameter expressions expr* param_vals[l]; -582 param_vals[0] = new expr((long) addr.size); return make_phantom_inst_with_args(COPY_ADDRESS_STR, 2, ios, io . insts, 1, param.vals);} II make.init . arr.ptr.block // Instantiate a "init.arr.ptr" block. // Returns FALSE if failed. BOOLEAN temporal: :make_init_arr_ptr_block(int addr_size, int addr.index, instance* addr . inst, int ptr.index, instance* ptr.inst) { // create array of VO wire indices int ios[2]; ios[0] = addr.index; ios[l] = ptr . index; // create array of I/O wire instance pointers instance* io_insts[2]; io_insts[0] = addr.inst; io_insts[l] = ptr.inst; // create array of parameter expressions expr* param_vals[l]; param_vals[0] = new expr((long) addr_size); return make.phantom _inst_with_args(INIT_ARR_PTR_STR, 2, ios, iojnsts, 1, param.vals);} II make_init_arr_ptr_block // Instantiate a "init_arr_ptr" block. // Version for insertion at a specific spot in partitioned sequence. // Returns FALSE if failed. BOOLEAN temporal: :make_init_arr_ptr_block(int addr.size, int addr.index, instance* addr.inst, int ptr.index, instance* ptr.inst, int place) { instance*dummy_inst; // create array of I/O wire indices int ios[2]; ios[0] = addr.index; ios[l] = ptr.index; // create array of VO wire instance pointers instance* io_insts[2]; M-583 ϊo_ϊnsts[0] = addr.inst; ϊo_ϊnsts[l] = ptr.inst; // create array of parameter expressions expr* param.vals [1]; param_vals[0] = new expr((long) addr.size); return make_phantomJnst_wϊth_args(llNirr_ARR_PTR_STR, 2, ios, iojnsts, I, param.vals, &dummy_inst, place);} II make_wait_seg_flag_block // Make a wait_seg_flag block to wait for a value of the given segment flag. // The segment flag must exist before calling. // Returns FALSE if failed. BOOLEAN temporal: :make.wait_seg_flag_block(string* flag_name, long value) { ϊnt wire.index; instance*wire_ϊnstance; // locate segment flag for him if (!thϊs_inst->find_wire_name(flag_name, &wire_index, &wire.instance)){ thϊs_inst->out_error("ZON908", cerr, FALSE); cerr « 'INTERNAL ERROR - Unable to find the seεment flag '" « *flag_name « "'Λn"; return FALSE;} // create array of I/O wire indices ϊntios[l]; ios[0] = wire Jndex; // create array of O wire instance pointers instance* io_insts[l]; io_insts[0] = wire.instance; // create array of parameter expressions expr* param_vals[l]; param_vals[0] = new expr(value); return make_phantomJnst_wϊ _args(WAIT_SEG_FLAG_STR, 1, ios, io.insts, 1, param.vals);} II make.pr.reset.block // Make a block to copy to the given fifo from an output. // Called after phantom wires have been created. // Returns FALSE if failed. M-584 BOOLEAN temporal: :make_pr_reset_block() { // all block instances use the same probe signal, which we allocate static instance* probe.signal.inst = (instance*) NULL; static int probe . signal Jndex = 0; // if probe signal not allocated, create it if (probe.signal.inst == (instance*) NULL){ string* probe.signal . name; BOOLEANstatus; expr* init.value.expr; probe_signal_inst = userjopjnstance; probe_signal_name = new string(PR.SIGNAL.STR); // add this to the top instance status = user.top_instance->add_phantom_storage.name(probe_signal_name, (expr*) NULL, &probe.signal_index, 'h'); if (Istatus) { user_top_instance->out_error("ZON089", cerr, FALSE); cerr « "A phantom wire named '" « *probe_signa l.name « '" already exists !\n"; return status; } // set the initialization for the probe signal init.value.expr = new expr(Qong) PR.SIGNAL . INIT.VAL); user_top_instance->set_storage.override_init(probe.signal_index, init.value.expr);} // create array of I O wire indices intios[l]; ios[0] = probe.signal.index; // create array of VO wire instance pointers instance* io_insts[l]; io_insts[0] = probe.signal . inst; return make_phantom_inst_with_args(PR_RESET_STR, 1, ios, io.insts, 0, (expr**) NULL);} II make.copy.blocks // Make a copy block for each pending input. // Called after phantom wires have been created. // Returns FALSE if failed. SUBSTITUTE SHEET -585 BOOLEAN temporal::make_copy_blocksO { int i; BOOLEANstatus = TRUE; for (i=0; ϊ<this_zone->pending_sϊze(); i++){ • status = make.phantom_copy_block(i) ; if (Istatus) break;} return status;} iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiin II make.phantom.copy.block // Make a copy block for the given pendmg input index. // Called after phantom wires have been created. // Returns FALSE if failed. BOOLEAN temporal::make_phantom_copy_block(int i) { int to.wire.level; ϊnt from.wire.level; ϊnstance*inst; int wire; ϊnt wire.index; instance*inst_ptr; BOOLEANstatus = TRUE; // get instance and wire within instance for next pending wire inst = this_zone->pending_instance(i); wire = thϊs_zone->pending_wire(i); // get last phantom level for wire, which is "to" wire level to.wire.level = inst->get.phantom_wireJevel(wire); // if "to" level was the first level (0), there's nothing to do I if (to.wire.level > 0){ // "from" wire is level before "to" wire from.wire.level = to.wire.level - 1; // get wire index for original wire wire.index = ϊnst->get_phantom(wϊre , 0); // create array of VO wire indices // which is same wire, but different phantom levels, as set below int ios[2]; ϊos[0] = wire.index; ios[l] = wire.index; // create array of VO wire instance pointers M-586 instance* io_insts[2j; io.insts [0] = inst; io . insts [1] = inst; if (Imake . phantom _inst_with_args(COPY_STR, 2, ios, io . insts, 0, (expr**) NULL, &inst_ptr)) status = FALSE; // set phantom levels for "from" and "to" wires inst_ptr->set_phantom_io _level(0, from.wire.level) ; inst_ptr->set_phantom_io.level( 1 , to.wire.level) ; } return status; } /////////////////////////////////////////////////////////////////////////////// // makejurnstile // Make a turnstile block for the given segment. // The segment flag wire must exist before calling. // Returns FALSE if failed. BOOLEAN temporal: :make_turnstile(string* the_flag_string, int seg_number){ int wire.index; instance*wire_instance; static string turnstile_string(TURNSTILE_STR); // set the phantom usage count to be the segment number so this // segment appears in this instance of the turnstile block phantom_usage.add(turnstile_string, seg_number); // locate segment flag for him if (!this_inst->find_wire_name(the_flag_string, &wire _index,&wire_instance)) { this_inst->out_error("ZON909", cerr, FALSE); cerr « "INTERNAL ERROR - Unable to find the segment flag '" « *the_flag_string « '"Λn"; return FALSE;} // set his 1 VO to point to the segment flag wire // create array of I/O wire indices int ios[l]; ios[0] = wire.index; // create array of I/O wire instance pointers instance* io.instsfl]; io_insts[0] = wire.instance; return make_phantom_inst_with_args(TURNSTILE_STR, 1, ios, io.insts, 0, (expr**) NULL);} M-587 II make.free.segment // Make a free.segment block for the previous segment. // The segment flag wire must exist before calling. // Returns FALSE if failed. BOOLEAN temporal::make_free_segnιent(string* flag_name){ ϊnt wirejndex; ϊnstance*wire.instance; int seg_number; static string free_seg_string(FREE_SEG_STR); seg_number = this.zone->seg_num() - 1; // set the phantom usage count to be the segment number so this // segment number appears in the instance phantom_usage.add(free_seg_string, seg_number) ; // locate segment flag for him if (!this_inst->find_wire_name(fiag.name, &wire_ϊndex, &wire_instance)){ this_ϊnst->out_error("ZON910", cerr, FALSE); cerr « "INTERNAL ERROR ~ Unable to find the segment flag '" « *flag_name « '"Λn"; return FALSE;} // set his 1 VO to point to the segment flag wire // create array of VO wire indices ϊntϊos[l]; ios[0] = wirejndex; // create array of I/O wire instance pointers instance* ϊo_insts[l]; io_insts[0] = wire.instance; return make_phantomJnst_with_args(FREE_SEG_STR, 1, ios, io.insts, 0, (expr**) NULL);} mmimituiiuinniiimimimumimmuiiiiiuiimimimimim II ending_overhead // Compute number of phantom block overhead cycles for ending the current // segment. //Exits if error. int temporal::ending_overhead() { static int turnstile.cycles = UNKNOWN.DURATION; -588 static intcopy.cycles = UNKNOWN.DURATION; static intfree_seg_cycles = UNKNOWN_DURATION; int n.wires; // if we don't have # of cycles for blocks, look them up if (copy . cycles == UNKNOWN.DURAHON) if ((copy.cycles = get_block_duration(COPY_STR)) == UNKNOWN . DURATION) exit(l); if (free_seg_cycles == UNKNOWN.DURAHON) if ((free_seg_cycles = get_block_duration(FREE_SEG_STR)) == UNKNOWN.DURATION) exit(l); if (turnstile.cycles == UNKNOWN.DURATION) if ((turnstile . cycles = get_block_duration(TURNSTILE_STR)) == UNKNOWN.DURATION) exit(l); n.wires = this_zone->pending_size(); return free_seg_cycles + (copy_cycles*n_wires) + turnstile.cycles; } II add Jhis.block.duration // Try to add the current block's duration to this zone. If it would // overfill the zone, don't add it and return FALSE. BOOLEAN temporal: :add_this_block_duration(int* dur_ptr){ long this.duration; // call our member function to get block duration this.duration = ge t_this_block_duration(); *dur.ptr = (int) this.duration; // if we are in "adding init blocks" mode, tally cycles separately if (addingjnit) this_zone->add_init_cycles(this_duration); else{ // test if blocks will fit, or if signal from above to force // a new zone boundary if ( tes t_block_duration(*dur_ptr) && !this_zone->boundaryJ rced() ) { // ok, so add this block to current segment this_zone->add_cycles(this_duration); return TRUE; M-589 93^ } else return FALSE;} return TRUE;} II test.block.duration // Test if the given duration will fit in this zone, ff it would // overfill the zone, return FALSE. BOOLEAN temporal::test.block_duration(ϊnt duration) { int overhead.cycles; overhead.cycles = ending_overhead(); // test if blocks will fit if ( (thϊs_zone->cycles_used() + duration + overhead.cycles) > this_zone->max_cycles() ) return FALSE; else return TRUE;} iiiiiiiiiiiiiiiiiiiiiifiiiiiiimfiiifiiiiiiiiiiiiiiiiffiiiiiififiiiiiifiirrin II getjhϊs.block.duration // Returns the current block's duration. long temporal::get.thϊs_block_duration() { return thϊs_inst->get_duration();} II add.block.duratϊon // Evaluate and add the new block's duration to the zone. // Returns FALSE if failed. BOOLEAN temporal::add_block_duration(string* prototype_name,instance*& inst.ptr) { BOOLEANstatus = TRUE; ϊnstance*current.inst; int duration; // evaluate contents so block duration will get filled in if (ins t_ptr->compute.contentsO){ this_ϊnst->out_error("ZON905", cerr, FALSE); cerr « "INTERNAL ERROR - Phantom block '" « *prototype_name « '" doesn't have valid contentsΛn"; M-590 status = FALSE; } // add this block's duration to the zone // save our current instance and set the pass-in instance currentjnst = thisjnst; thisjnst = inst.ptr; if (!add_this_block_duration(&duration)) { this_inst->out_error("ZON053", cerr, FALSE); cerr « "The sample rate is too high, with only " « this_zone->max_cycles() « " cycles in a sample period !\n" « "Could not add a required phantom block (" « *prototype_name « ").\n"; status = FALSE;} // restore our instance thisjnst = currentjnst; return status;} II end.zone.cycles // Called when all user blocks have been instantiated, this function determines // the number of cycles to finish the zone. // Exits if error. long temporal: :end_zone_cycles() { static intjump.block.cycles = UNKNOWN.DURATION; long cycles.required; // if we don't have # of cycles for blocks, look them up if (jump.block.cycles == UNKNOWN.DURATION) if ((jump.block.cycles = get_block_duration(JUMP_TO_STR)) == UNKNOWN.DURATION) exit(l); // add overhead for ending a block cycles.required = ending.overhead(); // add jump block cycles cycles_required += jump_block_cycles; return cycles.required;} II end.zone.fits SUBSTITUTE SHEET M-591 // Called when all user blocks have been instantiated, this function determines // if the end of zone overhead blocks will fit in the current segment. // Returns FALSE if no. //Exits if error. BOOLEAN temporal: :end_zone_fitsO{ // see if there is enough time if ( (this_zone->cycles_used() + end.zone.cyclesO) > this_zone->max_cycles()) return FALSE; else return TRUE;} II get.block.duration // Get constant block duration for an ASM block. intget_block_duration(char* name){ string* prototype.name; asm_bIock*proto_ptr; expr* expr_ptr; ϊnt blk_duration; int dummyl, dummy2; prototype.name = new strϊng(name); // make sure we have ptr to block prototype if (!(proto_ptr = (asm.block*) find_block(prototype_name))) return UNKNOWN.DURAHON; // make sure block is an asm block if (!proto_ptr->is_leaf_block0){ out_err_header("ZON057"); cerr « "Block "' « *prototype_name « '" needs to be an asm blockΛn"; return UNKNOWN.DURAHON;} // get expression for duration expr_ptr = proto_ptr->get_duratϊon_expr(); // make sure its a constant if (!expr_ptr->has_int_yalue()){ out_err_header("ZON058"); cerr « "Block "' « *prototype_name « '" needs to have a constant duratϊonΛn"; -592 return UNKNOWN.DURAHON;} // get integer value of expression and return as duration blk.duration = (int) expr_ptr->int_value(&dummyl, &dummy2); return blk.duration; } II get.block.duration // Get variable block duration for an ASM block. // Passed parameters which are required to evaluate the variable duration of // the asm block. int get.block.duration (char* name, int n.params, expr** param . values) { string* prototype . name; asm_block*proto_ptr; expr* expr.ptr; int blk . duration; int dummyl, dummy2; expr_hash*parameters; string* param.name; prototype.name = new string(name); // make sure we have ptr to block prototype if (Kproto.ptr = (asm.block*) find.block(prototype.name))) return UNKNOWN.DURAHON; // make sure block is an asm block if (!proto_ptr->is_leaf_block()){ out_err_header("ZON057"); cerr « "Block '" « *prototype_name « '" needs to be an asm blockΛn"; return UNKNOWN.DURATION;} // get expression for duration expr.ptr = proto_ptr->get_duration_expr(); // next, iterate on parameters, if present if (n.params) { // create a hash table of expressions for the parameters parameters = new expr.hash(n.params); for (int i=0; i<n_params; i++) { // get parameter name for this parameter index // from the prototype (must of course specify parameters // in their declared order) SUBSTITUTE SHEET M-593 param.name = proto_ptr->param_name_at_index(i); parameters->add(*param_name, param_values[i]); }} // Create a temporary instance for this block so that we // can set a temporary parameter table for the purpose of // evaluating the duration. // First clear out any junk instance ptr in prototype so we don't // get into any initialization problems ! proto_ptr->set _instance((instance*) NULL) ; string temp.stringC'temp"); instancetemp_instance(proto_ptr, temp.string, (instance*) NULL, 0); // set parameter table as override symbol table for this instance if (n.params) temp_instance.set_overrides(parameters); // now push the context for this instance so the instance info // is within the block's environment{ tempJnstance.push.contextO; // make sure duration expression now evaluates to an integer value if (!expr_ptr->has_int_value()) { out_err_header("ZON076"); cerr « "Block "' « *prototype_name « '" has an uncomputable durationΛn"; blk.duration = UNKNOWN.DURATION; } else // get integer value of expression and return as duration blk.duration = (int) expr_ptr->int_value(&dummyl, &dummy2); temp.instance.pop.contextO; } return blk.duration;} If Here are the overloaded multijemporal (multi-rate) versions of temporal // class member functions. itiiiiiiiiiiiiiiπiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiin II muIti_temporal::multi_temporal // Constructor. // This constructor is passed a possible previous zone for partitioning // a multi-rate sub-zone. Partitioning info from this zone is carried over -594 // for the this temporal partitioning. mult i_temporal::multijemporal(zone* z, instance* i, string* flag_s, zone* prev.z) : temporal(z, i, flag_s, prev.z) { is.multi . temporal = TRUE; if (prev . z != (zone*) NULL){ // carry over partitioning info by "adding" it (via the "+" operator, // of course!) from the old zone to the new zone. *z += *prev_z; } } II init.for.partition // Overloaded function from temporal class to do initialization before // we start partitioning. BOOLEANmulti.temporal: :init_for_partition() { BOOLEANstatus = TRUE; // instantiate the loop init block using repeat count for zone status = make_loop_init_block(); // Create top-of-loop for the new segment. if (status) status = makeJoopjopO; // we are in looped code, so set this set.in.repeat.codeO; return status;} II add_output_fifo_info // Overloaded function from temporal class which calls the base function // for each successive multi-rate zone derived from the master zone. // Output fifos are created for each subzone which has outputs. // This is called when all the zone's blocks have been processed. BOOLEAN multi_temporal::add_output_fifo_info(){ int i; BOOLEANstatus = TRUE; zone* next; for (i=0; i<the_zones->n_including_sub_zones(); i++){ // do all zones with our zone as the original 9^-0 M-595 next = the_zones->get_zone(i); if (next->original_zoneO == this.zone) { // Create a temporary multi-temporal object for next zone. multijemporal t(next, thisjnst, flag_string, this.zone); // call base class if (Kstatus =t.temporal::add_output_fifo_info())) break; }} return status;} II run.tϊme.input.port.init // Generate the code for the run-time portion of the input port initialization, // ϊ.e. initialization that should not be done via a static download. BOOLEAN multi_temporal::run_time_input_port_inϊt() { ϊnt i; BOOLEANstatus = TRUE; zone* next; for (i=0; i<the_zones->n_including_sub_zonesO; i++){ // do all zones with our zone as the original next = the_zones->get.zone(i); if (next->origϊnal_zone() = this.zone) { // create a temporary multi-temporal object for next zone multijemporal t(next, this.inst, flag_string); // call base class if (Kstatus = t.temporal::run_time_input_port_init())) break; } } return status;} II init.input.fifo.ptrs // Overloaded function from temporal class which calls the base function // for each successive multi-rate zone derived from the master zone. // Create the init blocks to set the input fifo pointers. miiuiiiuiiiiiiiiiiuiπiπiimMiiiiiirimiiiiiπmπiiniiM BOOLEAN multi_temporal::inϊtJnpu _fifo_ptrs() { M-596 int i; BOOLEANstatus = TRUE; zone* next; for (i=0; i<the.zones->n_including_sub_zones(); i++){ // do all zones with our zone as the original next = the_zones->get_zone(i); if (next->original_zone() == this.zone) • { // create a temporary multi-temporal object for next zone multijemporal t(next, thisjnst, flag_string); // call base class if (! (status = t. temporal: :init_input_fifo_ptrs())) break; } } return status;} II ini t.output.fifo.ptrs // Overloaded function from temporal class which calls the base function // for each successive multi-rate zone derived from the master zone. // Create the init blocks to set the output fifo pointers. BOOLEAN multijemporal: :init_output_fifo_ptrs() { int i; BOOLEANstatus = TRUE; zone* next; for (i=0; i<the_zones->n_including_sub.zones(); i++){ // do all zones with our zone as the original next = the.zones->get_zone(i); if (next->original_zone() == this.zone) { // create a temporary multi-temporal object for next zone multijemporal t(next, thisjnst, flag_string); // call base class if (Kstatus = t.temporal::init_output_fifo_ptrs())) break; } } return status; } 9^2 M-597 //partition // Overloaded function from temporal class which calls the base function // for each successive multi-rate zone derived from the master zone. BOOLEAN multi_temporal::partition(BOOLEAN* ok, int* duration_ptr){ ϊnt i; BOOLEANstatus = TRUE; zone* next; // partition our zone if (Kstatus = temporal::partition(ok, duratϊon_ptr))) return status; for (i=0; ϊ<the_zones->n_includϊng_sub_zones(); i++){ // partition all other zones with our zone as the original next = the.zones->get_zone(i); if ((next->originaI_zone() = this.zone) && (next != this.zone)) { // Create a temporary multi-temporal object for next zone. multijemporal t(next, this.inst, flag_string, this.zone); // We must force a new zone boundary because different rates must be // on different loops. This will take effect when we try to //partition. next->f orce.a.boundary () ; // don't recursively call ourself, but call base class if (Kstatus = t.temporal::partition(ok, duration . ptr))) break; // ustin case no partitioning done, clear flag (it // will get set again for another sub-zone) next->clear_forced_flag() ; } } return status;} II add.this.block.duration // Overloaded function from temporal class. // Try to add the current block's duration to this zone. If it would // overfill the zone, don't add it and return FALSE. //This overloaded version also checks for insertions of a poll block, //if required. 9^ -598 BOOLEAN multi_temporal::add_this_block_duration(int* dur_ptr){ BOOLEANstatus; int this.duration; // call our member function to get block duration this . duration = (int) get_this_block_duration(); *dur_ptr = this.duration; // first call to check for new segment required if (!test_block_duration(this_duration) II this_zone->boundary_forced() ) return FALSE; // no new segment, so see if poll block required if (status = !poll_block.required(this_duration)){ // no poll block required // so add block duration status = temporal::add_this_block_duration(dur_ptr); // do poll block accounting for duration poll_block_accounting(this_duration);} return status;} II poll.block.required // Returns TRUE if need a poll block before inserting block of given duration // in the current zone. BOOLEAN multi_temporal::poll_block_required(int duration)! int repeat.count; int since.temp; int max.cycles; since.temp = since .last.poll; if (this_zone->compute_pollingO) { // doing compute polling, so see if we need to insert a // poll block before adding this block repea t_count = (int) this_zone->original_zone()->get_repeat_count(); max.cycles = (int) (this_zone->max.cycles() / repeat.count); // divide duration by zone repeat count to get true duration if (in.repea t.code) duration = duration / repeat.count; if ( (duration + since.last.poll) > max.cycles ) return TRUE;} return FALSE; } SUBSTITUTE SHE 9kk M-599 II poll.block.accounting // Tally the given block duration for poll block accounting. miiπmiimiiiiui πu πu muuπniimπiunmii iimi void multiJemporal::poll_block.accounting(int duration)! if (this_zone->compute_pollingO){ // divide duration by zone repeat count to get true duration if (in.repeat.code) duration = (int) (duration/ this_zone->ge t.repea t_count()); since.last.poll += duration; } } II segment.would.follow.poll // Returns TRUE if a segment would immediately follow a new poll block. BOOLEAN muIti_temporaI::segmen _would_follow_poll(int duration) { ϊnt repeat.count; int poll.cycles; ϊnt overhead.cycles; long used; long max.cycles; repeat.count = (int) fhϊs_zone->get_repeat_count(); poll_cycles = poll_bIock_cycles(); if (ϊn_repeat_code) poll.cycles *= repeat.count; overhead.cycles = ending_overheadO; used = this_zone->cycles_used(); max.cycles = this_zone->max_cycles(); // if adding poll block would require a new segment, or if after adding // poll block we cannot add the given block's duration, then //return TRUE if ( ((used + poll.cycles + overhead.cycles) > max.cycles) II ((used + poll.cycles + duration + overhead.cycles) > max.cycles) ) return TRUE; else return FALSE;} If segraent.would.follow.boundary // Returns TRUE if a segment would immediately follow a rate boundary. 9^5 M-600 BOOLEAN multi_temporal::segment_would_follow.boundary(int duration) { int boundary.cycles; int overhead.cycles; long used; long max . cycles; boundary.cycles = boundary_overhead(); overhead.cycles = ending_overhead(); used = this_zone->cycles_used(); max.cycles = this_zone->max_cycles(); // if adding boundary would require a new segment, or if after adding // boundary we cannot add the given block's duration, then // return TRUE if ( ((used + boundary.cycles + overhead.cycles) > max . cycles) II ((used + boundary.cycles + duration + overhead.cycles) > max.cycles) ) return TRUE; else return FALSE;} II add.poll.block // Add a poll compute line block. BOOLEAN nιulti_temporal::add_poll_block() { int ctrjndex; instance*ctr_inst; BOOLEANstatus = TRUE; static long wait.mask = 0; // clear cycles since last poll block since_last_poll = 0; // get args for poll block and insert ctrjndex = this_zone->get_compute_ctr(&ctr_inst); if (!make_poll_compute_block(compute_ctr_wait_mask, cu-_inst, ctrjndex)) status = FALSE; return status;} II poll.block.cycles // This function determines the number of cycles for a poll block. // Exits if error. SUBSTITUTE H 9k6 M-601 int multi_temporal::poll_block_cycles() { static intpoll.bl.cycles = UNKNOWN.DURATION; // if we don't have # of cycles for block, look them up if (poll.bl.cycles = UNKNOWN.DURATION) if ((poll.bl.cycles = get_block_duration(POLL_COMP_STR)) = UNKNOWN.DURAHON) exit(l); return poll.bl.cycles;} II get_thϊs_bIock_duration // Overloaded function from temporal class. // Returns the current block's duration, adjusted by a possible repeat count // for looped code. long multi_temporal::get_thϊs_block_duration() { // if we're in a repeated code portion, scale the block duration // by the repeat count if (in.repea t.code) return thϊs_ϊnst->ge t.durationO * this_zone->ge t_repeat_count(); else return this_ϊnst->ge t.durationO;} II endϊng_overhead // Overloaded function from temporal class. // Compute number of phantom block overhead cycles for ending the current // segment. //Exits if error. int multi_temporal::ending.overhead() { static ϊnt turnstile.cycles = UNKNOWN.DUR HON; static intfree_seg_cycles = UNKNOWN.DURAHON; static ϊntloop.bottom.cycles = UNKNOWN.DURATION; static intloop.ϊnϊ t.cycles = UNKNOWN.DURAHON; int dupe.ph.array.cycles; ϊnt to.ph.array.cycles; int fr.ph.array.cycles; int to.ph.array.reset.cycles; int fr.ph.array.reset.cycles; zone* before.zone = this.zone;// zone before segment edge 9^- zone* after.zone = this.zone; // zone after segment edge int.arraybottom.of . last.copy;// type of copy for each wire, last loop int . arraytop . of.next.copy;// type of copy for each wire, next loop int n . cycles; int before . segmen t epeats; int after.segmen tjepeats; before . segment . repeats = (int) before_zone->get_repeat_count(); after.segment.repeats = (int) after_zone->get.repeat_count(); // analyze the type of copies to do for each phantom wire for the bottom // of previous loop, between loops, and top of next loop if (!analyze_phantom_multi_copies(before_zone, after.zone, &bottom_of_last_copy, &top_of_next_copy)) exit(l); // if we don't have # of cycles for blocks, look them up // compute number of cycles for each to phantom array copy block if (!n_to_phantom_arr_copy_cycles(&bottom_of_last.copy,&to_ph_array_cycles)) exit(l); // compute number of cucles for loop bottom block if (loop.bottom . cycles == UNKNOWN.DURATION) if ((loop.bottom.cycles = get_block_duration(LOOP_BOTTOM_STR)) == UNKNOWN.DURATION) exit(l); if (turnstile.cycles == UNKNOWN . DURATION) if ((turnstile.cycles = get_block_duration(TURNSTILE_STR)) == UNKNOWN.DURATION) exit(l); // compute number of cycles for each dupe phantom array block if ( !n_dupe_phantom.arrays_cycles(&dupe_ph_array_cycles)) exit(l); // to phantom array reset blocks if ( !n_to_phant_arr_ptr_resets(&bottom_of_last_copy, &to_ph_array_reset_cycles)) exit(l); // from phantom array reset blocks if ( !n_fr_phant_arr_ptr_resets(&top_of_next.copy, &fr_ph_array_reset_cycles)) exit(l); // free segment cycles 9^8 -603 if (free_seg_cycles == UNKNOWN.DURAHON) if ((free_seg_cycles = get_block_duration(FREE_SEG_STR)) = UNKNOWN.DURATION) exit(l); // loop init block if (loop.init.cycles = UNKNOWN.DURATION) if (Qoop. it.cycles = get_bIock_duration(COPY_CONSTANT_STR)) = UNKNOWN.DURATION) exit(l); // compute number of cycles for each from phantom array copy block ff (!n_from_phantom_arr_copy_cycles(&top_of_next_copy, &fr_ph_array_cycles)) exit(l); n.cycles — loop_bottom_cycles*before_segment_repeats + loop.init.cycles + free_seg_cycles + turnstile.cycles + to.ph.array.reset.cycles + fr.ph.array.reset.cycles + dupe.ph.array.cycles + to_ph.array_cycles*before_segment_repeats -i-fr_ph_array_cycles*after_segment_repeats; return n.cycles;} II end.zone.cycles // Overloaded function from temporal class. // Called when all user blocks have been instantiated, this function determines // the number of cycles to finish the zone. //Exits if error. long multϊ_temporal::end_zone_cycles() { static intjump.block.cycles = UNKNOWN.DURATION; long cycles.required; // if we don't have # of cycles for blocks, look them up if Qump.block.cycles = UNKNOWN.DURATION) if ( ' ump.block.cycles = get_block_duration(jTJMP_TO_STR)) = UNKNOWN.DURAHON) exit(l); // add overhead for ending a block cycles.required = ending_overheadO; // add jump block cycles cycles.required += jump.block.cycles; return cycles.required;} M-604 9 9 II create.segment.O // Segment 0 is created at the start of temporal partitioning. // We must: // 1. Create a label for loop back from the end of the time zone. // 2. Create segment flag phantom wires for segments 0 and 1. // 3. Instantiate a ".turnstile" block to wait for segment 1 free. // 4. Instantiate a ".free.seg" block to free segment 0. BOOLEANmulti Jemporal: :create_segment_0() { int segjndex; // wire index for new segment string* zeroth_flag_string; string* first.flag_string; string* label; BOOLEANstatus = TRUE; // // save current block context and set instance info in block // thisjnst- >push_context(); // we are not get in looped code set_not_in_repeat_code(); // create the label for GSP loop back // tie it to the next instance to be added, which will be a fifo or flag // wait block label = new string(LOOP.STR); *label = *label + this_zone->get_zone_chars(); // set this label (hierarchically named) in the temporal class loopback.label = new stringC"'); *loopback_label = *loopback_label + *this_inst->hier_name_string() + "." + *label; if ( Ithis _inst->add_phantom_label_name(label, this_inst->get_n_children())) { this_inst->out_error("ZON032", cerr, TRUE); cerr « "The phantom label '" « *label « '" already exist!\n"; status = FALSE;} // make a segment flag for the Oth segment if (status)! zeroth.flag_string = this_zone->make_segment_flag(&seg_index); if (!zeroth_flag_string) status = FALSE;} // make a segment flag for the first segment if (status)! M-605 // turnstile code exists in O'th segment, but account for it in first, // since we always have O'th as an extra segment and it would not get // otherwise accounted for (we would not add a segment after the // first at the correct number of cycles). thϊs_zone->bump_segment(); first_flag_string = this_zone->make_segment_flag(&seg Jndex); if (!first_flag_sιring) status = FALSE;} // instantiate a turnstile for the first segment if (status)! if (!makejurnstile(first_flag_string, 1)) status = FALSE;} // (10) Mark this segment boundary for possible next segment insertion of // "reset.from_phant_arr.ptr"s. Save the instance and child index // for the spot we are inserting at. save_segment_boundary(this_ϊnst, this_inst->get.partitioned_size()); // we have now officially entered the first segment, so // instantiate a free.segment block for segment 0 if (status)! if (!make_free_segment(zeroth_fiag_string)) status = FALSE;} // set contents of temporal class' flag string to first flag string if (status) *fiag_string = *first_flag_string; // // restore previous block context // thϊs_ϊnst->pop_context(); return status;} II create.new.segment // Overloaded function from temporal class. // It was determined that a new segment should be added. // The multi-temporal class must handle iterated code segment loops and // phantom arrays in addition to the normal turnstile and phantom wires // of a new segment. // We must (* was added beyond base class function): // 1. Create a segment flag phantom wire for the new segment. // 2. Create phantom wires for all pending inputs. // 3. *Create phantom arrays for all pending inputs. // 4. instantiate "to_phantom_arr_copy"s for all required pending inputs. // 5. instantiate bottom-of-loop code for the current segment. // 6. Instantiate a ".turnstile" block to end the current segment. // 7. instantiate "dupe_phantom_arr"s for all pending inputs. // 8. instantiate "reset.to_phant_arr_ptr"s for all required pending inputs // (instantiated at previous segment boundary). // 9. *Instantiate "reset_from_phant_arr_ptr"s for all required pending inputs. // 10.*Mark this segment boundary for possible next segment insertion of // "reset_from_phant_arr_ptr"s. // 11. Instantiate a ".free.seg" block. // 12. instantiate the loop init block using repeat count for zone // 13.*Create top-of-loop code for the new segment. // 14.*Instantiate "_from_phantom_arr_copy"s to copy to these phantom wires // for the next segment. BOOLEANmult i_temporal::create_new_segment(int duration) { int segjndex; // wire index for new segment string* new_flag_string; zone* before.zone = this.zone;// zone before segment edge zone* after.zone = this.zone; // zone after segment edge int.arraybottom.of Jast.copy;// type of copy for each wire, last loop int.arraytop.of.next.copy;// type of copy for each wire, next loop // see if we must create a new segment regardless if (tes t_block_duration(duration)) { // no, so check for any other cases // if we force a boundary, don't actually create a new segment, but // make zone boundary instead if (this_zone->boundary_forced()) { this_zone->clear_forced_flag(); // Make sure that a new segment will not immediately follow // zone boundary. If so, don't make a boundary but just // make a new segment. if (!segment_would_follow_boundary(duration)) return create_zone_boundary(); } // must also check if poll block required, in which case we do not // want a new segment unless a new one would immediately follow poll // block anyway if (poll_block_required(duration)) SUBSTITUTE SHEET M-607 { if (!segment_would_follow_polI(duration)) return add_poll_block(); } } // go ahead and create new segment, since that's the only thing left to do // set overhead cycles we had to allow for in this segment thϊs_zone->set_overhead_allowed_for(ending_overhead()); // get zone for previous block partitioned if (last.zone.for.partitioning != (zone*) NULL) before.zone = last.zone.for.partitioning; // advance to next segment thϊs_zone->bump.segment() ; #ifdef DEBUG cerr « "making new segmentXn"; debug = TRUE; #endif " // analyze the type of copies to do for each phantom wire for the bottom // of previous loop, between loops, and top of next loop if (lanalyze.phantom jnulti_copies(before_zone, after.zone, &bottom.of_last_copy, &top_of_next_copy)) return FALSE; #ifdefDEBUG debug = FALSE; #endϊf // (1) create a new segment flag, and return its name new_flag_string = this_zone->make_segment_flag(&seg_index); if (!new.flag_string) return FALSE; // (1.5) create non-phantom arrays, which are the destinations for // new wires in repeated code if (!make_non_phantom_arrays(&bottom_of_last.copy)) return FALSE; // (2) create phantom wires for all pending inputs if (!thϊs_zone->make_phantom_wires()) return FALSE; // (3) create phantom arrays, which are the signal sources for // phantom wires if (Imake.phantom.arraysO) return FALSE; // (3.5) make ptrs to and from phantom arrays if ( imake .to_phantom_array_ptrs(&bottom_of Jast.copy)) return FALSE; if ( !make_from_phantom_array_ptrs(&top_of_next_copy)) return FALSE; // (4) Instantiate "to_phantom_arr_copy"s for all pending inputs // which require it. // Each time through the previous segment's loop, a new value is copied // to the next array position for new wires, if (imake _to_phantom.arr_copys(&bottom_of Jast.copy, before.zone, after . zone)) return FALSE; // (5) Instantiate bottom-of-loop code for the current segment, if (imake Joop . bottom(before.zone)) return FALSE; // bottom of previous segment II between segments // we are no longer in looped code set.not.in.repeat.codeO; // (6) instantiate a turnstile for this new segment if (!makejurnstile(new_flag_string, this_zone->seg_num())) return FALSE; // (7) instantiate "dupe_phantom_arr"s for all pending inputs, if (idupe.phantom.arraysO) return FALSE; // (8) Instantiate "rese tjo_phant_arr_ptr"s for all required pending inputs // (inserted at previous segment boundary), if (!make_to_phant_arr_ptr_resets(&bottom_of_last_copy)) return FALSE; // (9) Instantiate "reset_from_phant_arr_ptr"s for all required pending // inputs. This initializes "from_phantom_arr" pointer to make // samples available for the new segment, if ( !make_fr_phant_arr_ptr_resets(&top_of_next_copy)) return FALSE; // (10) Mark this segment boundary for possible next segment insertion of // "reset_frorn_phant_arr_ptr"s. Save the instance and child index // for the spot we are inserting at. save_segment.boundary(this_inst, this_inst->get_partitioned_size()); 95^ M-609 // free any wires that are hanging around because they are loop inputs this_zone->free_pending.loop_wiresO; // (11) instantiate a free.segment block, passing current flag name if (!make_free_segment(fiag_string)) return FALSE; // (12) instantiate the loop init block using repeat count for zone if (ImakeJoop.init.blockO) return FALSE; // between segments /////////////////////////////////////////// // top of next segment // we are back in looped code set_in_repeat_code(); // (13) Create top-of-Ioop for the new segment. if (Imake.Ioop opO) return FALSE; // (14) *Instantϊate "_from_phantom_arr_copy"s to copy to these phantom // wires from the phantom arrays. // Each time through the next segment's loop, a new value is copied to // the new phantom wire from the next position in the corresponding // phantom array. if (!make_from.phantom_arr_copys(&top_of_next.copy, before.zone, after.zone)) return FALSE; // set contents of temporal class' flag string to first flag string *flag_string = *new.flag_string; if (this.zone->cycles_used() > this_zone->max_cycles()){ this_ϊnst->out_error("ZON033", cerr, TRUE); cerr « 'The sample rate is too high.Vn"; out_sample_period_msg(cerr) ; cerr « ", but " « this_zone->cycles_usedO « " overhead cycles are required to create a new segmentΛn"; return FALSE;} return TRUE;} II create.zone.boundary // Overloaded function from temporal class. // It was determined that a new segment should be added. M-610 // The multi-temporal class must handle iterated code segment loops and // phantom arrays in addition to the normal turnstile and phantom wires // of a new segment. // We must (* was added beyond base class function): // 1. Create a segment flag phantom wire for the new segment. // 2. Create phantom wires for all pending inputs. // 3. *Create phantom arrays for all pending inputs. // 4. *Instantiate "to_phantom.arr_copy"s for all required pending inputs. // 5. instantiate bottom-of-loop code for the current segment. // 6. Instantiate a ".turnstile" block to end the current segment. // 7. instantiate "dupe_phantom_arr"s for all pending inputs. // 8. instantiate "reset_to_phant_arr_ptr"s for all required pending inputs // (instantiated at previous segment boundary). // 9. instantiate "reset_from_phant_arr.ptr"s for all required pending inputs. // 10.*Mark this segment boundary for possible next segment insertion of // "reset_from_phant_arr_ptr"s. // 11. Instantiate a ".free.seg" block. // 12. instantiate the loop init block using repeat count for zone // 13.*Create top-of-loop code for the new segment. // 14.*Instantiate "_from_phantom_arr_copy"s to copy to these phantom wires // for the next segment. BOOLEANmultijemporal: :create_zone_boundary () ! zone* before.zone = this.zone;// zone before segment edge zone* after zone = this zone; // zone after segment ed2e in t_arraybottom_of _last_copy;// type of copy for each wire, last loop in t_arraytop_of_next_copy;// type of copy for each wire, next loop // get zone for previous block partitioned if (last_zone_for_partitioning != (zone*) NULL) before.zone = last_zone_for_partitioning; #ifdef DEBUG cerr « "making new zone boundary\n"; debug = TRUE; #endif // analyze the type of copies to do for each phantom wire for the bottom // of previous loop, between loops, and top of next loop if (!analyze_phantom_multi_copies(before_zone, after.zone, &bottom_of_last_copy, &top_of_next_copy)) return FALSE; M-611 #ϊfdef DEBUG debug = FALSE; #endϊf // (1.5) create non-phantom arrays, which are the destinations for // new wires in repeated code if (!make_non_phantom_arrays(&bottom_of_last_copy)) return FALSE; // (2) create phantom wires for all pending inputs // but only if we need them in the next section if (!thϊs_zone->make_phantom_wires(&top_of.next_copy)) return FALSE; // (3) don't create phantom arrays (copies of non-phantom arrays) // (3.5) just make ptrs from phantom arrays if (!make_from_phantom_array_ptrs(&top_of_next.copy)) return FALSE; // (4) Instantiate "to_phantonι_arr_copy"s for all pending inputs // which require it. // Each time through the previous segment's loop, a new value is copied // to the next array position for new wires, if ( !make_to_phantom.arr_copys(&bottom_of_last_copy, before.zone, after.zone)) return FALSE; // (5) Instantiate bottom-of-loop code for the current segment, if (!make_loop_bottom(before_zone)) return FALSE; //bottom of previous segment II between segments // we are no longer in looped code set.not_ϊn_repeat_code(); // (7) do not "dupe_phantom_arr"s // (8) Instantiate "resetjo_phant_arr_ptr"s for all required pending inputs // (inserted at previous segment boundary), if (!make_to_phant_arr_ptr_resets(&bottom_of_last_copy)) return FALSE; // (9) Instantiate "reset_from_phant_arr_ptr"s for all required pending // inputs. This initializes "from.phantom.arr" pointer to make // samples available for the new segment, if (!make_fr_phant_arr_ptr_resets(&top.of_next_copy)) M-612 return FALSE; // (10) Mark this boundary for possible next segment insertion of // "reset_from_phant_arr_ptr"s. Save the instance and child index // for the spot we are inserting at. save_segment_boundary(this_inst, this Jnst- >get_partitioned_size()); // (12) instantiate the loop init block using repeat count for zone if (imake Joop . init . blockO) return FALSE; // between segments II top of next segment // we are back in looped code set_in_repeat_code(); // (13) Create top-of-loop for the new segment. if (imakeJoopjopO) return FALSE; // (14) instantiate "_from_phantom_arr_copy"s to copy to these phantom // wires from the phantom arrays. // Each time through the next segment's loop, a new value is copied to // the new phantom wire from the next position in the corresponding // phantom array. if (!make_from_phantom_arr_copys(&top_of_nex t.copy, before.zone, after.zone)) return FALSE; return TRUE;} II boundary.overhead // Compute number of phantom block overhead cycles for creating a new // zone boundary. // Exits if error. int multi_temporal::boundary_overhead() ! static intloop.bottom.cycles = UNKNOWN.DURAHON; static intloop.init.cycles = UNKNOWN.DURAHON; int to . ph.array.cycles; int fr.ph.array.cycles; int to . ph.array.reset.cycles; inl fr.ph.array.reset.cycles; zone* before.zone = this.zone;// zone before segment edge 13 zone* after.zone = this.zone; // zone after segment edge ϊnt.arraybottom.of . last.copy;// type of copy for each wire, last loop int . arraytop.of.next.copy;// type of copy for each wire, next loop ϊnt n.cycles; ϊnt before.segment.repeats; int after.segmen t . repeats; before.segment.repeats = (int) before_zone->get_repeat_count(); after.segmen t . repeats = (int) after_zone->get_repeat_count(); // analyze the type of copies to do for each phantom wire for the bottom // of previous loop, between loops, and top of next loop if (!anaIyze_phantom_multi_copies(before_zone, after.zone, &bottom_of_last_copy, &top_of_next_copy)) exit(l); // if we don't have # of cycles for blocks, look them up // compute number of cycles for each to phantom array copy block if (!n_to_phantom_arr_copy_cycles(&bottom_of_Iast.copy,&to_ph_array_cycles)) exϊt(l); // compute number of cycles for loop bottom block if (loop.bottom.cycles = UNKNOWN.DURATION) if ((loop.bottom.cycles = get_block_duration(LOOP_BOTTOM_STR)) = UNKNOWN.DURATION) exϊt(l); // to phantom array reset blocks if (!n_to_phant_arr_ptr_resets(&bottom_of Jast.copy, &to_ph_array_reset_cycles)) exit(l); // from phantom array reset blocks if (!n_fr_phant_arr_ptr_resets(&top_of_next_copy, &fr_ph.array_rese t.cycles)) exit(I); // loop init block if (loop.init.cycles = UNKNOWN.DURATION) if ((loop.init.cycles = get_block_duration(COPY_CONSTANT_STR)) = UNKNOWN.DURAHON) exit(l); // compute number of cycles for each from phantom array copy block if (!n_from_phantom_arr_copy_cycles(&top_of_next_copy, &fr_ph_array_cycles)) exit(l); n.cycles = loop_bottom_cycles*before_segmen t.repeats + loop.init.cycles -614 + to . ph.array.reset.cycles + fr.ph.array.reset.cycles + to_ph_array_cycles*before_segment . repeats + fr.ph.array.cycles *after_segmen t.repeats ; return n.cycles;} II make.zone.finish // Multi-rate version of make.zone.finish. // Add the turnstile and jump blocks at the end of a zone. // Called after the ending fifo blocks are instantiated. BOOLEAN multi_temporal::make_zone jBnishO { string* zeroth_seg_name; BOOLEANstatus = TRUE; int n.segments; zone* before.zone; // zone before segment edge zone* after.zone; // zone after segment edge = same int.arraybottom.of.last.copy;// type of copy for each wire, last loop int.arraytop.of.next.copy;// type of copy for each wire, next loop // this function gets called at the top level multijemporal object // rather than during partitioning, so us the saved top of loop zone if (top.of.loop.zone != (zone*) NULL) before.zone = top.of.loop.zone; else before.zone = this.zone; after.zone = before.zone; // save current block context and set instance info in block this_inst->push_context(); // get # of segments partitioned n.segments = this_zone->seg_num(); // get segment flag string for the Oth segment zeroth.seg.name = this_zone->seg_flag_name(0); // instantiate a turnstile to wait for the zeroth segment // but first advance to next segment this_zone->bump_segment(); // (5) Instantiate bottom-of-loop code for the current segment. if (status)! if (!make_loop_bottom(before_zone)) status = FALSE;} // bottom of previous segment 96θ M-615 II between segments // we are no longer in looped code set.no t.in.repea t_code() ; // instantiate a turnstile to wait for the zeroth segment if (status)! if (!make.turnstile(zeroth.seg_name, 0)) status = FALSE;} // (8) Instantiate "reset Jo.phan _arr_ptr"s for all required pending inputs // (inserted at previous segment boundary), if (status)! if (!make_to_phant_arr_ptr_resets(&bottom_of_last_copy)) status = FALSE;} if (status)! // instantiate a free.segment block, passing current flag name if (!make_free_segment(flag_string)) status = FALSE;} if (status)! if(!makejump_block(loopback_Iabel)) status = FALSE;} if (status) status = generate_GSP_init_code(n_segments, zeroth_seg_name, loopback.label); //restore previous block context thϊs_ϊnst->pop_context() ; return status;} nmnmimimiuunuuiniiinimiiimimimmmmimnπiinπi ft analyze.phantom.multi.copies // Analyze all phantom wires (pending inputs) and characterize the types // of multiple copy operations to perform at the bottom of the previous // segment loop, top of next segment loop, and between segment loops. // Returns FALSE if failed. BOOLEANmulti_temporal::anaIyze_phantom_multi_copies(zone* before.zone, zone* after.zone, int.array* bottom.of.last.copy, int.array* top.of.next.copy)! ϊnstance*ϊnst; ϊnt wire; zone* wire.zone; M-616 before.segment.repeats = before_zone->get_repeat_count(); after.segment.repeats = after_zone->get.repeat_count(); for (i=0; i<this_zone->pending_size(); i++){ // pre-initialize arrays (*bottom_of_last_copy)[i] = NOTHING; (*toρ_of_next_coρy)[i] = NOTHING; // get zone for next wire inst = this.zone- >pending_instance(i); wire = this_zone->pending_wire(i); wire.zone = inst->get_zone_for_wire(wire); // also get level for wire // if level 0, this is just-generated wire, so we need to save its // value index = inst->get_last_phantom(wire , &level); // if wire just generated in "before" zone, assume we need to copy it if (level == 0 && before.zone == wire.zone) { (*bottom_of _last_copy)[i] = ORDINARY_COPY_TO_WIRE; #ifdef DEBUG if (debug) cerr « "Assume level 0 ordinary copy to wire\n"; #endif } #ifdef DEBUG if (debug) { inst->push_context(); string* hier.name; int level; int index = inst->ge t_last_phantom(wire , &level); hier.name = inst->prototype()->hier_storage_name_at_index(index); cerr « "analyzing phantom multi.copy for " « *hier_name « "\n"; inst->pop_context() ; M-617 } #endϊf // also need repeat count for this zone if (wire.zone != (zone*) NULL) { wire.zone.repeats = wire_zone->get.repeat_count(); #ϊfdef DEBUG if (debug) { cerr « "wire zone repeats: " « wire.zone.repeats « " before repeats: " « before.segment.repeats « " after repeats: " « after.segment.repeats « "\n"; } #endif // if repeat count is 1, then we don't need an array, so skip // remaining code if (wire.zone.repeats > 1) { if (wire.zone.repeats == before.segment.repeats) { // wire zone rate is compatible with before segment // but generate copy to array only if level 0 wire // which was generated in before zone if (level = 0 && before . zone == wire.zone) { (*bottom_of Jast_copy)[i] = NORMAL . COPY.TO.ARRAY; #ϊfdef DEBUG if (debug) cerr « "Normal copy to array\n"; #endϊf } if (before.segment.repeats == after.segment.repeats) { // wire zone rate compatible with after segment, so // do copy from array at top of after segment (*top_of_next_copy)[i] = NORMAL.COPY.FROM.ARRAY; #ϊfdef DEBUG if (debug) cerr « "Normal co from arra \n"; M-618 #endif } else if (wire . zone . repeats == after.segment.repeats) { // wire may be used in this zone, so make a local copy // available (*top_of_next_copy)[i] = NORMAL.COPY.FROM.ARRAY; #ifdef DEBUG if (debug) cerr « "Normal copy from array\n"; #endif } // Wire may be used in later zone which is at "before" // repeat rate, or in "after" segment right before an // interpolator or decimator. // If it is used by an interpolator in "after" segment, // we must make an upsampled copy available of it, // or if used by a decimator in "after" segment, // must if (wire.zone.repeats < after.segment.repeats) { (*top_of_next_copy)[i] = UPSAMPLE.COPY_FROM . AR- RAY; #ifdef DEBUG if (debug) cerr « "Upsample copy from array\n"; #endif } else if (wire.zone.repeats > after.segment.repeats) { (*top_of_next_copy)[i] = DOWNSAMPLE.COPY.FRO- M.ARRAY; #ifdef DEBUG if (debug) cerr « "Downsample copy from array\n"; #endif M-619 } } return TRUE;} II makeJoop.ini t.block // Make a loop init block to initialize the given loop counter. // Do this by calling make.copy.constant.block. // This function first creates the loop counter. It gets the loop count // from the repeat count for the current zone. // Returns FALSE if failed. BOOLEAN multi_temporal::make_loop_init_block() ! int loop.count; // first save the zone for the top of the loop // which we will need when be make the loop bottom top.of.loop.zone = this.zone; // loop count is repeat count for the current zone loop.count = (ϊnt) thϊs_zone->ge t.repeat.countO; // don't bother if loop count is 1, which isn't a loop if (loop.count > 1) { // create the loop counter, and get its name Iast.loop.counter.name = this_zone->make.loop.counter( &Ioop_counter.ϊndex, &Ioop_counter_instance); if (Has t.Ioop.counter.name) return FALSE; return make_copy_constant_block(last_loop_counter_name, (long) loop.count);} else return TRUE;} It make.phantom.arrays // Make a new level of phantom array for each pending input. // Phantom arrays are used to buffer phantom wire values for repeated code // segments. // Returns FALSE if failed to make phantom array. BOOLEAN muIti_temporal::make_phantom_arraysO { int i; int level; instance*inst; int wire; zone* wire.zone; long wire.zone . repeats ; expr* arr . size.expr; int prev Jndex; int index; string* prev.name; string* name; char type; string* arr.name; int arr.wire; BOOLEANstatus = TRUE; for (i=0; i<this_zone->pending_size(); i++){ // get wire and zone for next wire inst = this_zone->pending_instance(i); wire = this_zone->pending.wire(i); wire_zone = inst->get_zone_for_wire(wire); // also need repeat count for this zone if (wire.zone != (zone*) NULL) wire.zone.repeats = wire_zone->ge t_repeat_count(); else wire_zone_repeats = 1 ; #ifdef DEBUG Strin2* n; // get level for last phantom for this wire index = ins t->getjast_phan torn (wire , &level); n = inst->prototype()-> hier_storage_name_at_index(index); cerr « "making phantom arrays for wire " « *n « ' Λn"; #endif // if repeat count is 1, then we don't need an array, so skip // remaining code if (wire.zone.repeats > 1) { // make an expression for the array size from it arr.size.expr = new expr( wire.zone.repeats); // get level for last phantom for this wire index = inst->get_last_phantom(wire , &level); // we also want previous wire level level—; prevjndex = inst->get_phantom(wire , level); // get name of wires that we need name = inst->prototype()->storage_name_at_index(index); prev.name = inst->prototype()->storagejιame_at_index(prev_index); type = inst->prototypeO->get_storage.type(index); // we must always created a new phantom array to hold the values // for the new segment arr.name = new string(ARRAY_PREFIX_STR); *arr_name = *arr_name + *name; // add this array to wire instance status = ϊnst->add_phantom.storage_name(arr_name, arr.size.expr, &arr_wire, type); if (Istatus) { inst->out_error("ZON062", cerr, FALSE); cerr « "A phantom array named '" « *arr.name « '" already exists !\n"; break; } #ifdef DEBUG else { string* hier.name; hϊer_name = ϊnst->prototype()->hier_storage_name_at_index(arr_wire); cerr « "making phantom array " « *hier_name « "\n"; } #endϊf ) } return status;} II make_to_phantom_array_ptrs // Make "to" pointers into the phantom arrays as required. // Called after new phantom wires have been created. // Returns FALSE if failed to make phantom array. BOOLEANstatus = TRUE; for (i=0; i<this_zone->pending_size(); i++){ // get wire and zone for next wire inst = this_zone->pending_instance(i); wire = this_zone->pending_wire(i); wire.zone = inst->get_zone_for_wire(wire); // also need repeat count for this zone if (wire_zone != (zone*) NULL) wire.zone.repeats = wire_zone->get_repeat_count(); else wire_zone_repeats = 1; #ifdef DEBUG string* n; // get level for last phantom for this wire index = inst->get_last_phantom(wire , &level); n = inst->prototype()-> hier_storage_name_at_index(index); cerr « "making to phantom array pointers for wire " « *n « "\n"; #endif // if repeat count is 1, then we don't need an array, so skip // remaining code if ( wire.zone.repeats > 1 && (*bottom_of_last_copy)[i] != NOTHING ) { // get level for last phantom for the corresponding array if (!level_for_latest_array(i, &level)) { M-623 status = FALSE; break; } index = inst->get_phantom(wire, level); // we want previous wire level if (level >= 1) level--; prevjndex = ϊnst->get_phantom(wire , level); // get name of wire that we need prev.name - inst->prototype()->storage_name_at_ϊndex(pι-ev_ϊndex) ; // prepend a special prefix to create name for "to" array ptr ptr.name = new string(TO_ARRAY_PTR_STR); *ptr_name = *ptr_name + *prev_name; // add this to our instance status = ϊnst->add.phantom_storage_name(ptr_name, (expr*) NULL, &ptr_wire, 'h'); if (Istatus) { // there may already be a "to" array pointer because // it was already created for a decimator output wire status = TRUE; } #ifdef DEBUG else { string* hierjiame; hier.name = inst->prototype()-> hϊer_storage_name_at_index(ptr.wϊre); cerr « "making 'to' array ptr " « *hier_name « "\n"; } #endif } } return status;} II make_from_phantom_array_ptrs // Make "from" pointers for the phantom arrays as required. // Called after new phantom wires have been created. // Returns FALSE if failed to make phantom array. int ptr.wire; BOOLEANstatus = TRUE; for (i=0; i<this_zone->pending . size(); i++){ // get wire and zone for next wire inst = this_zone->pending.instance(i); wire = this_zone->pending_wire(i); wire . zone = inst->get_zone_for_wire(wire); // also need repeat count for this zone if (wire_zone != (zone*) NULL) wire_zone_repeats = wire_zone->get_repeat_count(); else wire.zone . repeats = 1; #ifdef DEBUG string* n; // get level for last phantom for this wire index = inst->ge t.las t_phantom(wire , &level); n = inst->prototype()-> hier_storage_name_at_index(index); cerr « "making from phantom array pointers for wire " « *n « "\n"; #endif // if repeat count is 1, then we don't need an array, so skip // remaining code if (wire.zone.repeats > 1 && (*top_of_next_copy)[i] != NOTHING) { // get level for last phantom for the corresponding array . if (ilevel.forjates t_array(i, &level)) { status = FALSE; M-625 break; } index = inst->get_phantom(wire, level); // get name of wire that we need name = ϊnst->prototype()->storage_name_at Jndex (index); // prepend a special prefix to create name for "from" array ptr ptr . name = new string(FR_ARRAY_PTR_STR); *ptr_name = *ptr.name + *name; // add this to wire instance status = inst->add_phantom.storage_name(ptr_name, (expr*) NULL, &ptr_wire, 'h'); if (Istatus) status = TRUE; #ifdef DEBUG else { string* hier.name; hier.name = inst->prototype()-> hier_storage.name_at_index(ptr.wire); cerr « "making 'from' array ptr " « *hϊer_name « "\n"; } #endϊf } } return status;} II make.non.phantom.arrays // If a new wire, then make an initial non-phantom array to hold its // output values if it is in repeated code. //Also create its "to" ptr. // Called BEFORE new phantom wires have been created. // Returns FALSE if failed to make an array. BOOLEAN nιultϊ_temporaI::nιake_non_phantom_arrays(ϊnt.array* bottom_of_last_copy) ! ϊnt i; int level; instance*ϊnst; int wire; zone* wire.zone; long wire.zone.repeats; M-626 int index; string* name; char type; string* arrjiame; int aπjwire; BOOLEANstatus = TRUE; for (i=0; i<this_zone->pending_size(); i++){ // get wire and zone for next wire inst = this_zone->pending Jnstance© ; wire = this_zone->pending_wire(i); wire.zone = inst->get_zone_for_wire(wire); // also need repeat count for this zone if (wire.zone != (zone*) NULL) wire.zone.repeats = wire.zone ->get_repeat.count(); else wire.zone.repeats = 1; #ifdef DEBUG string* n; // get level for last phantom for this wire index = inst->get_last_phantom(wire , &level); n = inst->prototype()-> hier.storage.name.at.index(index); cerr « "making non-phantom arrays for wire " « *n « "\n"; #endif // if repeat count is 1, then we don't need an array, so skip // remaining code // and make array only of we need to copy from the previous section if (wire.zone.repeats > 1 && (*bottom_of_las t_coρy)[i] != NOTHING) { // make an expression for the array size from it arr_size_expr = new expr(wire_zone_repeats); // get level for last phantom for this wire index = inst->getJast_phantom(wire , &level); // get name of wires that we need name = inst->prototype()->storage.name_a t.index(index); type = inst->prototype()->get_storage_type(index); // prepend a special prefix to create name for array arr.name = new string(ARRAY_PREFIX_STR); -627 *arr_name = *arr_name + *name; // add this array to wire instance status = inst->add_phantom_storage_name(arr_name, arr_size_expr, &arr_wire, type); if (Istatus) { inst->out_error("ZON059", cerr, FALSE); cerr « "An array named '" « *arr_name « '" already exists !\n"; break; } #ϊfdef DEBUG else { string* hier.name; hier.name = inst->prototype()-> hier_storage_name_at_index(arr_wire); cerr « "making non-phantom array " « *hier.name « "\n"; } #endϊf // prepend special prefix to create name for "to" array ptr arr.name = new string(TO_ARRAY_PTR_STR); *arr_name = *arr_name + *name; // add this to our instance status = inst->add.phantom_storage_name(arr_name, (expr*) NULL, &arr_wire, 'h'); if (Istatus) { ϊnst->out_error("ZON079", cerr, FALSE); cerr « "A phantom 'to' array pointer named '" « *arr_name « '" already exists !\n"; break; } #ifdef DEBUG else { string* hier.name; hier.name = inst->prototype()-> hier_storage_nanιe.at_index(arr_wire); -628 cerr « "making 'to' array ptr " « *hier_name « 'Λn"; } #endif } } return status;} II dupe.phantom.arrays // Duplicate the pending phantom arrays for the segment boundary. // Returns FALSE if failed. BOOLEAN multi_temporal::dupe_phantom_arrays() { int i; int level; instance*inst; int wire; zone* wire.zone; long wire.zone.repeats; expr* arr.size.expr; int prev Jndex; int index; string* prev.name; string* name; string* arr.name; int src.index; instance*src_inst; int dest.index; instance*dest_inst; BOOLEANstatus = TRUE; for (i=0; i<this_zone->pending_size(); i++){ // get zone for next wire inst = this_zone->pending_instance(i); wire = this_zone->pending_wire(i); wire.zone = inst->get.zone_for.wire(wire); // also need repeat count for this zone if (wire_zone != (zone*) NULL) wire.zone.repeats = wire_zone->get_repeat_count(); else wire.zone.repeats = 1; // if repeat count is 1 , then we don't need an array, so skip 97k // remaining code if (wire.zone.repeats > 1) { // make an expression for the array size from it arr.size.expr = new expr(wire_zone_repeats); // get level for last phantom for the corresponding array if (!Ievel_for_latest_array(i, &level)) { status = FALSE; break; } index = inst->get_phantom(wire, level); // get level for previous phantom if (!level.for_previous_array(i, level, &level)) { status = FALSE; break; } // get corresponding wire index prev.index = inst->get.phantom(wire , level); // get name of wires that we need name = inst->prototype()->storage_name_a t.indexfindex); prev.name = inst->prototype()->storage_name_at.index(prev.index); // create name for source array arr.name = new string(ARRAY_PREFLX_STR); *arr.name = *arr_name + *prev.name; // look up index and instance for the source array using // original wire parent instance if (!inst->find.wire_name(arr.name, &src_index, &src_inst)) { this_inst->out_error("ZON067", cerr, FALSE); cerr « "Unable to find the source array '" « *arr_name « '"Λn"; status = FALSE; break; } // create name for destination array arr.name = new string(ARRAY_PREFTX_STR); M-630 *arr_name = *arr_name + *name; // look up index and instance for the destination array if (!inst->find_wire_name(arr_name, &dest.index, &dest_inst)) { this_inst->out_error("ZON068", cerr, FALSE); cerr « "Unable to find the destination array '" « *arr_name « '"Λn"; status - FALSE; break; } // create array of I/O wire indices int ios[2]; ios[0] = src.index; ios[l] = dest Jndex; // create array of VO wire instance pointers instance* io_insts[2]; io_insts[0] = src.inst; io_insts[l] = dest.inst; // create array of parameter expressions expr* param.vals! 1]; param.valsfO] = arr_size_expr; if (!nιake_phantom_inst_with_args(DUPE_PHANT_ARR_STR, 2, ios, iojnsts, 1, param_vals)) { status = FALSE; break; } } } return status;} II n_dupe_phantom_arrays_cycles // Compute the number of cylces to duplicate the pending phantom arrays for // the segment boundary. // Returns FALSE if failed. BOOLEAN multijemporal::n_dupe_phantom_arrays_cycles(int *n_cycles_ptr) { int i; instance*inst; int wire; -631 zone* wire.zone; long wire.zone.repeats; BOOLEANstatus = TRUE; ϊnt dupe.ph.array.cycles; ϊnt n_cycles = 0; for (i=0; i<this_zone->pendϊng_size(); i++){ // get zone for next wire inst = this_zone->pending_instance(I); wire = this_zone->pending_wire(i); wire.zone = ϊnst->get_zone_for_wire(wire); // also need repeat count for this zone if (wire.zone != (zone*) NULL) wire.zone . repeats = wire_zone->ge t.repeat_count(); else wire.zone.repeats = 1; // if repeat count is 1, then we don't need an array, so skip // remaining code if (wire.zone.repeats > 1) { // create array of parameter expressions expr* param_vals[l]; param_vals[0] = new expr(wire_zone_repeats);// repeat count is param // always recompute dupe.ph.array cycles because its variable if ((dupe_ph_array_cycles = get_block_duration(DUPE_PHANT_ARR_STR, 1, param.vals)) == UNKNOWN.DURATION) return FALSE; } else // if not repeated, no phantom array dupe.ph.array.cycles = 0; // tally count of cycles n.cycles += dupe.ph.array.cycles;} *n_cycles_ptr = n.cycles; return TRUE;} II make.to.phantom.arr.copys // Make a "to phantom arr copy" block for each pending input which has // one specified in the "bottom.of Jas t popy" array. //This block copies from a wire to its corresponding phantom array, which // acts as a buffer for wire value to the wire phantom. M-632 // Two types of blocks can be created: normal array copy blocks and // downsampling array copy blocks, depending on bottom.of.last.copy. // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. BOOLEAN multi.temporal::makejo_phantom_arr_copys( int . array* bottom.of.last.copy, zone* before.zone, zone* after.zone)! int i; int copy.status; int status = TRUE; NOREF(before.zone) ; NOREF(af ter.zone) ; for (i=0; i<this_zone->pending_size(); i++){ copy.status = (*bottom_of_las t_copy)[i]; switch (copy.status) { case NORMAL.COPY.TO.ARRAY: status = make_normal_to_phantom_arr_copy(i); break; case ORDINARY.COPY.TO.WIRE: // if no array involved, just make ordinary phantom wire copy status = make_phantom_copy_block(i); break; default: // else do nothing break; } if (Istatus) break;} return status;} II njo.phantom.arr.copy.cycles // Computes the cycles for all to phantom array copies. // Returns FALSE if error. BOOLEAN multi_tenιporal::n_to_phantom_arr_copy_cycles( int.array* bottom.of.last.copy, int *n_cycles_ptr) { int i; int copy.status; int status = TRUE; M-633 static int to.phant.arr.cycles = UNKNOWN.DURATION; static ϊntcopy.cycles = UNKNOWN.DURATION; int n.cycles = 0; // if we don't have # of cycles for blocks, look them up if (to_phant_arr_cycles = UNKNOWN.DURATION) if ((to_phant_arr_cycles = get_block_duration(TO_PHANT_ARR_STR)) = UNKNOWN.DURATION) return FALSE; if (copy . cycles == UNKNOWN.DURAHON) if ((copy.cycles = get_block_duration(COPY_STR)) = UNKNOWN.DURATION) return FALSE; for (i=0; i<this_zone->pending_size(); i++){ copy_status = (*bottom_of_last_copy)[i]; switch (copy.status) { case NORMAL.COPY.TO.ARRAY: n.cycles += to.phant.arr.cycles; break; default: // if no array involved, just ordinary phantom wire copy n.cycles += copy.cycles; break; } } *n_cycles.ptr = n.cycles; return TRUE;} II make.from.phantom.arr.copys // Make a "from phantom arr copy" block for each pending input which has // one specified in the "top.of.next.copy" array. //This block copies from a phantom array to its corresponding wire, which // acts as a buffer for wire value to the wire. //Two types of blocks can be created: normal array copy blocks and // upsampling array copy blocks, depending on top.of.next.copy. // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. BOOLEAN multi_temporal::make_from_phantom_arr_copys( int.array* top.of.next.copy, zone* before.zone, zone* after.zone)! M-634 int i; int copy . status; int status = TRUE; for (i=0; i<this_zone->pending.size(); i++){ copy . status = (*top_of_next_copy)[i]; switch (copy.status) { case NORMAL.COPY.FROM.ARRAY: status = make_normal_from_phantom_arr_copy(i); break; case UPSAMPLE . COPY . FROM.ARRAY: status = make_upsample_from_phantom_arr_copy(i, before . zone, after.zone); break; case DOWNSAMPLE . COPY.FROM.ARRAY: status = make_downsample_from_phantom_aιτ.copy(i, before.zone, after.zone); break; default: break; } if (istatus) break; } return status;} // n.from.phantom.arr.copy . cycles // Computes the cycles for all from phantom array copies. // Returns FALSE if error. BOOLEAN multi.tenιporal::n_from_phantom_arr.copy_cycles( in t_array* top_of_next_copy, int *n_cycles_ptr){ int i; int copy.status; int status = TRUE; static int fr.phant.arr.cycles = UNKNOWN.DURAHON; static intup_fr_ph_arr_cycles = UNKNOWN.DURATION; int n.cycles = 0; // if we don't have # of cycles for blocks, look them up if (fr_phan t.arr.cycles == UNKNOWN.DURATION) M-635 if ((fr.phant.arr.cycles = get_block_duration(FR_PHANT_ARR_STR)) = UNKNOWN.DURAHON) return FALSE; if (up_fr_ph_arr_cycles = UNKNOWN.DURATION) if ((up_fr_ph_arr_cycles = get_block_duration(UP_FR_PH_ARR_STR)) = UNKNOWN.DURATION) return FALSE; for (ϊ=0; ϊ<this_zone->pendϊng_sizeO; i++){ copy.status = (*top_of_next_copy)[i]; switch (copy.status) { case NORMAL . COPY.FROM . ARRAY: n.cycles += fr.phant.arr.cycles; break; case UPSAMPLE.COPY.FROM.ARRAY: n.cycles += up .fr.ph.arr.cycles; break; default: break; }} *n.cycles_ptr = n_cycles; return TRUE;} II make.normal o.phantom.arr.copy // Make a normal "to_phant_arr" block // This block copies from a wire to its corresponding phantom array, which // acts as a buffer for wire value to the wire phantom. // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. BOOLEAN nιulti_temporal::make_normal_to_phantom.arr_copy(int i) { int level; // ϊnt from.wire.level; ϊnstance*inst; int wire; ϊnt wire.index; int index; inl to.ptr.index; instance*to_ptr_ϊnstance; string* name; string* ptr.name; instance *inst_ptr; BOOLEANstatus = TRUE; inst = this_zone->pending_instance(i); wire = this.zone->pending_wire(i); // get level for last phantom for this wire index = inst->ge tjast.phan torn (wire , &level); // we actually want previous wire level, which is for prev. segment level--; index = inst->get_phantom(wire , level); // synthesize name of "to" array ptr by getting name of phantom wire name = inst->prototype()->storage.name_at_index(index); // prepend a special prefix to create name for "to" array pointer ptr.name = new string(TO_ARRAY_PTR_STR); *ptr_name = *ptr_name + *name; if (!inst->find_wire_name(ptr_name, &to_ptr_index, &to_ptr .instance)) { this_inst->out_error("ZON065", cerr, FALSE); cerr « "Unable to find the 'to' array pointer '" « *ptr_name « '"Λn"; return FALSE;} // now set I/O for source of copy, which is previous phantom wire // get previous phantom level for wire, which is one before current // get wire index for original wire wirejndex = inst- >get_phantom (wire , 0); // create array of I O wire indices // which is same wire, but different phantom levels, as set below int ios[2]; ios[0] = to.ptr.index; ios[l] = wirejndex; // create array of VO wire instance pointers instance* io_insts[2]; io_insts[0] = to.ptr.instance; io_insts[l] = inst; if (!nιake_phantom_inst_with_args(TO_PHANT_ARR_STR, 2, ios, io.insts, 0, (expr**) NULL, &inst_ptr)) return FALSE; // set phantom level for "from" wires M-637 ϊnst_ptr->set_phantom_io_level(l, level); return TRUE;} iiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiiiiiiiiiiffiiiifiriiiiiiriiiiimimiiiniiiii // make_downsample.from_phantom_arr_copy // Make a downsampled "from_phant_aπr" block // This block copies from a wire to its corresponding phantom array, which // acts as a buffer for wire value to the wire phantom. // It downsamples from the block rate to the lower rate in the // next time zone. // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiiiiniiiiiiiniiiiimiriiiiiiiiiiiii BOOLEAN multi_temporal::make_downsample_from.phantom_arr.copy(int i, zone* before.zone, zone* after.zone)! int level; ϊnstance*inst; int wire; ϊnt index; int array.ϊndex; int fr.ptr.index; instance*fr_ptr.instance; string* name; string* ptr.name; instance*inst_pιr; BOOLEANstatus = TRUE; long decim.factor; long before.segment.repeats; long after.segment.repeats; zone* wire . zone; NOREF(before.zone); ffifdef DEBUG string* hier.name; hier.name = this_inst->hier_name_stringO; cerr « "making downsample from phantom arr copy in " « *hier.name « "\n"; #endif inst = thϊs_zone->pendϊng_instance(i); wire = this_zone->pending_wire(i); wire.zone = inst-> et_zone_for_wire wire ; // get zone repeat counts to compute downsampling factor before.segment.repeats = wire_zone->get epeat.count(); after.segment.repeats = after_zone->get_repeat_count(); decim . f actor = before.segmentjrepeats/after.segmen t.repeats; if ( ((before.segment.repeats % after.segment.repeats) != 0) II (decim.factor <= 1) ){ this_inst->out_error("ZON071", cerr, FALSE); cerr « "Illegal downsampling rates: " « before.segment.repeats « " downsampled to " « after.segment.repeats « '"Λn"; return FALSE;} // get level for last phantom for this wire index = inst-r>get_last_phan torn (wire , &level); // synthesize name of "from" array ptr by getting name of phantom wire // get level for last phantom for the corresponding array if (ileve l_forJatest_array(i, &level)) return FALSE; array.index = inst->get_phantom(wire, level); name = inst->prototype()->storage_name_at_index(array_index); // prepend a special prefix to create name for "from" array pointer ptr.name = new string (FR.ARRAY_PTR.STR); *ptr_name = *ptr_name + *name; if (!inst->find_wire_name(ptr_name, &fr_ptr_index, &fr_ptr_instance)){ this_inst->out_error("ZON072", cerr, FALSE); cerr « "Unable to find the 'from' array pointer '" « *ptr_name « '"Λn"; return FALSE;} // create array of VO wire indices int ios[2]; ios[0] = fr.ptr.index; ios[l] = index; // create array of I/O wire instance pointers instance* io_insts[2]; io.insts [0] = fr.ptr .instance; io_insts[l] = inst; // create array of parameter expressions expr* param.vals[l]; param_vals[0] = new expr(decim.factor); if (imake.phantom _inst_with_args(DOWN_FR_PH_ARR_STR, 2, ios, -639 io.insts, 1, param.vals, &inst_ptr)) return FALSE; return TRUE;} mimHuuiimiiiiinimuiiiiiimimmimmimtMiimmimimi II make.normal.from.phantom.arr.copy // Make a normal "from.phant.arr" block // This block copies from a phantom array to its corresponding wire. // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. BOOLEAN multi jemporal::make_normal_from_phantom_arr_copy(int i) ! int level; instance*ϊnst; int wire; int index; int array.index; int fr.ptr.index; instance*fr_ptr_instance; string* name; string* ptr.name; instance*inst_ptr; BOOLEANstatus = TRUE; inst = this_zone->pendingJnstance(i); wire = this_zone->pending.wire(i); // get level for last phantom for this wire index = inst->get_last_phantom (wire , &level); // synthesize name of 'Trom" array ptr by getting name of phantom wire // get level for last phantom for the corresponding array if (!level_forJatest_array(i, &level» return FALSE; array Jndex = ϊnst->get_phantom(wire, level); name = inst->prototype()->storage_name_at_index(array_index); // prepend a special prefix to create name for "from" array pointer ptr.name = new string(FR_ARRAY_PTR_STR); *ptr_name = *pιr_name + *name; if (!inst->find_wire_name(ptr_name, &fr_ptr_ϊndex, &fr_ptrjnstance)) { thϊs_ϊnst->out_error("ZON066", cerr, FALSE); cerr « "Unable to find the 'from' array pointer '" « *ptr_name « '"Λn"; M-640 return FALSE; } // now set VO for dest of copy, which is last phantom wire // create array of VO wire indices int ios[2]; ios[0] = fr.ptr.index; ios[l] = index; // create array of I/O wire instance pointers instance* io_insts[2]; io_insts[0] = fr.ptr Jnstance; io_insts[l] = inst; if (!nιake_phantonι_inst_with_args(FR_PHANT_ARR_STR, 2, ios, io.insts, 0, (expr**) NULL, &ins t . ptr)) return FALSE; return TRUE;} // make.upsample.from.phantom.arr.copy // Make an upsampled "from_phant_arr" block // This block copies from a phantom array to its corresponding wire. // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. BOOLEAN multi _temporal::make_upsample_from_phantom.arr_coρy(int i, zone* before.zone, zone* after.zone)! int level; instance*inst; int wire; int index; int array Jndex; int fr.ptr.index; instance*fr_ptr.instance; string* name; string* ptr.name; instance*inst_ptr; BOOLEANstatus = TRUE; long interp.factor; long before.segment.repeats; long after.segment.repeats; zone* wire . zone; 41 NOREF(before.zone); inst = thϊs_zone->pending_instance(i); wire = this_zone->pending_wire(i); wire.zone = inst->get_zone_for_wire(wire); // get zone repeat counts to compute upsampling factor before.segment.repeats = wire_zone->ge t.repeat.countO; after.segment.repeats = after_zone->get_repeat_count(); ϊnterp.factor = after.segment.repeats/before.segment.repeats; if ( ((after.segment.repeats % before.segment.repeats) != 0) II (interp.factor <= 1) ){ this_inst->out_error("ZON073", cerr, FALSE); cerr « 'Illegal upsampling rates: " « before.segment.repeats « " upsampled to " « after.segment.repeats « '"Λn"; return FALSE;} // get level for last phantom for this wire index = ϊnst->ge tjast.phantom (wire , &level); // synthesize name of "from" array ptr by getting name of phantom wire // get level for last phantom for the corresponding array if (!Ievel_for_latest_array(i, &level)) return FALSE; arrayjndex = inst->get_phantom(wire, level); name = inst->prototype()->storage_name.at_index(array_index); // prepend a special prefix to create name for "from" array pointer ptr.name = new stting( _A_RRAY_PTR_STR); *pιr.name = *ptr_name + *name; if (!ϊnst->find_wire_name(ptr_name, &fr.ptr_index, &fr_ptr_instance)){ thϊsJnst->out_error("ZON074", cerr, FALSE); cerr « "Unable to find the 'from' array pointer '" « *ptr.name « '".\n"; return FALSE;} // create array of VO wire indices intϊos[2]; ios[0] = fr.ptr.index; ϊos[l] = index; // create array of VO wire instance pointers instance* io_insts[2]; M-642 io_insts[0] = fr.ptr.instance; io_insts[l] = inst; // create array of parameter expressions expr* param_vals[l]; param_vals[0] = new expr (interp.f actor); if (!make_phantom_inst_with_args(UP_FR_PH_ARR_STR, 2, ios, io.insts, 1, param.vals, &inst_ptr)) return FALSE; return TRUE;} II makejo_phant.arr_ptr.resets // Make a "to phantom arr ptr reset" block for each pending input which has // one specified in the "bottom.of.last.copy" array. // This block initializes the pointer to be used for "to phantom array copies". // The init block is inserted at the previous segment. // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. /////////////////////////////////////////////////////////////////////////////// BOOLEAN multi_tenιporal::make_to_phant_arr_ptr_resets( int.array* bottom.of.last . copy)! int i; int copy.status; int status = TRUE; for (i=0; i<this.zone->pending_size(); i++){ copy.status = (*bottom_of_las t_copy)[i]; switch (copy.status) { case NORMAL.COPY.TO.ARRAY: status = makejo.phan t_arr_ptr_reset(i); break; default: break; } if (Istatus) break; } return status;} II njo.phant.arr.ptr.resets // Return the number of "to phantom arr ptr reset" block cycles required. SUBSTITUTE HEE //Returns FALSE if failed. miiiinuinimiimmmimimummmimuiiiiiiMiiitimmimi BOOLEAN multi emporaI::n_to_phant_arr_ptr_resets( int.array* bottom.of.last.copy, int *n.cycles_ptr)! int i; int copy.status; ϊnt status = TRUE; static int to.phant.arr.reset.cycles = UNKNOWN.DURAHON; ϊnt n.cycles = 0; // if we don't have # of cycles for blocks, look them up if (to_phant_arr_reset_cycles = UNKNOWN.DURATION) if ((to_phant_arr_reset_cycles - get_block_duration(LNlT_ARR_PTR_STR)) = UNKNOWN.DURATION) return FALSE; for (i=0; i<thϊs_zone->pending_size(); i++)! copy.status = (*bottom_of_las t_copy)[i]; switch (copy_status) { case NORMAL.COPY.TO.ARRAY: n.cycles += to.phan t.arr.rese t_cycles; break; default: break; } if (Istatus) break;} *n_cycles_ptr = n.cycles; return status;} II make.to.phant.arr.ptr.reset // Make a "to phantom arr ptr reset" block. // This block initializes the pointer to be used for "to phantom array copies". // The init block is inserted at the previous segment // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. BOOLEAN multi.temporal::make_to_phant_arr_ptr.reset(int i) ! instance*ϊnst; int wire; int level; string* name; string* ptr.name; instance * wire.instance ; int wirejndex; int index; string* arr.name; int arr.size; instance*arr_instance; int arr Jndex; instance*inser t.instance;// parent instance in which to insert int insert . index;// index in parent for insert instance*current_instance; zone* wire.zone; instance*child_inst; int place; int status = TRUE; inst = this_zone->pending_instance(i); wire = this_zone->pending_wire(i); // get zone for this wire wire.zone = inst->get_zone_for_wire(wire); // repeat count for this zone gives us the array size arr_size = (int) wire_zone->get.repeat_count(); // get level for last phantom for this wire index = inst->getjast_phan torn (wire , &level); // we actually want previous wire level, which is for prev. segment level--; index = inst->get_phantom(wire , level); // synthesize name of "to" array ptr by getting name of phantom wire name = inst->prototype()->storage_name_at_index(index); // prepend a special prefix to create name for "to" array pointer ptr.name = new string(TO_ARRAY_PTR_STR); *ptr.name = *ptr_name + *name; // need to get instance of wire (child if parent instance) // so we can find name of array in parent child.inst = inst->get_child(wire); if (!child_inst->find_wire_name(ptr_name, &wire_index, &wire_instance)) { this_inst->out_error("ZON063", cerr, FALSE); cerr « "Unable to find the 'to' array pointer '" M-645 « *ptr_name « '".\n"; return FALSE;} // make name for array arr.name = new strϊng(ARRAY_PREFIX_STR); *arr_name = *arr_name + *name; // get index and parent instance for array if (!child_ϊnst->find_wire_name(arr_name, &arr_index, &arr_instance))! this_inst->out_error("ZON064", cerr, FALSE); cerr « "Unable to find the array "' « *arr_name « '".\n"; return FALSE;} insert.instance = get_segment_boundary(&insert_index); // replace current instance context by context for prev segment boundary curren t . ϊnstance — thisjnst; this nst = insert.instance; place = insert.index - 1; // get the child instance index of this position in the sequence int child.index = this_inst->get_par t_sequence(place); //reattach any label attached to this position to the instance index // of the new block we are about the create this_inst->reattach_phantom_labels(chϊld_index,this_inst->get_n_chϊldren()); // insert a "inϊt.arr.ptr" block in this spot status = make.ϊnϊt_arr_ptr_block(arr.size, arr.index, arr Jnstance, wire.index, wire.instance, place); // restore instance context thisjnst = current Jnstance; return status;} II make.fr.phant.arr.ptrjresets // Make a "from phantom arr ptr reset" block for each pending input which has // one specified in the "top_of.next.copy" array. // This block initializes the pointer to be used for "from phantom array // copies". // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. BOOLEAN multijemporal::make_fr_phant.arr_ptr_resets( int.array* top.of.next.copy)! ϊnt ϊ; M-646 int copy.status; int status = TRUE; for (i=0; i<this_zone->pending_size(); i++){ copy.status = (*top_of_next_copy)[i]; switch (copy.status) { case NORMAL . COPY . FROM . ARRAY: case UPSAMPLE . COPY . FROM . ARRAY: case DOWNSAMPLE.COPY.FROM . ARRAY: status = make_fr_phant_arr_ptr_reset(i); break; default: break; } if (istatus) break; } return status;} /////////////////////////////////////////////////////////////////////////////// // n.fr.phant.arr.ptr.resets // Return the number of "from phantom arr ptr reset" block cycles required. // Returns FALSE if failed. BOOLEAN multi_temporal::n_fr_phant_arr_ptr_resets( int.array* top.of.next.copy, int *n_cycles_ptr){ int i; int copy.status; int status = TRUE; static int fr.phant.arr.reset . cycles = UNKNOWN . DURATION; int n . cycles = 0; // if we don't have # of cycles for blocks, look them up if (fr_phant_arr_reset_cycles == UNKNOWN.DURATION) if ((fr.phant.arr.reset.cycles = get_block_duration(INIT_ARR_PTR_STR)) == UNKNOWN.DURATION) return FALSE; for (i=0; i<this_zone->pending_size(); i++){ copy.status = (*top_of_next_copy)!i]; switch (copy.status) { case NORMAL.COPY.FROM.ARRAY: -647 case UPSAMPLE.COPY.FROM.ARRAY: case DOWNSAMPLE.COPY.FROM.ARRAY: n.cycles += fr.phant.arr.reset.cycles; break; default: break; } if (Istatus) break;} *n_cycles.ptr = n.cycles; return status;} II make.fr . phant.arr.ptr.reset // Make a "from phantom arr ptr reset" block. // This block initializes the pointer to be used for "from phantom array // copies". // Called after phantom wires and phantom arrays have been created. // Returns FALSE if failed. BOOLEAN multi_temporal::make_fr_phant_arr_ptr_reset(int i) { instance*inst; ϊnt wire; ϊnt level; string* name; string* ptr.name; instance*wϊre_instance; int wire.index; int index; string* arr.name; int arr.size; instance*arr_instance; int arrjndex; zone* wire.zone; instance*child_inst; int status = TRUE; inst = thϊs_zone->pending_instance(i); wire = this_zone->pending_wire(i); // get zone for this wire wire.zone = inst->get.zone_for_wire(wire); M-648 // repeat count for this zone gives us the array size arr.size = (int) wire_zone->get.repeat_count(); // get level for last phantom for the corresponding array if (!level_for_latest_array(i, &level)) ' return FALSE; index = inst->ge t_phantom(wire, level); // synthesize name of "from" array ptr by getting name of phantom wire name = inst->prototype()->storage_name_a t.index(index); // prepend a special prefix to create name for "from" array pointer ptr . name = new string(FR_ARRAY_PTR_STR); *ρtr_name = *ptr_name + *name; // need to get instance of wire (child if parent instance) // so we can find name of array in parent child Jnst = inst->get_child(wire); if (!child_inst->find_wire_name(ptr_name, &wire Jndex, &wire_instance))! this_inst->out_error("ZON069", cerr, FALSE); cerr « "Unable to find the 'from' array pointer '" « *ptr_name « '"Λn"; return FALSE; } // make name for array arr.name = new strin ( ARR AY.PREFIX.STR); *arr_name = *arr_name + *name; // get index and parent instance for array if (!child_inst->find_wire_name(arr_name, &arr_index, &arr_instance)){ this_inst->out_error("ZON070", cerr, FALSE); cerr « "Unable to find the array '" « *arr_name « '"Λn"; return FALSE; } // insert a "init.arr.ptr" block status = make.init_arr_ptr_block(arr_size, arr.index, arr.instance, wirejndex, wire Jnstance); return status;} II level.forjates t.array // The latest array may not be at the same level as its latest wire, so // this function returns the level for the latest array for a given // pending input i. // Returns FALSE if failed. 99 k -649 πiiiiiiHiiiπiimimπiimiiiimmπiiiminiπiiuniiiiiiiππiiiii BOOLEANmultijemporal::level_for_latest_array(inti, int* level.ptr)! BOOLEANfound; instance*arr_instance; int arr.index; string* arr.name; instance*inst; ϊnt wire; int level; string* name; int index; instance*child.inst; found = FALSE; arrjiame = new stringC'"); // get the instance and wire for this pending wire inst = thϊs_zone->pending_instance(i); wire = this_zone->pending_wire(i); // get level for last phantom for this wire index = inst->get_last_phantom(wire, &level); // need to get instance of wire (child if parent instance) // so we can find name of array in parent child jnst = inst->get.child(wire); // find the last phantom array available for this wire do! index = inst->get_phantom(wire, level); // synthesize name of "from" array ptr by getting name of phantom wire name = inst->prototype()->storage_name_at_index(index); // make name for array *arr_name = ARRAY.PREFTX.STR; *arr_name = *arr_name + *name; // see if this array exists if (chϊld_mst->find_wire_name(arr.name, &arr_index, &arr_instance)) found = TRUE; else level—;} while ((Ifound) && level >= 0); delete arr.name; if (found)! M-650 *level_ptr = level; return TRUE;} else! this_inst->out_error("ZON080", cerr, FALSE); cerr « "Unable to find the array '" « *arr_name « '".\n"; return FALSE; } } II level.for.previous.array // The previous level array may not be at the same level as its wire, so II this function returns the level for the previous level array for a given // pending input i. // Returns FALSE if failed. BOOLEANmulti_temporal::level_for_previous_array(int i, int level, int* leve ptr)! BOOLEANfound; instance *arr_instance ; int arr.index; string* arr.name; instance*inst; int wire; string* name; int index; instance*child_inst; found = FALSE; arr.name = new stringC'"); // get the instance and wire for this pending wire inst = this_zone->pending_instance(i); wire = this_zone->pending_wire(i); // need to get instance of wire (child if parent instance) // so we can find name of array in parent child Jnst = inst->get_child(wire); // use previous level level--; // find the last phantom array available for this wire do{ index = inst->get_phantom(wire, level); M-651 // synthesize name of "from" array ptr by getting name of phantom wire name = st->prototype()->storage_name.atJndex(index); // make name for array *arr_name = ARRAY . PREFLX.STR; *arr.name = *arr.name + *name; // see if this array exists if (child_ϊnst->find_wϊre_name(arr_name, &arr Jndex, &arr_instance)) found = TRUE; else level--;} while ((Ifound) && level >= 0); delete arr.name; if (found)! *level_ptr = level; return TRUE;} else! thϊs_inst->ou t_errorC'ZON081", cerr, FALSE); cerr « "Unable to find the array "' « *arr_name « '"Λn"; return FALSE; }} II makejoop op // Create the loop top label and insert it for the current repeated code //portion. // Returns FALSE if failed. BOOLEAN multi_temporal::make_loop_topO { string* local.label.name;// local (non-hierarchical) loop label name int index; static ϊnti=0; // create the label for the top of repeat loop local.label.name = new string(LOOP_RPT_STR); *local_labeI_name = *local.label_name + this_zone->get_zone.chars() + ϊnt_to_c_sιrϊng(i); i++; // tie it to the next child instance if (!ιhis_inst->add.phantomJabel_name(local_label_name, this nst->get ji.childrenO)) { M-652 this_inst->out_error("ZON032", cerr, TRUE); cerr « "The phantom label '" « *loop_label_name « '" already exist!\n"; return FALSE; } if (!make_phantom_inst_with_args("_dummy", 0, (int*) NULL, (instance**) NULL, 0, (expr**) NULL)) return FALSE; // insert a make probe reset block at the top of every loop if (!make_pr_reset_block()) return FALSE; // now need to save global (hierarchical) name for label so we can reference // it from anywhere // loop up its index if (!this_inst->prototype()->label_name_to_index(local Jabel.name, &index)) ! this_inst->out_error("ZON075", cerr, TRUE); cerr « "Could not find newly added label '" « *local Jabel . name « "'!\n"; return FALSE; } // and derive full name from this loop.label.name = this Jnst- >prototype ()->hier_label_nanιe_a t.index(index) ; return TRUE;} II make . loop.bottom // Make a block for the bottom of the current repeated code portion. // Returns FALSE if failed. BOOLEAN multi_temporal::make_loop_bottonι(zone* loop.zone) { long segment.repeats; segment.repeats = loop_zone->get_repeat_count(); // only make loop if segment repeats itself if (segment.repeats > 1){ // create array of VO wire indices int ios[l]; ios[0] = loop.counter.index; / only I/O is current loop counter // create array of I/O wire instance pointers instance* io.insts! 1]; io_insts[0] = loop.counter.instance; // create array of parameter expressions M-653 expr* param_vals[l]; param_vals[0] = new expr(loop Jabel.name);// set label name as param #ifdef DEBUG cerr « "inserting loop bottom for counter " « *Ias t.loop . counter.name «"\n"; #endϊf return make_phantom_inst_with_args(LOOPJBOTTOM_STR, 1, ios, io.insts, 1, param.vals);} else return TRUE;} II save.segmen t.boundary // Save latest segment boundary for possible later pointer initialization. void multijemporal: :save_segment.boundary(instance* inst, int index)! seg_bound_ϊnst = inst; seg_bound_ind = index;} II get.segment.boundary instance* muIti_temporal::get_segment_boundary(int* index.ptr)! *index_ptr = seg.bound.ind; return seg_bound_inst;} II out.sample.period.msg // Output a msg giving the cycles in one or more sample periods. // Overloaded from temporal class to output cycles in N sample periods // for decimation/interpolation. void muIti_temporal::out.sample_period_msg(ostream& out)! if (this_zone->get_repeat_count() > 1){ out « this_zone->get_repea t_count() « " sample periods for a decimation loop provide " « this_zone->max.cycles() « " cycles";} else{ out « "One sample period provides " « this_zone->max_cyclesO « " cycles"; -654 } } II add . block.duration // Evaluate and add the new block's duration to the zone. // Overloaded from base class, this checks for possible requirement for // poll block. // Returns FALSE if failed. BOOLEAN multi_temporal::add_block_duration(string* prototype.name, instance*& inst . ptr)! BOOLEANstatus = TRUE; instance*current_inst; int duration; BOOLEANsample.rate . ok = FALSE; // evaluate contents so block duration will get filled in if (inst_ptr->compute_contents()) { this_inst->out_error("ZON905", cerr, FALSE); cerr « "INTERNAL ERROR - Phantom block '" « *prototype_name « '" doesn't have valid contentsΛn"; status = FALSE; } // add this block's duration to the zone // save our current instance and set the pass-in instance currentjnst = thisjnst; thisjnst = inst.ptr; if (!add_this_block.duration(&duration)) { // could not add the block, but before we declare an error, see if // we merely have to add a poll block // first call to check for new segment required if (!test_block_duration(duration) II this_zone->boundary_forced()) // new segment, so its a vahd error else if (poll_block_required(duration)) { //just need to add poll block thisjnst = currentjnst; status = add_poll_block(); thisjnst = inst.ptr; M-655 if (status) status = add_this_block_duratϊon(&duration); sample.rate.ok = TRUE; } • if (isample.rate.ok) { this_ϊnst->out_error("ZON053", cerr, FALSE); cerr « "The sample rate is too high, with only " « this_zone->max_cycles() « " cycles in a sample « "Could not add a required phantom block (" « *prototype_name « ").\n"; status = FALSE; }} // restore our instance this.inst = currentjnst; return status;} // zone2.cxx // functions for zone class II T. Montlick // 1/29/90 // source code control: static char SccsLDQ = "@(#)zone2b.cxxl.56 10/7/91"; #ifndef ZONE_DEF #include "zone.hxx" #endif // zone.schedule class II zone_schedule::zone_schedule // Constructor. zone_scheduIe::zone_schedule() ! master.zone = (zone*) NULL; n.zones = 0;} II zone_schedule::~zone_schedule //Destructor. M-656 zone.schedule: :~zone_schedule() { } II find.connected.zones // Starting from the master zone, which must have been set, find all connecting // zones and record their zone pointers. void zone_schedule::find_connected_zones(){ zone* z: zone* z.next; int i, j; if (master_zone != NULL){ zone_ptrs[0] = master_zone; n.zones = 1; for (i=0; i<n.zones; i++) { z = zone_ptrs[i]; for (j=0; j<z->n_next.zones(); j++) { z.next = z->next_zone(j); // if next zone not aheady present, add it if (zone.ptrs.find(z.next) < 0) { zone.ptrs [n.zones] = z.next; n_zones++; } } } } } II compute.sample.periods //Based on the relative sample rates, compute relative sample periods. void zone.schedule ::compute_sample_periods(){ M-657 for (ϊ=0; i<n_zones; i++){ z = zone_ptrs[ιj; // get relative sample period w/respect to original sample period z->original_zone(&rel_period) ; // if rel period is < 1, then we must increase base period if (rel.period < 1.0) { rel.base = round(base_period / rel.period); base.period = base.period * rel.base; // go back and adjust previous periods by new base for (j=0;j<i;j++) periods [j] = periodsOl * rel.base; } // Set this zone's period, adjusted by base // (make sure to round off is upward to the next integer, // since PC doesn't always do multiplication acurately). periods[i] =round(rel.period * base.period); } } II set.scheduler.connects // Tell the scheduler about all our zone's connections. iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiini BOOLEAN zone_schedule::set_scheduler_connections() { zone* z; zone* z.next; int i,j; for (i=0; ϊ<n_zones; i++)! z = zone_ptrs[ιJ; for 0=0; j<z->n_next_zones(); j++) { z.next = z->next_zone(j); // get task number from zone pointer and add connection if (!the_scheduler.add_connecύon(ϊ, zone_ptrs.find(z_next))) { out.err.headerC'ZSCOOl"); cerr « "Zone " « *z->get_zone_name0 « " and zone " « *z_next->get_zone_name() « " have incompatible ratesΛn"; return FALSE; M-658 } } } return TRUE;} II compute_schedule // This function is passed the master zone in an interconnected set if // decimated/interpolated zones. It finds these connecting zones and, // based on their sample rates, computes the temporal partitioning // schedule for them, which is the number of times each should be fired. BOOLEAN zone_schedule::compute_schedule(zone* first.zone){ #define MINESCULE.DURATION0.000001 int i; // record the master zone for scheduling master.zone = firs t.zone; // find all the sub-zones derived from this master zone find_connected_zones(); // compute the relative sample period for each zone compute.sample.periodsO; // set 0 headroom in the scheduler to force temporal partitioning the.scheduler.set.headroom(O.O); // add sample periods, giving an insignificant duration since in // pure temporal partitioning we don't need to determine gsp // boundaries for (i=0; i<n.zones; i++) the_scheduler.add_sample_period_and_duration(periods[i], MINESCULE.DURATION); // pass the scheduler info on which zone connects to which if (iset.scheduler.connectionsO) return FALSE; // finally, compute the scheduler periods the.scheduler.compute.periodsO; return TRUE;} // zones class II zones::zones // Constructor. zones::zones(M M-659 gpio_reg_value = 0; first.sub.zone = 0;} u uimu u muiimiuπiπi iiiiπiiiiπiiii uiii tmiiui II zones: :~zones // Destructor. muiiMUumumimimmiiuπumuππiumiiiMiiiiiiiiimmii zones::~zones() {} uninmumiu i iiuuuuuuuiuuuuiu uii uuuiUHiiii II add.new.zone // Add a ' new time zone with the given name. zone* zones: :add_new.zone(string* name, BOOLEAN make_sub_zone)! ϊnt i; i = n Jncluding_sub_zones(); if (make.sub.zone) timezones[i] = new sub_zone(i, this); else timezones[i] =new zone(i, this); timezones[iJ->set_zone_name(name); // if not a sub-zone (added at end), then set this # as less // than 1st sub-zone # if (Imake.sub.zone) first.sub.zone = i+1; return tϊmezones[ϊ];} II create.and.partϊtion.zones //Find time zones and do temporal partitioning. // If no errors, returns 0. // If error, returns a value of ERROR.STATUS. // If no inputs for partitioning, returns a value of NO . INPUTS. int zones::create_and_partitϊon_zones(int* n.zones.ptr, int.array* n_gspn_ptr, double* exact_gsps_ptr){ int status; if (status = create ime_zones(n_zones_ptr)) return status; if (status = compute.zone.scheduler.repeatsO) return status; M-660 if (status = partition_created_time_zones(n_gspn_ptr, exact_gsps_ptr)) return status; if (status = initialize_port_registers()) return status; return 0; } // compute.zone.scheduler . repeats // For each master zone (zone with derived interpolated or decimated sub-zones) // run the scheduler to determine the number of temporal partitioning repeats // for the zone. // If no errors, returns 0. int zones: :compute_zone_scheduler_repeats() { int i,j; int n.zones; zone*zone_ptr; long firings; // scan all master zones for (i=0; i<timezones.size(); i++){ if (timezones[i]->is_master_zone()) { // create a temporary zone.schedule object to compute the // temporal partitioning schedule zone.schedulethe.z.sched; the_z_sched.compute_schedule(timezones[i]); n.zones = the_z_sched.get_n_zones(); for (j=0; j<n_zones; j++) { // get # of zone firings in schedule and set in each zone firings = the_z_sched.get_task_firings_and_zone(j , &zone_ptr) ; zone.ptr- >set_repeat_count(firings); // adjust cycles for zone segment by repeat count zone_ptr->set_max_cycles( firings * zone.ptr- >max.cycles() ); } }} return 0;} II create.time.zones SUBSTITUTE SHEET M-661 // Find and create all time zones (including decimated and interpolated), but // don't do any temporal partitioning. II If no errors, returns 0. // If error, returns a value of ERROR.STATUS. // If no inputs for partitioning, returns a value of NO.INPUTS. ϊnt zones::create_time_zones(int* n.zones.ptr)! int ϊ; int status = 0; int n.ϊnputs = 0; // create the initial (non-decimated or interpolated) time zones if (!identϊfy_zones(user_top_instance, &n_inputs)) return ERROR.STATUS; // Evaluate input info for each zone. // This includes determining the sample rate for each input zone, which is // required to compute rates for any decimated or interpolated zones, for (ϊ=0; i<n_zones(); i++){ if (status = timezones[i]->process_zone_inputs()) return status;} // label wires with these zones // (this function also generates decimated/interpolated sub-zones) if ( !user_top_instance->set_wire_zonesO) return ERROR.STATUS; // label instances connected to the wires // (this function also collapses supposedly ordinary but non-triggered // zones with decimated/interpolated sub-zones) if(!user.top_mstance->set_mstance_zones(NO_TIME_ZONE)) return ERROR.STATUS; // scan for leftover non-triggered zones for (i=0; ϊ<n_zones(); i++){ if ( timezones[i]->zone_maskO = 0L && !timezones[i]->is_user_triggered() ) { user_top_instance->out_error("ZON012", cerr, FALSE); cerr « "No trigger source for timezone '" « *get_zone_name(i) « '".\n"; status = ERROR.STATUS; return status: M-662 } // also check for rate never set if ( timezones[i]->get_zone_rate() == 0.0 ) { user_top_instance->out_error("ZON088", cerr, FALSE); cerr « "You never specified a rate for timezone '" « *get_zone_name(i) « '"Λn"; status = ERROR.STATUS; return status; } } // Evaluate output info for each zone. We must do this after zones // have been labeled for outputs or we don't know which output belongs // to which zone. // Make sure to include sub-zones, because outputs may be in these // rather than original zones derived from inputs for (i=0; i<n_including_sub_zones(); i++){ if (status = timezones[ij->process_zone_outputs()) return status;} // return the final number of time zones *n_zones_ptr = n_zones(); return 0; } II partition.created jime.zones // Do temporal partitioning. // Called after time zones have been created. // If no errors, returns 0. // If error, returns a value of ERROR.STATUS. // If no inputs for partitioning, returns a value of NO.INPUTS. int zones::partition_created_time_zones(in t.array* n_gspn_ptr, double* exact_gsps_ptr){ int i; int status = 0; for (i=0; i<n_zones(); i++){ if (timezones[i]->do_temporal_partition()) return ERROR.STATUS; else (*n_gspn_ptr)[i] = timezones[i]->get_gsp_count(&exact_gsps_ptr[i]); } SUBSTITUTE SHEET M-663 if (n_zones() > 0){ if (!make_probe_fifo()) return ERROR.STATUS; if (!init_idle_gspsO) return ERROR . STATUS; } return 0;} II make.probe.fifo // Create the fifo for the probing D/A converter. BOOLEAN zones::make_probe_fifo()! string* name; BOOLEANstatus = TRUE; // fifo depth is max of zone repeat counts for (i=0; ϊ<timezones.sϊze(); i-H-){ temp = timezones[i]->get_repeat_count(); if (temp > depth) depth = temp;} // make a size expression for the fifo, including fudge factor fifo.size = compute_probe_fifo_size(PROBE_FIFO_BUF_LEN*depth); fifo.size.expr = new expr(fifo_sϊze); // get ptr to our child, which is the user's top level block this.inst = top_instance->get.child(users_top_block_index); // add this fifo to our instance status = this_inst->add_phantom_storage_name(name, fifo.size . expr, &fifo_wire, * f * ); if (Istatus)! -664 this_inst->out_error("ZON050", cerr, FALSE); cerr « "Tried to create a second fifo named '" « *name « "'!\n"; } // also add fifo size as symbol proto.ptr = this_inst->prototype(); name = new string(PROBE_FIFO_LEN_STR); if (status) status = proto.ptr- >add_symbol_name(name, &dummy); fifo.size.expr = new expr((long) fifo.size); if (status) status = proto_ptr->add_expression_name(name, fifo.size.expr); if (!status){ this_inst->out_error("ZON051", cerr, FALSE); cerr « "Tried to create a second fifo size named '" « *name « "'!\n";} return status;} II compute.fifo.size // Compute fifo size from depth. long compute_fifo_size(long depth)! // fifo size is 2X depth (no fudge factor required for ordinary fifo) return (depth*2); } II compute.probe.fifo.size // Compute probe fifo size from depth. long compute_probe_fifo_size(long depth)! // fifo size is 2X depth, plus Keith's fudge factor return (depth*2 + FIFO_SIZE_FUDGE); } II init_idle_gsps // Set the unused gsps to just loop. BOOLEAN zones: :init_idle_gsps(){ int i; string* label; instance* child; BOOLEAN status = TRUE; SUBSTITUTE SHEET M-665 instance* thisjnst; string* flag_string = new stringC") ; // push top instance context on stack top_ϊnstance->push.context() ; // get ptr to our child, which is the user's top level block thisjnst = top_instance->get_child(users_top_block_index); // save current block context and set instance info in block this_ϊnst->push_context(); // create a temporal object for this instance and zone temporal this jemporal(timezones[0], this.inst, flag_string); // generate benign code for the rest of the GSPs for (i=gsp_allocator->curren t_gsp(); i<=n_gsps; i++){ //create the label label = new string(GSP_START_STR); *label = *label + int_to_c_string(i); // attach label to next instance in sequence if (!this_ϊnst->add_phantom_label_name(label, this_inst->get_n_childrenO)) { this_inst->out_error("ZON035", cerr, TRUE); cerr « "Phantom label '" « *label « '" already exist!\n"; status = FALSE; break; } // create the code, which is just a jump to oneself if ( !this_temporaI.makeJumρ_block(label)) { status = FALSE; break; } // set block as an init block child = tMs_mst->get_chUd(thϊs_iπst->ge t.n.childrenO-1); chϊld->set_init();} //restore previous block context this_inst->pop_context() ; return status;} II ϊnitialize.port.registers M-666 // Called after time zones have been created and fifos info has been // initialized. // If no errors, returns 0. // If error, returns a value of ERROR.STATUS. // If no inputs for partitioning, returns a value of NO.INPUTS. int zones::initialize_port_registers() { int i; expr* value.expr; string* name; for (i=0; i<n_including_sub_zones(); i++){ // create initialization for ports if (!timezones[i]->init_port_registers()) return ERROR.STATUS;} // set the initial value for gpio register which has been accumulated // in this class' gpio_reg_value variable value.expr = new expr(gpio_reg_value); name = new string(GPIO_REGISTER); if (n_including_sub_zones() > 0) // make sure we have at least 1 zone!{ if (!timezones[0]->init_hardware_register(name, value . expr)) return ERROR.STATUS;} return 0;} II initialize.all.fifo.info // Called if not automatically partitioned, this routine initializes // all fifo info for the zone. // If no errors, returns 0. int zones::initialize_all_fifo JnfoO { int i; zone* the.zone; string* flag_string = new stringC"'); for (i=0; i<n_including_sub_zones(); i++){ the.zone = timezonesp]; // create a temporal object to handle fifo initialization { temporal the.temporal(the_zone, user.top.instance, flag_string); if ( !the_temporal.add_input_fifo_info( 1 )) return ERROR.STATUS; -667 if (Ithejemporal.add.output.fifo.infoO) return ERROR.STATUS; } } return 0;} //identify.zones // Find the input blocks to the design, and allocate a timezone for // each unique zone name. Also mark the zone in the input block // instance. // The function will also create sub-zones for interpolated/decimated blocks. // Called with a pointer to the top instance, it recursively calls itself. //If no errors, returns TRUE. BOOLEAN zones: :identify_zones(insfance* this.inst, int* n.ptr)! BOOLEANstatus = TRUE; expr* name.expr; expr* rate.expr; string* name; zone* zone.ptr; int i; ϊnt which.child; ϊnstance*child; block* our.proto; // save current block context and set instance info in block this_inst->push_context(); our_proto = ιhis_inst->prototype(); if (our.proto->is_sproc_input()){ // found an inputs, so add to caller's tally (*n_pιr)-H-; // make sure we can get timezone for it if (!our_proto->get_timezone(&name_expr, &rate.expr)) { this_inst->out_error("ZON060", cerr, FALSE); cerr « "This signal source does not have a " « "timezone nameΛn"; status - FALSE; } // // make sure this is a top level input // if (status) M-668 // { // if (!this_inst->parent()->is_top_level()) // { // this_inst->out_error("ZON161", cerr, FALSE); // cerr « "Design inputs in other than top level cells are not " // « "supportedΛn"; // status = FALSE; // } // } // evaluate the timezone name if (status) { if (translate_zone.name(name_expr, thisjnst, &name)) { // name now has a zone name // if its new, allocate a new zone zone.ptr = add.zone.if _not_present(name); // mark the zone in our instance this_inst->add_zone(zone_ptr) ; // also make sure ancestors have zone, in case we're not // at top level! this_inst->add_zone_in_ancestors(zone_ptr); } else { this_inst->out_error("ZON086", cerr, TRUE); cerr « "Timezone does not have a valid nameΛn"; status = FALSE; } } } // recursively call all our children for (i=0; i<this_inst->get_n_children(); i++){ // get next child in sequence which_child = thisjnst- >get.sequence(i); child = this_inst->get_child(which_child); // call child if (Kstatus = identify_zones(child, n.ptr))) break;} // make sure we really found some inputs for the top level -669 if (status)! If (this_inst->ϊs_top JevelO && ((*n_ptr) = 0) ) { ϊf(ιhis_inst->prototype()->is_autosequenceO) { this_inst->out_error("ZON061", cerr, FALSE); cerr « "Top level block has no inputs, so we cannot " « "partitionΛn"; status = FALSE; } }} //restore previous block context this_inst->pop_contextO ; return status;} iiiiiπiπiiiiππiiiiπiπiiiuiiiiiiiπiiniiiiiiiiiiiiiiiirii iπiiiiiiiii II add.zone.if.not.present // If zone name not present among zones, create a new zone. // Returns a pointer to the zone, old or new. zone* zones::add_zone_if_not_present(string* name)! BOOLEANfound.name; ϊnt j; zone* zone.ptr; found.name = FALSE; for (j=0; j<n_zones(); j++) ! if (*(timezones|j]->get_zone_name()) == *name) { found.name = TRUE; zone.ptr = timezonesβ]; }} if (Ifound.name) // new timezone, so allocate it and set name for zone zone_ptr = add_new.zone(name, FALSE); return zone.ptr;} II make.sub.zone // Create a sub-zone decimated or interpolated from another zone. // Passed the original zone ptr, the interpolation/decimation ratio, and // a flag as to whether interpolating or decimating. -670 // Returns the ptr of the newly created time zone. zone* zones::make_sub_zone(zone* in.zone.ptr, long ratio, BOOLEAN decimating)! char* ratio.str; string* name; zone* new.zone.ptr; double rel.sample.rate; long trigger.mask; int trigger.decim.factor; zone* orig_zone; // get a C string for the ratio number ratio . str = in t_to_c_string((inf) ratio); // create a name from the original zone name of the form xxxx.dnnn for // decimation or xxxx.innn for interpolation, which nnn is the // decimation or interpolation ratio name = new stringC"'); *name = *name + *in_zone_ptr->get_zone_name(); if (decimating) *name = *name + "_d"; else *name = *name + "J"; *name = *name + ratio.str; // add the new sub-zone to the set of zones new.zone.ptr = add_new_zone(name, TRUE); // record decimation/interpolation info for this sub-zone ((sub.zone*) new.zone_ptr)-> set_sub_zone(in_zone_ptr, ratio, decimating); // also set the mask and decimation info for probing wires in this zone // but do so only if not interpolated with respect the the original // zone orig_zone = new.zone.ptr- >original_zone(&rel_sample_rate); if (rel.sample.rate <= 1.0) { // make sure decimating by an integer factor trigger.decim.factor = (int) round(1.0/rel_sample_rate); trigger.mask = in_zone_ptr->zone_mask(); new.zone_ptr->set_zone_mask(trigger_mask); ((sub.zone*) new_zone_ptr)->set_decimation(trigger_decim_factor);} // mark original zone as a master zone orig_zone->set_as_master_zone(); M-671 return new.zone.ptr;} If zones.a t.samejrate // Returns TRUE if the given two zones are at the sample rate, that is, // if they operate from the same timing source at the same sample rate. BOOLEANzones::zones_at_same_rate(zone* zonel, zone* zone2){ zone*orig_zone_l ; zone*orig_zone_2; doublezone.l.fraction; doublezone_2_fraction; // trace zones back to its origin, computing decimation/interpolation //factors orϊg_zone_l = zonel->original_zone(&zone_l_fraction); orig_zone_2 = zone2->origϊnal_zone(&zone.2.fraction); // both must be equal to be at the same rate return (orig_zone_l = orig_zone_2 && zone_l_fraction = zone_2.fraction );} II later.zone // Returns TRUE if the first zone was created later than the second zone. // Later created zones have a higher array index. BOOLEANzones::later.zone(zone* zonel, zone* zone2)! ϊnt indexl, index2; ϊndexl = timezones.find(zonel); ϊndex2 = tϊmezones.find(zone2); return (ϊndexl > index2);} II try.to.collapse.zones // See if one zone has no trigger and the other zone is a sub-zone. // If so, collapse the non-triggered zone into the sub-zone. // Returns FALSE if unable to collapse zones. BOOLEANzones::try.to_collapse_zones(zone* zl, zone* z2){ zone*temp; if (z2->zone_mask() = 0L)( // swap zones so that zl can get potentially collapsed temp = zl; -672 zl = z2; z2 = temp;} if (zl->zone.mask() == 0L){ II zl is collapsible because it is non-triggered // is z2 a sub-zone? if (z2->is_sub_zone()) { // zl can be collapsed into z2 // give derived zone same name as collaped zone z2->override_zone_name(zl->get_zone_name()); // change all references to collaped zone top_instance->change_zone(z 1 , z2) ; // remove collapsed zone timezones.remove(timezones.find(zl)); first . sub.zone--; return TRUE; } } return FALSE;} // gsps::gsps // Constructor. gsps::gsps(){ next_gsp = 1;} II gsps:: -gsps // Destructor. gsps::~gsps() { } // bref.arr.cxx // derived class for block.ref array // Terry Montlick // 10/10/89 /* source code control: */ static char SccsID[] = "@(#)zone_arr.cxxl.56 10/7/91"; #include "bref_arr.hxx" // zone_arr.hxx // header for derived zone array class M-673 II T. Montlick // 3/14/90 /* source code control: @(#)zone_arr.hxxl.56 10/7/91 */ #define ZONE_ARRAY_DEF #ifndefARRAY_DEF #include "array.hxx" #endif class zone; class zone.array : public array! public: zone*&operator [j (inti) ! return (zone*&) array::operator[] (i); } ϊnt find(zone* ptr) ! return array::find(ptr); } void append(zone* ptr){ array: :append(ptr); } zone_array&operator+(zone_array& a) { return (zone_array&) array::operator+((array&) a); } zone_array&operator+=(zone_array& a) {a = *this + a; return *fhis; } };

Claims: We claim: 1. Apparatus for dividing a processing task into tasks for a programmable real time signal processor means and tasks for a host processor means, wherein said signal processor means and said host processor means are separately compiled, said signal processor means and said host processor means each include means for interfacing with each other, and said signal processor means includes program memory means and data memory means, said apparatus comprising: means for describing a block diagram representing said processing task for said signal processor means with a plurality of signal processing functional block means and a plurality of connections therebetween, each functional block means having a name, and a plurality of said functional block means having parameters; signal processor cell library means containing code representing a plurality of said high level signal processing functional block means and containing named cell specific variable requirements; signal processor scheduler means coupled to said means for describing and to said signal processor cell library means, for analyzing, scheduling, and compiling said code and for providing program code for the program memory of the signal processor means, data code for the data memory of the signal processing means, and a correspondence table between signal processor memory locations and said named cell variables and parameters of said functional blocks, said correspondence table being for the host processor means such mat said correspondence table is used in the compiling of the host processor means, wherein said program code and data code will cause the signal processor means to implement said tasks for said signal processor means, with said program code controlling the functioning of said real time signal processor means, and said data code providing initial parameter values for the signal processor means and initial sample data values for memory locations in the data memory means of said signal processor means, and wherein said parameter values represent values of parameters of said functional block means. 2. Apparatus according to claim 1, wherein: said means for describing a block diagram comprises a high-level computer screen entry system means for said choosing, entry, parameterization, and connection of a plurality of said functional block means. 3. Apparatus according to claim 2, wherein: said means for describing a block diagram further comprises a text editor means. 4. Apparatus according to claim 1, wherein: said means for describing a block diagram comprises means for representing said processing task for said host processor means with a plurality of high level host processor functional block means and a plurality of connections therebetween, each host processor functional block means having a name, and a plurality of said host processor functional block means having parameters, wherein said means for describing further comprises means for distinguishing between aspects of said block diagram intended for compilation by said signal processor means and aspects of said block diagram intended for compilation by said host processor means. 5. Apparatus according to claim 1, further comprising: means for generating from said program code and said data code signal processor means boot code suitable for compilation by said compiler of said host processor or for direct storage in said host processor, wherein said host processor means can use said boot code to boot up said signal processor means. 6. Apparatus according to claim 1, further comprising: correspondence table translation means for translating said correspondence table generated by said scheduler means into code suitable for compilation by a compiler for said host processor means. 7. Apparatus according to claim 5, further comprising: correspondence table translation means for translating said correspondence table generated by said scheduler means into code suitable for compilation by a compiler for said host processor means. 8. Apparatus according to claim 1 in conjunction with said signal processor means. 9. Apparatus according to claim 8, wherein: said signal processor means receives real time data signals, and processes said real time data signals thereby generating processed real time data signals which are available external to said signal processor means, and said signal processor means comprises at least one real time data signal receiving means forreceiving said real time data signals, each real time data signal receiving means including means for writing data to desired first address locations in a multiported central memory unit in a repeated sequential fashion; said multiported central memory unit coupled to said at least one real time data signal receiving means, said multiported central memory unit for storing said received data signals and said data code and comprising said data memory means; a digital processor means coupled to said multiported central memory unit, for obtaining said real time data signals from said first addresses of said multiported central memory unit, for processing said real time data signals and thereby generating processed data signals, and for sending said processed data signals for storage in second address locations of said multiported central memory unit; at least one data output means coupled to said multiported central memory unit, for obtaining in a repeated sequential fashion said processed data signals from said second address locations of said multiported central memory unit, and for making said processed data signals available external to said signal processor means as real time processed data signals, said program memory means coupled to said digital processor means for storing said program code, wherein said digital processor means processes said real time data signals according to said program code, wherein substantially all signal data received by said signal processor means flows through said multiported central memory unit, and wherein said real time data signal receiving means and said output means handle data flow into and out of said signal processor means and permit said digital processor means to function substantially free of data input interrupts. 10. Apparatus according to claim 9, wherein: said signal processor means further comprises a parallel host port coupled to said program memory means and to said multiported central memory means, wherein said host port comprises said interface to said host processor means. 11. Apparatus according to claim 1, further comprising: compiler means for said host processor means coupled to said signal processor scheduler means, wherein said compiler means for said host processor means compiles said correspondence table or a translation thereof and code for accomplishing said tasks of said host processor means. 12. Apparatus according to claim 11 in conjunction with said host processor means. 13. Apparatus according to claim 12 wherein: said host processor means comprises a microprocessor. 14. Method for dividing a processing task into tasks for a programmable real time signal processor means and tasks for a host processor means, wherein said signal processor means and said host processor means are separately compiled, said signal processor means and said host processor means each include means for interfacing with each other, and said signal processor means includes program memory means and data memory means, said method comprising: describing and representing said processing task for said signal processor means with a plurality of high level signal processing functional block means and a plurality of connections therebetween, each functional block means having a name, and a plurality of said functional block means having parameters; providing a signal processor cell library means containing code representing a plurality of said high level signal processing functional block means and containing named cell specific variable requirements; analyzing, scheduling, and compiling said code with a signal processor scheduler means, and providing program code for the program memory of the signal processor means, data code for the data memory of the signal processing means, and a correspondence table between signal processor memory locations and said named cell variables and parameters of said functional blocks; providing said correspondence table or a translation thereof to the compiler of the host processor means for compilation. 15. A method according to claim 14, further comprising: providing said program code and data code to said signal processor, thereby implementing said tasks for said signal processor means, with said program code controlling the functioning of said signal processor means, and said data code providing initial parameter values for the signal processor means and initial sample data values for memory locations in the data memory means of said signal processor means, and wherein said parameter values represent values of parameters of said functional block means. 16. A method according to claim 14, further comprising: generating from said program code and said data code signal processor means boot code suitable for compilation by said compiler of said host processor or for direct storage in said host processor. 17. A method according to claim 14, further comprising: compiling said correspondence table or a translation thereof in said host processor compiler, 18. A method according to claim 16, turther comprising: compiling said correspondence table or a translation thereof in said host processor compiler; storing said boot code in said host processor, and booting up said signal processor by providing said boot code stored in said host processor to said signal processor.

Inventors: KRASSOWSKI ANDREW J, MONTLICK TERRY F, ROBINSON JEFFREY I, ROUSE KEITH, KRASSOWSKI, ANDREW, J., MONTLICK, TERRY, F., ROBINSON, JEFFREY, I., ROUSE, KEITH
Applicants: STAR SEMICONDUCTOR CORP, STAR SEMICONDUCTOR CORPORATION
Application year: 1992
Main classification: G06F9
IPC codes: F02B75, G06F9, G06F15, G06F17