Abstract:
A method and apparatus for programming hardware registers using a database defining each hardware register and associated bit fields of the registers, input code including bit field write (BFW) commands identifying bit fields corresponding values to program into the bit fields and defining an array of software copies of the hardware registers, and a preprocessor for writing the appropriate code to program the hardware registers. The database provides the name, size and address of each register and the names and sizes of associated bit fields within each register. The preprocessor generates output source code by replacing the BFW commands with code to manipulate software copies of the hardware registers and to write the software copies to the hardware registers. The output source code identifies each of the affected registers and writing appropriate code to access the register only once per BFW command. The database definitions and the BFW commands allow superior organization and simplification to reduce programming time, cost and potential for error.

Description:
This application is a continuation of application Ser. No. 08/249,171, filed May 25, 1994 now abandoned. 
    
    
     RESERVATION OF COPYRIGHT 
     A portion of the disclosure of this patent document contains material which is subject to a claim of copyright protection. The copyright owner has no objection to the facsimile reproduction by anyone of the patent document or the patent disclosure, as it appears in the Patent and Trademark Office patent file or records, but otherwise reserves all copyright rights whatsoever. 
     APPENDIX 
     The present disclosure includes appendices A-C, which are source code listings of one embodiment of the present invention. Appendix A is a source code listing of a preprocessor which replaces bit field write commands with source code to program hardware registers. Appendix B is a source code listing of various header files used in conjunction with the source code of Appendix A. Appendix C is a listing of a database for use by the preprocessor of Appendix A defining each hardware register and its associated bit fields. 
     FIELD OF THE INVENTION 
     The present invention relates to programming hardware via software, and more particularly to programming write-only registers with simplified commands using a database and preprocessor. 
     DESCRIPTION OF THE RELATED ART 
     It is often desired to program hardware devices via software, e.g., processing systems where it is necessary to execute software commands to control hardware. Examples of such systems include an instrumentation system to perform laboratory research, process monitoring and control, data logging, analytical chemistry, test and analysis of physical phenomena and control of mechanical or electrical machinery, to name a few examples. The hardware may include transducers or other measuring and control devices to detect physical phenomena and provide electrical signals, where these electrical signals are received, measured or otherwise converted to digital data to be used by the processing system. Such instrumentation can be specialized for performing a particular task, but may also be programmable for performing a variety of tasks and functions. Programmable hardware typically includes some form of memory such as buffers or registers for storing the digital information. The memory is also used by the processing system to store values and parameters to initialize or otherwise control the hardware for performing the desired tasks. For example, a data acquisition (DAQ) or control system may include several initialization registers to program count values for counters and timers, or to otherwise select certain options or hardware devices to take desired measurements or to control some process or device. 
     Read/write registers are commonly used to achieve bidirectional communication between the hardware and software. However, such bidirectional communication is not always necessary. From the standpoint of the processing system, a read-only register may be sufficient to collect data from the hardware. Correspondingly, write-only registers are commonly used for setting values and counts or otherwise selecting certain options to initialize hardware to perform particular tasks. For example, a DAQ system may use write-only registers to program the hardware by establishing timing values for counters or timers, selecting positive or negative edges as triggering events, or enabling/disabling certain measuring functions, etc. Read-only or write-only registers are advantageous since the hardware required to perform the Write or read operations, respectively, is eliminated. This reduction in circuitry reduces cost and simplifies instrumentation hardware used for measurement and control. 
     Although the use of read- or write-only registers has many advantages, they are difficult to manage in software. A plurality of registers are often required for complete control of a measurement or control system. Not all of the bits of a given register are associated with related functions, and related bits often span a plurality of registers. For example, one register may include several bits to select a counter, another register may include related bits to control the synchronization and polarity of the selected counter, while another register may include related bits to program a delay value for the selected counter. Yet these three registers typically contain other unrelated bits which must remain unchanged when programming the counter values. A programmer is faced with the task of managing the current state of all of these bits to assure proper control of the hardware. 
     One solution for managing hardware registers is to maintain copies of the registers in software, often referred to as shadowing. In this manner, operations are performed on the software copy, such as reading, writing, or clearing certain bits while leaving the state of the remaining bits unchanged, and then the software copy is written out to the hardware register to complete the programming procedure. For example, for a write-only register, the computer executes code to manipulate the software copy of the register with defined constants using bitwise AND and NOT logic operations, and then writes the software copy of the register out to the address location of the hardware register. Since the write-only register can not be read, this entire operation must be performed in software for each bit or series of bits within each register. Although this procedure is relatively straightforward for a given register, it is difficult for a programmer to manage a plurality of registers in this manner. This is especially true in complicated conditional structures where certain parameters must be monitored to determine which register to program and with what values. Such a task is relatively time-consuming and is very error-prone, and such errors are often very difficult to detect. 
     As a simple example, the following source code lines may be written in the C language to program a 16 bit wide write-only hardware register: 
     
         ______________________________________#define  COLOR.sub.-- REG              17#define  BLUE.sub.-- BIT              (1&lt;&lt;13)#define  RED.sub.-- BIT              (1&lt;&lt;11)color.sub.-- reg.sub.-- soft.sub.-- copy = color.sub.-- reg.sub.--soft.sub.-- copy | BLUE.sub.-- BIT;color.sub.-- reg.sub.-- soft.sub.-- copy = color.sub.-- reg.sub.--soft.sub.-- copy &amp; (˜RED.sub.-- BIT);OUTWORD (base.sub.-- add+COLOR.sub.-- REG, color.sub.-- reg.sub.--soft.sub.-- copy);______________________________________ 
    
     The first three lines are #define directives for an ANSI (American National Standard Institute) C language preprocessor, where the C preprocessor substitutes the first value in the input source code with the second value in the output source code. Thus, the string of characters COLOR --  REG is substituted with the number 17. the string BLUE --  BIT is substituted with (1&lt;&lt;13) and so on. The value (1&lt;&lt;13) denotes a constant where a &#34;1&#34; in the right-most bit location, which is typically the least significant bit, is shifted left 13 times to the fourteenth bit location. The remaining bit locations are filled with 0&#39;s, so that this operation identifies a hexadecimal number of 0×2000 if a 16-bit value is indicated. A number with prefix &#34;0×&#34; denotes a hexadecimal number throughout this disclosure. The value color --  reg --  soft --  copy is a C language variable for containing a software copy of the COLOR --  REG hardware register. The &#34;|&#34; symbol denotes the bitwise logic OR function and the &#34;&amp;&#34; denotes the bitwise logic AND function. The &#34;˜&#34; symbol denotes bitwise logic negation or the NOT function. 
     In the fourth line of the above code, the fourteenth or blue bit of the color --  reg --  soft --  copy register is set to 1 by ORing it with a temporary register containing 0×2000, equivalent to binary 0010, 0000, 0000, 0000 (the commas added for clarity), where the result is stored back into the software copy. Thus, the fourteenth or blue bit is the only bit affected. In the fifth line, a 1 is shifted to the twelfth location of another temporary register and then the entire register is inverted, so that the twelfth bit becomes a 0 while the remaining bits become 1&#39;s. Thus, the temporary register contains the value 0×F7FF, equivalent to binary 1111, 0111, 1111, 1111, which is ANDed with, and stored back onto, the software copy. The only affected bit is the twelfth bit, while the remaining bits of the software copy remain unchanged. The sixth line of the above code involves writing the new software copy of the register out to the hardware. The term OUTWORD refers to a macro for directing the computer to write a value to a hardware register, where the base --  add value identifies the starting address in memory where several hardware registers are located. In this manner, the decimal number 17 is added to the base --  add address to locate the COLOR --  REG hardware register in memory, and the value in the color --  reg --  soft --  reg is written to the COLOR --  REG register. In summary, the selected bits of the software copy are modified and then the software copy is written to program the write-only register. 
     As another example using C language pointers, the following lines may be used in source code to program several related bits in a register: 
     
         ______________________________________#define    REG 33uInt32*    value.sub.-- ptr;value.sub.-- ptr = &amp; (mp--&gt;Copy.sub.-- COMM3.sub.-- REG);(*value.sub.-- ptr) &amp;= 0xFFBF;(*value.sub.-- ptr) |= 0x1B00;mp--&gt;Copy.sub.-- COMM3.sub.-- REG = &amp;(value.sub.-- ptr);OUTWORD(base.sub.-- add + REG, (*value.sub.-- ptr));______________________________________ 
    
     The above code clears bits 5 and 6 and sets bits 11, 12, and 13 of a hardware register at address 33. Here value --  ptr is a pointer variable loaded with an address to point to a software copy referred to as Copy --  COMM3 --  REG within a structure pointed to by a pointer mp. The register pointed to by value --  ptr is ANDed with hexadecimal value 0×FFBF to clear bits 5 and 6, and ORed with hexadecimal value 0×1B00 to set bits 11-13, while leaving the remaining bits unchanged. The software copy is updated with the new value and the result is written to the hardware register denoted by REG. 
     The lines of code to define the various registers, constants and variables of the database are typically placed in a header at the beginning of the source code or in a separate file for better organization. The programmer is required to write code similar to that described above for each hardware register to be programmed. Since the particular registers and individual bits of each register to be programmed often depends upon other variables, the programmer is required to properly embed the desired code within conditional structures, such as if-then-else structures, loop structures, case structures, etc. It is clear that programming a plurality of hardware registers a monumental task, which is time-consuming and error prone, especially in complicated conditional structures. 
     It is desirable therefore to provide a method and apparatus for more easily programming and managing low-level write-only registers, while maintaining the desired speed and performance. 
     SUMMARY OF THE INVENTION 
     A method of programming hardware registers according to the present invention includes storing a database defining each register as well as the various bit fields within each of the defined registers, receiving code including simplified BFW commands identifying bit fields and values to be programmed into those bit fields, and executing a preprocessor on the input code to expand the BFW commands to the appropriate output code. In this manner, the present invention allows a programmer to use simplified bit field write (BFW) commands to program the registers. The resulting output code is then compiled and executed on a computer. 
     In the preferred embodiment, the register database defines the size, address, name, and software mechanism to access each of the hardware registers. Each defined register is then followed by the names, sizes, and attributes of each of the bit fields within the register. The size of the bit fields may vary from one bit up to the size of the register, and may even span multiple registers. The database defining the hardware registers and associated bit fields may be at the header of the source code of the preprocessor, or placed into a separate file and linked together with the object code of the preprocessor. The use of a database to define each of the bit fields of the registers allows superior organization of the registers by placing the bit field information into a manageable format. In this manner, a programmer need not manage the individual bits since this function is performed by the preprocessor. 
     In the preferred embodiment, a preprocessor according to the present invention detects the BFW commands in the input code, retrieves each bit field and the value to be written to that bit field, determines all of the affected hardware registers, and replaces the BFW commands with appropriate code to manipulate each hardware register only once. Performance is maximized since the computations are performed before the software is compiled rather than at runtime. Preferably, an array of software copies of the hardware registers are also defined, so that the preprocessor writes the code to update the relevant software copies and then to write the software copies to program the corresponding hardware registers. If the BFW commands are written to program multiple fields of several registers, the preprocessor generates and organizes code to perform only one access for each hardware register to achieve optimal results. Thus, the efficiency of the compiled program is maximized since each hardware register is accessed only once per BFW command. The input code developed by the programmer is also greatly simplified since each BFW command only includes a list of the bit fields and corresponding values to be written to the bit fields. 
     Therefore, a programming method according to the present invention substantially simplifies the input code, maximizes performance of the resulting software program and allows superior organization, thereby reducing programming time, cost and potential for error. 
    
    
     BRIEF DESCRIPTION OF THE DRAWINGS 
     A better understanding of the present invention can be obtained when the following detailed description of the preferred embodiment is considered in conjunction with the following drawings, in which: 
     FIG. 1 is a simplified block diagram of an instrumentation system according to the present invention using a computer for programming and controlling hardware; 
     FIG. 2 is a flowchart diagram illustrating a procedure for programming hardware registers according to the present invention; and 
     FIG. 3 is a flowchart diagram illustrating operation of a preprocessor according to the present invention. 
    
    
     DETAILED DESCRIPTION OF THE PREFERRED EMBODIMENT 
     Referring now to FIG. 1, a simplified block diagram is shown of an instrument system 100 using a computer 102 for programming, controlling and receiving data from a hardware interface 104 connected to a unit under test (UUT) 106. The UUT 106 generally represents any process, physical phenomena, mechanical or electrical machinery, etc. being monitored, measured or controlled as desired. The hardware interface 104 may be a separate unit, but is preferably an interface card which plugs into the input/output (I/O) bus of the computer 102. The hardware interface 104 typically includes any transducers or devices for measuring parameters or controlling equipment, and also includes signal conditioning and computer interface apparatus, such as a GPIB (general purpose interface bus), data acquisition board (DAQ), VXIbus, RS-232, etc., for communicating digital information with the computer system 102. The hardware interface 104 includes programmable hardware, such as write-only registers 108, which are accessible by the computer 102 for establishing the appropriate measurement or control of the UUT 106. It is understood that similar concepts could be applied to read-only registers. 
     The computer 102 includes a microprocessor 110, I/O logic 112 for interfacing with the hardware interface 104, and memory 114 for storing data and for storing and executing software. For purposes of this disclosure, the memory 114 generally includes permanent storage media, such as magnetic disk and disk drives and the like, as well as dynamic memory such as random access memory (RAM) for loading and executing software programs. The input code 116 and the register definition database 122 are preferably written in a high level language, such as the C language, although it is understood that the present invention is not limited to any particular computer language since other languages, such as C++, PASCAL, FORTRAN, BASIC, assembly language, etc., could be used. The input code 116 is any program written to perform whatever functions are desired for the instrumentation system 100, which includes programming the hardware registers 108. For programming the hardware registers 108, the input code 116 includes bit field write (BFW) commands, described more fully below. The register definition database 122 defines each of the write-only hardware registers 108 accessible by the computer 102 and each of the bits or bit fields within each hardware register. 
     A preprocessor 118 according to the present invention is stored in the memory 114, which when executed, receives the input code 116 as input and generates output code 120, which is then stored in memory 114. The preprocessor 118 replaces the BFW (bit field write) commands with appropriate code commands into the output code 120. The preprocessor 118 also inserts the appropriate code and commands to cause the software program 126 to generate an array of software copies 128, in a similar manner as arrays are typically created in software. A compiler 124 is executed, which receives the output code 120 and generates and stores a software program 126 in the memory 114. The software program 126 is then loaded into RAM and executed by the microprocessor 110 to program the hardware interface 104 and hardware registers 108 as desired to perform the necessary measurement or control functions. While executing, the software program 126 creates the array of software copies 128 of the hardware registers 108 for shadowing purposes. 
     The array of software copies 128 is a structure for storing copies of the hardware registers 108 while the software program 126 is executing. It is preferably defined within the input code 116, but could be defined elsewhere, such as in a separate file or even within the preprocessor 118. The preprocessor 118 generates code to use the array of software copies 128 to program and to save the values written out to program the hardware registers 108. As will be described more fully below, each software copy is updated and then written out to program a corresponding one of the hardware registers 108. The term array is used generically since any suitable data structure could be used for shadowing purposes. 
     The database 122 is preferably located in a separate file and either referenced in the preprocessor 118, or compiled together with the source code of the preprocessor 118, or compiled separately and linked together using some type of object code linker to create a single executable program as the preprocessor 118. Of course, many other variations are possible, where the database could be a separate file used by the preprocessor as input while generating the output code 120. In any event, the database 122 includes the name of each of the hardware registers 108, its size, location or address in memory, followed by the name, location and size of each bit field within the respective registers, although other attributes may also be defined for the registers and the bit fields. For example, the register definitions in the database 122 may include a parameter defining whether to maintain a software copy of the register in the array of software copies 128 and another parameter defining a software mechanism, such as a macro, used to access the register. The bit field definition preferably includes other attributes, such as an optional parameter indicating whether a hardware bit field is automatically cleared after being asserted, in which case the software copy must also be cleared after being written to that hardware register 108. The preprocessor 118 uses the various parameters to assure that the software copy mirrors the hardware copy, if desired. 
     Although the database 122 is preferably written in C language eventually, it may be generated in another interim format and converted to C using a conversion program. For example, a register is defined using the following format: 
     R &lt;name&gt; &lt;size&gt; address&gt; &lt;copy&gt; &lt;access&gt; 
     where &lt;name&gt; is the register name, &lt;size&gt; is size of the register preferably in bits, &lt;address&gt; is the register address in any desired format (e.g. hexadecimal, decimal, octal, etc.), &lt;copy&gt; indicates whether or not to maintain a software copy in the array of software copies 128, and &lt;access&gt; is the name of the software mechanism used to access the register, such as the name of a macro. The address could be an address in the memory 114, but is preferably in the I/O space accessed through the I/O logic 112 to write to the hardware registers 108. The copy parameter is preferably one of two values, either &#34;SAVE&#34; to keep a software copy or &#34;TRASH&#34; indicating a software copy is unnecessary. It is understood that the particular order of the parameters is arbitrary and that other parameters could be added if desired. The most important parameters are the name, address, and size of the register for appropriate manipulation, where the copy parameter is desired but could be omitted. 
     The register line is followed by one or more bit field lines defining each of the bit fields within the register. Although many possible formats for the bit fields are contemplated, the preferred format is as follows: 
     F&lt;name&gt; &lt;width&gt; [&lt;strobe&gt;] 
     where &lt;name&gt; is the bit field name, &lt;width&gt; is the bit field width in bits, and &lt;strobe&gt; is an optional parameter for indicating a bit field that is written without modifying the corresponding software copy of the hardware register. Each of the bit fields of the register is one or more bits in width. The name for each bit field allows specific identification of each bit field in each hardware register 108. As a particular example, three of the hardware registers 108 and corresponding bit fields are defined as follows: 
     
         __________________________________________________________________________R AI.sub.-- Mode.sub.-- 3.sub.-- Register              16                0x57                   SAVE                       STC.sub.-- WRITE.sub.-- 16.sub.-- WF AI.sub.-- External.sub.-- Gate.sub.-- Select              5F AI.sub.-- External.sub.-- Gate.sub.-- Polarity              1F AI.sub.-- FIFO.sub.-- Mode              2F AI.sub.-- External.sub.-- Gate.sub.-- Mode              1F AI.sub.-- Delayed.sub.-- START1              1F AI.sub.-- Delayed.sub.-- START2              1F AI.sub.-- SI2.sub.-- Source.sub.-- Select              1F AI.sub.-- SI.sub.-- Special.sub.-- Trigger.sub.-- Delay              1F AI.sub.-- Software.sub.-- Gate              1F Reserved         2R AI.sub.-- START.sub.-- STOP.sub.-- Select.sub.-- Register              16                0x3E                   SAVE                       STC.sub.-- WRITE.sub.-- 16.sub.-- WF AI.sub.-- START.sub.-- Select              5F AI.sub.-- START.sub.-- Edge              1F AI.sub.-- START.sub.-- Sync              1F AI.sub.-- STOP.sub.-- Select              5F AI.sub.-- STOP.sub.-- Edge              1F AI.sub.-- STOP.sub.-- Sync              1F AI.sub.-- STOP.sub.-- Polarity              1F AI.sub.-- START.sub.-- Polarity              1R AI.sub.-- Mode.sub.-- 1.sub.-- Register              16                0x0C                   SAVE                       STC.sub.-- WRITE.sub.-- 16.sub.-- WF AI.sub.-- Trigger.sub.-- Once              1F Ai.sub.-- Continuous              1F Reserved.sub.-- One              1F AI.sub.-- Start.sub.-- Stop              1F AI.sub.-- SI.sub.-- Source.sub.-- Polarity              1F AI.sub.-- CONVERT.sub.-- Source.sub.-- Polarity              1F AI.sub.-- SI.sub.-- Source.sub.-- Select              5F AI.sub.-- CONVERT.sub.-- Source.sub.-- Select              5__________________________________________________________________________ 
    
     where the registers AI --  Mode --  3 --  Register, AI --  START --  STOP --  Select --  Register and AI --  Mode --  1 --  Register are each 16 bits in length, located in the memory 114 or I/O space of the computer 102 at hexadecimal address 0×57, 0×3E and 0×06, respectively, and are written using a predefined macro called STC --  WRITE --  16 --  W. The AI --  Mode --  3  --  Register includes ten separate bit field definitions, including a 5-bit AI --  External --  Gate --  Select bit field located at the least significant 5 bits, a 2-bit AI --  FIFO --  Mode bit field and where the most significant 2 bits are reserved. The remaining bit fields are 1 bit in length. Likewise, the AI --  START --  STOP --  Select --  Register includes eight bit fields, where the bit fields AI --  START --  Select and AI --  STOP --  Select are 5 bits in width each and the remaining bit fields are 1 bit each. The AI --  Mode --  1 --  Register has eight bit fields, including two 5-bit bit fields named AI --  SI --  Source --  Select and AI --  CONVERT --  Source --  Select located at the 10 most significant bits. In this manner, the bit fields defined above can easily be referenced in the source code, as will be described below. 
     The above register and bit field definitions are then converted to C language using a simple conversion program. The above format and conversion are for convenience and simplicity, although the database 122 could also be written directly in C language. Appendix C provides a full listing in C language of the register definition database 122 used in the preferred embodiment. For purposes of illustration, the AI --  Mode --  3 --  Register is provided below in C language format: 
     {AI --  Mode --  3 --  Register,16,0,0,0×57,0×FF,&#34;AI --  Mode --  3 --  Register&#34;,&#34;AI --  Mode --  3 --  Register&#34;}, 
     {AI --External   --  Gate --  Select,5,0,0,0×57,0×FF,&#34;AI --  External --  Gate --  Select&#34;, &#34;AI --  Mode --  3 --  Register&#34;}, 
     {AI --  External --  Gate --  Polarity,1,5,0,0×57,0×FF,&#34;AI --  External --  Gate --  Polarity&#34;, &#34;AI --  Mode --  3 Register&#34;}, 
     {AI --  FIFO --  Mode,2,6, 0,0×57, 0×FF,&#34;AI --  FIFO --  Mode&#34;,&#34;AI --  Mode --  3 --  Register&#34;}, 
     {AI --  External --  Gate --  Mode,1,8,0,0&gt;57,0×FF,&#34;AI --  External --  Gate --  Mode&#34;, &#34;AI --  Mode --  3 --  Register&#34;}, 
     {AI --  Delayed --  START1,1,9,0,0×57,0×FF,&#34;AI --  Delayed --  START1&#34;,&#34;AI --  Mode --  3  --  Register&#34;}, 
     {AI --  Delayed --  START2,1,10,0,0×57,0×FF,&#34;AI --  Delayed --  START2&#34;, &#34;AI --  Mode --  3 --  Register&#34;}, 
     {AI --  SI2 --  Source --  Select,1,11,0,0×57,0×FF&#34;AI --  SI2 --  Source --  Select&#34;, &#34;AI --  Mode --  3 --  Register&#34;}, 
     {AI --  SI --  Special --  Trigger --  Delay,1, 12, 0, 0×57, 0FF, &#34;AI --  SI --  Special --  Trigger --  Delay&#34;, &#34;AI --  Mode --  3 --  Register&#34;}, 
     {AI --  Software --  Gate,1,13, 0, 0×57, 0×FF, &#34;AI --  Software --  Gate&#34;, &#34;AI --  Mode 3 --  Register&#34;}, 
     {Reserved, 2, 14, 0, 0×57, 0×FF, &#34;Reserved&#34;, &#34;AI --  Mode --  3 --  Register&#34;}, 
     where the first parameter between each bracket pair {} is the name of the register or bit field, the second parameter is the register or bit field size in bits, the third parameter is the bit location of the bit field within the register, the fourth parameter is the copy parameter for a register line (0=SAVE, 1=TRASH) or the fourth parameter is the strobe parameter for a bit field line (0=no strobe, 1=strobe), the fifth parameter is the address of the register, the sixth parameter is not used, and the seventh and eighth parameters are string definitions of the name of the bit field followed by the name of the register for debug purposes. The macro definitions are suppressed in this example since the preprocessor 118 typically includes one or more header files for defining constants and macros. Examples of such header files are provided in appendix B. 
     It is clear that the database 122 may be easily established to define as many of the hardware registers 108 as desired, including the names and sizes of the bit fields contained within each of registers. It is understood that the particular formats described above are exemplary only and that other formats could be defined depending upon the programming language used. Alternatively, since the hardware registers 108 and corresponding bit field definitions are typically predefined according to the hardware requirements, the lines of the database 122 may be generated automatically by a computer. 
     The input code 116 includes the BFW commands to program the bit fields with the desired patterns or values. Each BFW command preferably has the following form: 
     BFW(list of bit field name/value pairs,  --  LAST -- ) 
     where the list of bit field name/value pairs includes one or more pairs of bit field names followed by a value to be programmed into that bit field, and where &#34; --  LAST --  &#34; denotes the end of the list. For example, the input code 116 could include the following commands: 
     
         __________________________________________________________________________BFW(    AI.sub.-- SI.sub.-- Special.sub.-- Trigger.sub.-- Delay,               0,    AI.sub.-- START.sub.-- Select,               0,    AI.sub.-- START.sub.-- Edge,               1,    AI.sub.-- START.sub.-- Sync,               1    AI.sub.-- START.sub.-- Polarity,               0,           .sub.-- LAST.sub.--);BFW(    AI.sub.-- SI.sub.-- Source.sub.-- Select,               p--&gt;ai.sub.-- si.sub.-- source.sub.-- select,    AI.sub.-- SI.sub.-- Source.sub.-- Polarity,               0,           .sub.-- LAST.sub.--);__________________________________________________________________________ 
    
     where the name of each bit field is followed by the number of value to be programmed into the respective bit field. Note that the AI --  SI --  Special --  Trigger --  Delay bit field is the 13th bit of the AI --  Mode --  3 --  Register and that the AI --  START --  Select, Edge, Sync and Polarity bit fields are located in the AI --  START --  STOP --  Select --  Register. Note further that although the AI --  START --  Select bit field is 5 bits wide, the input code 116 need only specify a 0 to clear all five bits. Thus, a plurality, of bit fields from a plurality of registers may be programmed with a single BFW command if the particular order of programming the registers or bit fields is not important. Alternatively, if the particular programming order for the bit fields is important, the first BFW command listed above can be replaced by the following BFW commands: 
     BFW(AI --  SI --  Special --  Trigger --  Delay, 0,  --  LAST -- ); 
     BFW(AI --  START --  Select, 0,  --  LAST -- ); 
     BFW(AI --  START --  Edge, 1,  --  LAST -- ); 
     BFW(AI --  START --  Sync, 1,  --  LAST -- ); 
     BFW(AI --  START --  Polarity, 0,  --  LAST -- ): 
     to assure that the bit fields are programmed in the particular order listed. 
     The preprocessor 118 is then executed upon the input code 116, which generates the output code 120. The preprocessor 118 merely copies each of the commands other than BFW commands to the output code 120. However, for each BFW command, the preprocessor 118 forms the bit field identifiers and corresponding values for each BFW command definition, then creates a list of all of the hardware registers 108 that are affected by the BFW command, generates the code that performs the appropriate manipulation of the corresponding software copy within the array of software copies 128 and replaces the BFW command with the generated code in the output code 120. For example, the BFW commands described above are received by the preprocessor 118 and the following code is preferably written to the output code 120: 
     
         ______________________________________uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr =&amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[87]);(* soft.sub.-- copy.sub.-- ptr)   &amp;=   0xEFFF;(* soft.sub.-- copy.sub.-- ptr)   |=   0x0060;stc--&gt;stc.sub.-- write.sub.-- soft.sub.-- copy[87] =&amp;(soft.sub.--copy.sub.-- ptr);STC.sub.-- WRITE.sub.-- 16.sub.-- W(87, (* soft.sub.-- copy.sub.--ptr));uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr =&amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--coppy[62]);(* soft.sub.-- copy.sub.-- ptr)   &amp;=   0x7F80;(* soft.sub.-- copy.sub.-- ptr)   |=   0x0060;stc--&gt;stc.sub.-- write.sub.-- soft.sub.-- copy[62] =&amp;(soft.sub.--copy.sub.-- ptr);STC.sub.-- WRITE.sub.-- 16.sub.-- W(62, (* soft.sub.-- copy.sub.--ptr));uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr =&amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy [12];(*soft.sub.-- copy.sub.-- ptr) &amp;= 0xF82F;(*soft.sub.-- copy.sub.-- ptr) |= (((p--&gt;ai.sub.-- si.sub.--source.sub.-- select)&amp; 0x1F)&lt;&lt;6)     | (((0) &amp; 0x1) &lt;&lt;4);stc--&gt;stc.sub.-- write.sub.-- soft.sub.-- copy [12] =&amp;(soft.sub.--copy.sub.-- ptr);STC.sub.-- WRITE.sub.-- 16.sub.-- W(12, (*soft.sub.-- copy.sub.--______________________________________ptr)); 
    
     where soft --  copy --  ptr is a 32-bit pointer variable and the pointer stc points to a software structure containing copies of the hardware registers 108 to implement the array of software copies 128. The → operator is a pointer reference of a structure as known to those skilled in the art of programming in C language. Also, the decimal numbers 87, 62, and 12 correspond to the hexadecimal address values 0×57, 0×3E and 0×0C of the defined hardware registers 108. 
     In the first group of code lines, the soft --  copy --  ptr value is defined and then made to point to the software copy in the array of software copies 128 of the hardware register 108 to be programmed. In the next line, the software copy is ANDed with the hex value 0×EFFF, which corresponds to binary 1110, 1111, 1111, 1111. Thus, the software copy of the register is ANDed with all 1&#39;s in the bit fields, except for a 0 located in the fourth most significant bit location corresponding to the AI --  SI --  Special --  Trigger --  Delay bit field of the AI --  Mode --  3 --  Register. In the next line, the result is ORed with all zeros, which is equivalent to a non operation so that this code line is extraneous and not necessary. In this example, the preprocessor 118 is relatively simple and generates code to perform an AND operation followed by an OR operation, even if one of these operations is unnecessary. The performance penalty is relatively minimal since computation is performed during compilation rather than at runtime. However, several optimization methods could be implemented. For example, the preprocessor 118 could be more sophisticated to recognize extraneous lines and not generate corresponding code to the output. In that case, the OR operation would not be generated. Alternatively, a compiler 124 executed on the output code 120 after preprocessing could be instructed to ignore extraneous lines and operations. 
     In the next line of the code, the copy pointed to by soft --  copy --  ptr is stored back into the software copy in the stc structure within the database 123. In the last line of the first group, the STC --  WRITE command writes out to decimal address 87, which corresponds to hexadecimal address 0×57 to program the AI --  Mode --  3 --  Register. 
     The second group of commands is used to program the AI --  START --  STOP --  Select --  Register corresponding to the next four lines of the first BFW command listed above. In the first two lines, the soft --  copy --  ptr is defined and then made to point to the software copy of the write-only register located at decimal address 62, corresponding to hexadecimal address 0×3E of the AI --  START --  STOP --  Select --  Register. In the third line, the contents pointed to by soft --  copy --  ptr is then ANDed with hexadecimal value 0×7F80, which is equal to binary 0111, 1111, 1000, 0000, which programs a 0 in the least significant seven bits and into the most significant bit, thereby clearing the 5-bit field AI --  START --  Select and the AI --  START --  edge, and AI --  START --  sync and AI --  START --  Polarity bit fields of the AI --  START --  STOP --  Select --  Register. In the fourth line, the software copy is ORed with hex value 0×0060, which equals bit value 0000, 0000, 0110, 0000, which forces a 1 into each of the 5th and 6th bit locations, corresponding to the AI --  START --  Edge and AI --  START --  sync bit fields of the AI --  START --  STOP --  Select --  Register. This corresponds precisely to that specified in the first BFW command. In this manner, all bit locations to be programmed are first cleared including those that are set in the following command line. Clearing all of the bits is not necessary, but allows the preprocessor 118 to be simpler without incurring any performance penalty. In the last two lines, the contents of the temporary software register pointed to by soft --  copy --  ptr is written back into the corresponding software copy of the stc structure, and then written out to hardware address decimal 62 to program the corresponding hardware register. 
     The final group of input code 116 programs the 5-bit AI --  SI --  Source --  Select bit field and the 1-bit AI --  SI --  Source --  Polarity bit field of the AI --  Mode --  1 --  Register according to the second BFW command. Again, soft --  copy --  ptr is defined and set to point to the appropriate software copy in the stc structure or array of software copies 128. In the third line, all bit locations of the software copy are first cleared by ANDing with hexadecimal value 0×F82F. In the fourth line, a 5-bit constant value p→ai --  si --  source --  select is ANDed with 5 ones (0×1F) to clear the non-relevant bit locations, and then shifted left six times to convert to 16 bits and to place a 1 in each relevant bit location, while placing a 0 in the remaining bit locations. In the same line, the result is ORed with another value defined as 0 ANDed with a 1 and shifted left four times to program a 0 into the AI --  SI --  Source --  Polarity bit field. This OR operation is extraneous since a 0 has already been programmed into that location. Again, the preprocessor or compiler could be optimized to remove or otherwise ignore this extraneous portion of the operation. In the last two lines, the soilware copy in the stc structure is updated and the calculated value is written to program the AI --  Mode --  1 --  Register hardware register. 
     Referring now to FIG. 2, a flowchart diagram is shown summarizing the procedure detailed above. Each of the hardware registers 108 and associated bit fields are defined in the database 122 as indicated by a step 200. The input code 116 including the BFW commands is received by the computer 102 in a step 202. The array of software copies 128 is preferably defined in step 204 within the input code 116, although the actual array is not created until runtime of the software program 126. The input code 116 is then preprocessed by the preprocessor 118 in a step 204 to generate the output code 120. The preprocessor 118 preferably generates code to use the array of software copies 128 to update and store the values to be written to the hardware registers 108. The output code 120 is compiled by the compiler 124 in a step 206 to create the software program 126. The software program 126 is then executed in a step 208 by the microprocessor 110 of the computer 102, which uses the I/O logic 112 to program the hardware registers 108. 
     Referring now to FIG. 3, a flowchart diagram is shown illustrating operation of the preprocessor 118 according to the present invention. Operation begins at step 300, where the preprocessor 118 reads the first or the next line of an input code 116. Each command line contains a string of characters tbllowed by some end character, such as a semi-colon(;), denoting the end of the command line. Operation then proceeds to a step 302 which determines if the line contains a BFW command, which is preferably detected if the letters &#34;BFW&#34; are present in the line. If not, operation proceeds to a step 304, where the entire line is copied to the output file. Operation then proceeds to a step 306 which queries whether there are more lines in the input code 116. If not, operation is completed. If there are more lines in the input code 116 as determined in step 306, operation returns to step 300 to read the next line of the input code 116. The end of file (eof) character is preferably detected to determine whether there are more command lines in the input code 116. 
     Referring back to step 302, if the line contains a BFW command, operation proceeds to a step 310, where the entire BFW command is retrieved from the input code 116. The end of the BFW command is preferably indicated by a parameter  --  LAST -- . Operation then proceeds to a step 312, where the BFW command string is divided into pairs of bit field names and corresponding values to be programmed into that bit field. Once all of these pairs are defined in step 312, operation proceeds to a step 314 where all of the hardware registers 108 associated with the bit fields in step 312 are determined and listed. Operation then proceeds to a step 316, where the preprocessor 118 generates the necessary code to perform the appropriate logic operations to manipulate all of the bit fields of each software copy within the array of software copies 128 of each hardware register 108, and to write the software copy to the corresponding hardware register 108. Details of an embodiment of particular code are provided in the source code listing provided in appendix A. As stated previously, the particular code used depends upon the programming language and the level of code optimization desired. Finally, operation proceeds to a step 318, where the generated code is written to the output code 120. From step 318, operation proceeds to step 306 to determine if more lines exist in the input code 116. In this manner, only one hardware access is required for each hardware register 108 affected for each BFW command, thereby optimizing execution of the software program 126. Such optimization allows the software program 126 to be executed much more quickly, since only one access is necessary rather than multiple accesses as would be done in prior art. 
     For purposes of full disclosure and completeness, a portion of an example input code 116 and the corresponding output code 120 is provided below. The output code 120 is generated by a preprocessor 118 for preprocessing according to the method of the present invention. The if-then-else structure emphasizes the simplicity of the input code compared to that source code which a programmer would be required to write without the present invention. 
     EXAMPLE INPUT CODE 
     
         __________________________________________________________________________STC.sub.-- START.sub.-- AI.sub.-- SINGLE.sub.-- RUN(ai.sub.-- scan.sub.--start)BFW( AI.sub.-- Configuration.sub.-- Start,  1,.sub.-- LAST.sub.--);if(p--&gt;ai.sub.-- will.sub.-- use.sub.-- internal.sub.-- scan.sub.--clock){BFW( AI.sub.-- SI.sub.-- Special.sub.-- Trigger.sub.-- Delay, 0,AI.sub.-- START.sub.-- Select,               0,AI.sub.-- START.sub.-- Edge,               1,AI.sub.-- START.sub.-- Sync,               1,AI.sub.-- START.sub.-- Polarity,               0,                 .sub.-- LAST.sub.--);if(p--&gt;ai.sub.-- si.sub.-- will.sub.-- use.sub.-- internal.sub.-- time){BFW( AI.sub.-- SI.sub.-- Source.sub.-- Select,                p--&gt;ai.sub.-- si.sub.-- source.sub.-- select,  AI.sub.-- SI.sub.-- Source.sub.-- Polarity,               0,            .sub.-- LAST.sub.--);}else{BFW( AI.sub.-- SI.sub.-- Source.sub.-- Select,                p--&gt;ai.sub.-- si.sub.-- source.sub.-- select,  AI.sub.-- SI.sub.-- Source.sub.-- Polarity,               p--&lt;ai.sub.-- si.sub.-- source.sub.-- polarity,                             .sub.-- LAST.sub.--);}if ( ! (p--&gt;ai.sub.-- will.sub.-- be.sub.-- retriggerable)){/* you can specify special delay from START1 *//* trigger to the first start of scan by  *//* preloading SI    */BFW( AI.sub.-- SI.sub.-- Load.sub.-- A,               p--&gt;ai.sub.-- si.sub.-- special.sub.-- ticks-1,               LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Initial.sub.-- Load.sub.-- Source,                        .sub.-- LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Load,              1,      .sub.-- LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Load.sub.-- A,               p--&gt;ai.sub.-- si.sub.-- ordinary.sub.-- ticks-1,               --LAST);BFW( AI.sub.-- SI.sub.-- Reload.sub.-- Mode,               0,   .sub.-- LAST.sub.--);}else if( ! (p--&gt;ai.sub.-- with.sub.-- change.sub.-- rate.sub.-- on.sub.--the.sub.-- fly)){/* you can specify special delay from START1 *//* trigger to the first start of scan by  *//* using one of the reload modes.      */BFW( AI.sub.-- SI.sub.-- Load.sub.-- B,               p--&gt;ai.sub.-- si.sub.-- special.sub.-- ticks-1,               .sub.-- LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Load.sub.-- A,               p--&gt;ai.sub.-- si.sub.-- ordinary.sub.-- ticks-1,               .sub.-- LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Initial.sub.-- Load.sub.-- Source,                        .sub.-- LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Load,              1,    .sub.-- LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Initial.sub.-- Load.sub.-- Source, 0,  AI.sub.-- SI.sub.-- Reload.sub.-- Mode,               6,   .sub.-- LAST.sub.--);}else{/* interval from the START1 trigger to the  *//* first start of scan is equal to the scan  *//* interval        */BFW( AI.sub.-- SI.sub.-- Load.sub.-- A,               p--&gt;ai.sub.-- si.sub.-- ordinary.sub.-- ticks-1,               .sub.-- LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Initial.sub.-- Load.sub.-- Source, 0,  AI.sub.-- SI.sub.-- Reload.sub.-- Mode,               0,     .sub.-- LAST.sub.--);BFW ( AI.sub.-- SI.sub.-- Load,               1,   .sub.-- LAST.sub.--);}BFW( AI.sub.-- SI.sub.-- Write.sub.-- Switch,               0,   .sub.-- LAST.sub.--);}else{/* In the single-wire for START and CONVERT case, you need to/* set AI.sub.-- START.sub.-- Sync to 0./* The single-wire case is defined by START and CONVERT coming/* from a single external source, with the same polarity./* In other cases, it is safe to set AI.sub.-- START.sub.-- Sync to 1./* It is always safe to set AI.sub.-- START.sub.-- Edge to 1. */if(  (p--&gt;ai.sub.-- start.sub.-- select == p--&gt;ai.sub.-- convert.sub.--source.sub.-- select) &amp;&amp; (p--&gt;ai.sub.-- start.sub.-- polarity !=p--&gt;ai.sub.-- convert.sub.--source.sub.-- polarity))/* The inequality of the two polarities indicates that the two *//* signals are of the same polarity, since those data   *//* structure components correspond to the hardware...   */{DaqDebugPrint((&#34;AI.sub.-- START.sub.-- Sync = 0\n&#34;));BFW( AI.sub.-- START.sub.-- Select,               p--&gt;ai.sub.-- start.sub.-- select,  AI.sub.-- START.sub.-- Sync,               0,  AI.sub.-- START.sub.-- Edge,               1,  AI.sub.-- START.sub.-- Polarity,               p--&gt;ai.sub.-- start polarity,                          .sub.-- LAST.sub.--);}else{DaqDebugPrint((&#34;AI.sub.-- START.sub.-- Sync = 1\n&#34;));BFW (AI.sub.-- START.sub.-- Select,               p--&gt;ai.sub.-- start.sub.-- select,  AI.sub.-- START.sub.-- Sync,              1,  AI.sub.-- START.sub.-- Edge,              1,  AI.sub.-- START.sub.-- Polarity,              p--&gt;ai.sub.-- start.sub.-- polarity,                          .sub.-- LAST.sub.--);}if(p--&gt;ai.sub.-- will.sub.-- have.sub.-- special.sub.-- delay){BFW( AI.sub.-- SI.sub.-- Special.sub.-- Trigger.sub.-- Delay, 1,  AI.sub.-- SI.sub.-- Write.sub.-- Switch, 0, .sub.-- LAST.sub.--);if(p--&gt;ai.sub.-- si.sub.-- will.sub.-- use.sub.-- internal.sub.-- time){  BFW(AI.sub.-- SI.sub.-- Source.sub.-- Select, p--&gt;ai.sub.--  si.sub.-- source.sub.-- select,  AI.sub.-- SI.sub.-- Source.sub.-- Polarity, 0,                    .sub.-- LAST.sub.--);}else{BFW( AI.sub.-- SI.sub.-- Source.sub.-- Select, p--&gt;ai.sub.-- si.sub.--source.sub.-- select,  AI.sub.-- SI.sub.-- Source.sub.-- Polarity, p--&gt;ai.sub.-- si.sub.--   source.sub.-- polarity, --LAST.sub.--);}BFW( AI.sub.-- SI.sub.-- Load.sub.-- A,               p--&gt;ai.sub.-- si.sub.-- special.sub.-- ticks-1,               --LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Initial.sub.-- Load.sub.-- Source,                        .sub.-- LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Load,              1,      .sub.-- LAST.sub.--);}else{BFW( AI.sub.-- SI.sub.-- Special.sub.-- Trigger.sub.-- Delay, 0, .sub.--LAST.sub.--);}}if(p--&gt;ai.sub.-- will.sub.-- be.sub.-- staged == YES){BFW( AI.sub.-- SI.sub.-- Load.sub.-- B,               p--&gt;ai.sub.-- si.sub.-- new.sub.-- ordinary.sub.--               ticks[0]-1,                      --LAST.sub.--);BFW( AI.sub.-- SI.sub.-- Reload.sub.-- Mode,              0,    .sub.-- LAST.sub.--);BFW ( AI.sub.-- SI.sub.-- Switch.sub.-- Load.sub.-- On.sub.-- SC.sub.--TC,20 1,                    .sub.-- LAST.sub.--);p--&gt;ai.sub.-- si.sub.-- last.sub.-- load.sub.-- register = 1; } else {p--&gt;ai.sub.-- si.sub.-- last.sub.-- load.sub.-- register = 0; } BFW( AI.sub.-- Configuration.sub.-- Start,  0,AI.sub.-- Configuration.sub.-- End,  1, .sub.-- LAST.sub.--);}STC.sub.-- END__________________________________________________________________________ 
    
     RESULTING OUTPUT CODE (AFTER PREPROCESSING) 
     
         __________________________________________________________________________STC.sub.-- START.sub.-- AI.sub.-- SINGLE.sub.-- RUN(ai.sub.-- scan.sub.--start) { {uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[72]);(* soft.sub.-- copy.sub.-- ptr) |= 0x0010;STC.sub.-- WRITE.sub.-- 16.sub.-- W(72, (* soft.sub.-- copy.sub.--ptr));(* soft.sub.-- copy.sub.-- ptr) *= ˜0xF7CF; }}if(p--&gt;ai.sub.-- will.sub.-- use.sub.-- internal.sub.-- scan.sub.--clock){ /* AI.sub.-- START.sub.-- Select            := 0    */ /* AI.sub.-- START.sub.-- Edge            := 1    */ /* AI.sub.-- START.sub.-- Sync            := 1    */ /* AI.sub.-- START.sub.-- Polarity             := 0   */ {{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = *(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[87]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0xEFFF;STC.sub.-- WRITE.sub.-- 16.sub.-- W(87, (* soft.sub.-- copy.sub.--ptr));}{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[62]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0x7F80;(* soft.sub.-- copy.sub.-- ptr) |= 0x0060;STC.sub.-- WRITE.sub.-- 16.sub.-- W(62, (* soft.sub.-- copy.sub.--ptr)); }}if(p--&gt;ai.sub.-- si.sub.-- will.sub.-- use.sub.-- internal.sub.-- time){/* AI.sub.-- SI.sub.-- Source.sub.-- Polarity            := 0    */{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[12]);(* soft.sub.-- copy.sub.-- ptr) *= 0xF82F;(* soft.sub.-- copy.sub.-- ptr) |= ( ((p--&gt;ai.sub.-- si.sub.--source.sub.-- select)&amp; 0x1F) &lt;&lt;6)            |( ((0) &amp; 0x1) &lt;&lt;4);STC.sub.-- WRITE.sub.-- 16.sub.-- W(12, (* soft.sub.-- copy.sub.--ptr));}}}else{/* AI.sub.-- SI.sub.-- Source.sub.-- Polarity              := p--&gt;ai.sub.-- si.sub.-- source.sub.-- polarity                             */{{uInt32* soft.sub.-- copy .sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[12]);(* soft.sub.-- copy.sub.-- ptr) *= 0xF82F;(* soft.sub.-- copy.sub.-- ptr) |= ( ((p--&gt;ai.sub.-- si.sub.--source.sub.-- select) &amp; 0x1F) &lt;&lt;6)            |( ((p--&gt;ai.sub.-- si.sub.-- source.sub.--            polarity) &amp; 0x1) &lt;&lt;4);STC.sub.-- WRITE.sub.-- 16.sub.-- W(12, (* soft.sub.-- copy.sub.--ptr));}}}if( ! (p--&gt;ai.sub.-- will.sub.-- be.sub.-- retriggerable){/* you can specify special delay from START1 *//* trigger to the first start of scan by  *//* preloading SI     */{{STC.sub.-- WRITE.sub.-- 32.sub.-- W(14, ( ((p--&gt;ai.sub.-- si.sub.--special.sub.-- ticks-1) &amp; 0xFFFFFF) &lt;&lt;0));}}{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0xFF7F;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (* soft.sub.-- copy.sub.--ptr));}}{{STC.sub.-- WRITE.sub.-- 16.sub.-- W(8, 0x0200);}}{{STC.sub.-- WRITE.sub.-- 32.sub.-- W(14, ( ((p--&gt;ai.sub.-- si.sub.--ordinary.sub.-- ticks-1) &amp; 0xFFFFFF) &lt;&lt;0));}}{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0xFF8F;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (*soft.sub.-- copy.sub.-- ptr));}}}else if ( ! (p--&gt;ai.sub.-- with.sub.-- change.sub.-- rate.sub.-- on.sub.-- the.sub.-- fly)){/* you can specify special delay from START1 *//* trigger to the first start of scan by  *//* using one of the reload modes.     */{{STC.sub.-- WRITE.sub.-- 32.sub.-- W(16, ( ((p--&gt;ai.sub.-- si.sub.--special.sub.-- ticks-1) &amp; 0xFFFFFF) &lt;&lt;0));}}{{STC.sub.-- WRITE.sub.-- 32.sub.-- W(14, ( ((p--&gt;ai.sub.-- si.sub.--ordinary.sub.-- ticks-1) &amp; 0xFFFFFF) &lt;&lt;0));}}{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) |= 0x0080;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (* soft.sub.-- copy.sub.--ptr));}}{{STC.sub.-- WRITE.sub.-- 16.sub.-- W(8, 0x0200);}}/* AI.sub.-- SI.sub.-- Reload.sub.-- Mode              := 6  */{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0xFF0F;(* soft.sub.-- copy.sub.-- ptr) |= 0x0060;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (* soft.sub.-- copy.sub.--ptr));}}}else{/* interval from the START1 trigger to the  *//* first start of scan is equal to the scan *//* interval       */{{STC.sub.-- WRITE.sub.-- 32.sub.-- W(14, ( ((p--&gt;ai.sub.-- si.sub.--ordinary.sub.-- ticks-1) &amp; 0xFFFFFF) &lt;&lt;0));}}/* AI.sub.-- SI.sub.-- Reload.sub.-- Mode              := 0  */{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) = 0xFF0F;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (* soft.sub.-- copy.sub.--ptr));}}{{STC.sub.-- WRITE.sub.-- 16.sub.-- W(8, 0x0200);}}}{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) *= 0xFFF7;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (* soft.sub.-- copy.sub.--ptr));}}}else{/* In the single-wire for START and CONVERT case, you need to/* set AI.sub.-- START.sub.-- Sync to 0./* The single-wire case is defined by START and CONVERT coming/* from a single external source, with the same polarity./* In other cases, it is safe to set AI.sub.-- START.sub.-- Sync to 1./* It is always safe to set AI.sub.-- START.sub.-- Edge to 1. */if( (p--&gt;ai.sub.-- start.sub.-- select == p--&gt;ai.sub.-- convert.sub.--source.sub.-- select) &amp;&amp; (p--&gt;ai.sub.-- start.sub.-- polarity != p--&gt;ai.sub.-- convert.sub.--source.sub.-- polarity))/* The inequality of the two polarities inicates that the two *//* signals are of the same polarity, since those data  *//* structure components correspond to the hardware...  */{DaqDebugPrint((&#34;AI.sub.-- START.sub.-- Sync = 0\n&#34;));/* AI.sub.-- START.sub.-- Sync            := 0    *//* AI.sub.-- START.sub.-- Edge            := 1    *//* AI.sub.-- START.sub.-- Polarity            := p--&gt;ai.sub.-- start.sub.-- polarity                         */{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[62]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0x7F80;(* soft.sub.-- copy.sub.-- ptr) |= ( ((p--&gt;ai.sub.-- start.sub.-- select) &amp; 0x1F) &lt;&lt;0)            |( ((0) &amp; 0x1) &lt;&lt;6)            |( ((1) &amp; 0x1) &lt;&lt;5)            |( ((p--&gt;ai.sub.-- start.sub.-- polarity) &amp;            0x1) &lt;&lt;15);STC.sub.-- WRITE.sub.-- 16.sub.-- W(62, (* soft.sub.-- copy.sub.--ptr));}}}else{DaqDebugPrint((&#34;AI.sub.-- START.sub.-- Sync = 1\n&#34;));/* AI.sub.-- START.sub.-- Sync            := 1    *//* AI.sub.-- START.sub.-- Edge            := 1    *//* AI.sub.-- START.sub.-- Polarity            := p--&gt;ai.sub.-- start.sub.-- polarity                         */{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[62]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0x7F80;(* soft.sub.-- copy.sub.-- ptr) |= ( ((p--&gt;ai.sub.-- start.sub.-- select) &amp; 0x1F) &lt;&lt;0)            |( ((1) &amp; 0x1) &lt;&lt;6)            |( ((1) &amp; 0x1) &lt;&lt;5)            |( ((p--&gt;ai.sub.-- start.sub.-- polarity) &amp;            0x1) &lt;&lt;15);STC.sub.-- WRITE.sub.-- 16.sub.-- W(62, (* soft.sub.-- copy.sub.-- ptr);}}}if(p--&gt;ai.sub.-- will.sub.-- have.sub.-- special.sub.-- delay){/* AI.sub.-- SI.sub.-- Write.sub.-- Switch              :=0   */{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[87]);(* soft.sub.-- copy.sub.-- ptr) |= 0x1000;STC.sub.-- WRITE.sub.-- 16.sub.-- W(87, (* soft.sub.-- copy.sub.--ptr));}{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) *= 0xFFF7;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (* soft.sub.-- copy.sub.--ptr));}}if(p--&gt;ai.sub.-- si.sub.-- will.sub.-- use.sub.-- internal.sub.-- time){/* AI.sub.-- SI.sub.-- Source.sub.-- Polarity              := 0  */{{  uInt32* soft.sub.-- copy.sub.-- ptr;  soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.--  soft.sub.-- copy[12]);  (* soft.sub.-- copy.sub.-- ptr) *= 0xF82F;  (* soft.sub.-- copy.sub.-- ptr) |= ( ((p--&gt;ai.sub.--  si.sub.-- source.sub.-- select) &amp; 0x1F) &lt;&lt;6)            |( ((0) &amp; 0x1) &lt;&lt;4);  STC.sub.-- WRITE.sub.-- 16.sub.-- W(12, (* soft.sub.-- copy.sub.--  ptr));}}}else{/* AI.sub.-- SI.sub.-- Source.sub.-- Polarity              := p--&gt;ai.sub.-- si.sub.-- source.sub.-- polarity                             */{{  uInt32* soft.sub.-- copy.sub.-- ptr;  soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.--  soft.sub.-- copy[12]);  (* soft.sub.-- copy.sub.-- ptr) &amp;= 0xF82F;  (* soft.sub.-- copy.sub.-- ptr) |= ( ((p--&gt;ai.sub.--  si.sub.-- source.sub.-- select) &amp; 0x1F) &lt;&lt;6)            |( ((p--&gt;ai.sub.-- si.sub.-- source.sub.--            polarity) &amp; 0x1) &lt;&lt;4);  STC.sub.-- WRITE.sub.-- 16.sub.-- W(12, (* soft.sub.-- copy.sub.--  ptr));}}}{{STC.sub.-- WRITE.sub.-- 32.sub.-- W(14, ( ((p--&gt;ai.sub.-- si.sub.--special.sub.-- ticks-1) &amp; 0xFFFFFF) &lt;&lt;0));}}{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0xFF7F;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (* soft.sub.-- copy.sub.--ptr));}}{{STC.sub.-- WRITE.sub.-- 16.sub.-- W(8, 0x0200);}}}else{{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[87]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0xEFFF;STC.sub.-- WRITE.sub.-- 16.sub.-- W(87, (* soft.sub.-- copy.sub.--ptr));}}} } if(p--&gt;ai.sub.-- will.sub.-- be.sub.-- staged == YES) {{{STC.sub.-- WRITE.sub.-- 32.sub.-- W(16, ( ((p--&gt;ai.sub.-- si.sub.--new.sub.-- ordinary.sub.-- ticks[0]-1) &amp; 0xFFFFFF)&lt;&lt;0));}}{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[13]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0xFF8F;STC.sub.-- WRITE.sub.-- 16.sub.-- W(13, (* soft.sub.-- copy.sub.--ptr));}}{{uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[4]);(* soft.sub.-- copy.sub.-- ptr) |= 0x0200;STC.sub.-- WRITE.sub.-- 16.sub.-- D(4, (* soft.sub.-- copy.sub.-- ptr));(* soft.sub.-- copy.sub.-- ptr) &amp;= ˜0xC3FF;}} p--&gt;ai.sub.-- si.sub.-- last.sub.-- load.sub.-- register = 1; } else { p--&gt;ai.sub.-- si.sub.-- last.sub.-- load.sub.-- register = 0; }/* AI.sub.-- Configuration.sub.-- End              := 1  */ { {uInt32* soft.sub.-- copy.sub.-- ptr;soft.sub.-- copy.sub.-- ptr = &amp;(stc--&gt;stc.sub.-- write.sub.-- soft.sub.--copy[72]);(* soft.sub.-- copy.sub.-- ptr) &amp;= 0xFEEF;(* soft.sub.-- copy.sub.-- ptr) |= 0x0100;STC.sub.-- WRITE.sub.-- 16.sub.-- W(72, (* soft.sub.-- copy.sub.--ptr));(* soft.sub.-- copy.sub.-- ptr) *= ˜0xF7CF; } }}STC.sub.-- END__________________________________________________________________________ 
    
     It can now be appreciated that the method and apparatus for programming low level hardware write-only registers provides several advantages. First, once all of the registers and bit fields are defined in a database, the input code need only include simple BFW commands to manipulate the bit fields of the hardware registers by name. The database is easily established and the BFW commands are much easier to write, resulting in improved organization and simpler source code. The use of BFW commands allows much improved organization of the bit field information, since the code refers to and manipulates individual bit fields, rather than the specific code for manipulating the entire register each time an access is necessary. A preprocessor according to the present invention provides optimization of the final source code by combining all of the bit fields within each BFW command corresponding to a register, so that only one access of the hardware register is necessary for each BFW command issued. This allows the compiled program to execute faster. Although a programmer could conceivably optimize the code manually, such manual coding is much more difficult and error prone, would consume valuable programming time and is usually not done. A preprocessor according to the present invention automates the whole process and simplifies programming of write-only registers. 
     Another programming method is to use functions to program each register. A function can simplify the source code since the code for bit manipulation is written only once, and each line of the source code to implement a function call is rather simple. The function must be generalized and sophisticated enough to program multiple bits of multiple registers, which causes a slight performance penalty if the call performs a simple operation. Although functions provided better organization for programming registers, there is a significant amount of overhead associated with functions resulting in slower operation. First, a function call forces the processor to jump to a remote location to perform the computations, and then return with the calculated parameters, thereby consuming valuable time. More significantly, a function threes all computation to be performed at run time since the same function is used to program many registers, so that the particular bits and corresponding values are not defined until runtime. If runtime performance is vital, which it often is, functions can not be used due to significant performance penalty. 
     Although the method and apparatus of the present invention has been described in connection with the preferred embodiment, it is not intended to be limited to the specific form set forth herein, but on the contrary, it is intended to cover such alternatives, modifications, and equivalents, as can be reasonably included within the spirit and scope of the invention as defined by the appended claims.