Workbook for SLD Offline Users - Writing Code: Using Jazelle from Prepmort

A Note about Using Upper Case

In all of the Jazelle function calls that you see in the following examples, you will see that we supply the family names in upper case. For example, we use:
   $CALL JZBLOC( 'PHPSUM', F_PHPSUM ) ERROR RETURN;
and not
   $CALL JZBLOC( 'phpsum', F_PHPSUM ) ERROR RETURN;
In the interests of speed, Jazelle functions do not take the time to convert the family name to upper case for you. Be sure to supply all family names to Jazelle functions as upper case.

Two Different Ways to Use Jazelle from Prepmort

The method of using Jazelle from Prepmort that you have seen so far, based on the use of pointers, was the originally method. It conforms to general ideas of what a modern programming language should do. Most other modern languages, such as C, use the same ideas. But because so many of the physicists in the SLD collaboration come from a Fortran background, demands were made for a method of using Jazelle that looks more like Fortran. There was a major fight over this issue. Jazelle's creator, Tony Johnson, wanted nothing to do with this method. But he was eventually forced to compromise, and so a second method of using Jazelle from Prepmort was implemented alongside the first method.

The first method, the one that works like a modern programming language, is referred to as the "pointer" method. The second method, the one that works like Fortran, is referred to as the "indexed pointer" method. It is also sometimes referred to as the "usebank" menthod, since one of the statements required to in this method is the USEBANK statement.

We recommend you use the "pointer" method whenever you have a choice. Learn about the "indexed pointer" method just so you can recognize and debug it in other peoples code.

The Pointer Method

Before you can use the pointer method, your routine must include the signpost common block JAZELLE by including the following statement:
   "&COMMON /JAZELL/"
This sets up the basic structure necessary to make pointers work.

This statement can not have any spaces before it. It is, in that sense, different from any other kind of Prepmort statement.

Some routines do the same thing with the statement:

   "&COPY FROM JAZELL.COMMON"
Again, this statement can not have any spaces before it. The general rule is, statements that begin with the two characters "& can not have spaces before them.

Don't worry about how these statements work. Just make sure your routine contains one of them.

Pointer Method: Declaring a Pointer

Before you can use a particular pointer, you must declare it with a POINTER statement in the declarations part of your routine. For example:
   POINTER P_IEVENTH --> IEVENTH;
The name of the pointer can be any string of up to eight characters.

People often start their pointers with the characters P_. After the underscore they put the name of the Jazelle family that this pointer works with. This is just a convention to make it clear that the variable in question is a pointer and to tell what bank it points to. But this is not required.

You could have your pointer be something less helpful such as

   POINTER A --> IEVENTH;

Since one often sets up a pointer just to point at the head of a family, some people use the convention F_ for a pointer that points to the head of a family. For example, they might use:

   POINTER F_PHPSUM --> PHPSUM;

Pointer Method: Finding the Head of a Family

To set a pointer to the head of a family, call the routine JZBLOC. For example:
   $CALL JZBLOC( 'PHPSUM', F_PHPSUM ) ERROR RETURN;

Pointer Method: Finding the Total Number of Banks in a Family

To find the total number of banks in a family, receive one more variable from the routine JZBLOC. For example:
   $CALL JZBLOC( 'PHPSUM', F_PHPSUM, NPHPSUM ) ERROR RETURN;
NPHPSUM will then be the number of PHPSUM banks.

Pointer Method: Finding a Pointer to the First Bank in a Family

To set a pointer to the first bank in a family, call the routine JZBFND. For example:
   $CALL JZBFND( 'PHPSUM', P_PHPSUM ) ERROR RETURN;
P_PHPSUM will then point to the first bank in the family.

Pointer Method: Finding a Pointer to the Last Bank in a Family

To set a pointer to the last bank in a family, call the routine JZBFND but with some additional arguments. For example:
   $CALL JZBFND( 'PHPSUM', P_PHPSUM, IDOUT, 'LAST' ) ERROR RETURN;
P_PHPSUM will then point to the last bank in the family. This function returns the extra variable IDOUT which is the bank ID of the bank that is found. This will be zero if no bank is found.

If that last argument is 'FRST' instead of 'LAST', you get the first bank of the family. For example:

   $CALL JZBFND( 'PHPSUM', P_PHPSUM, IDOUT, 'FRST' ) ERROR RETURN;
As you have already seen, you get the same result by default when you leave out the last two arguments.

Pointer Method: Finding a Particular Bank in a Family

To set a pointer to a particular bank in a family, call the routine JZBFND with the bank ID as the fourth argument. For example:
   IDIN = 4;
   $CALL JZBFND( 'PHPSUM', P_PHPSUM, IDOUT, IDIN ) ERROR RETURN;
P_PHPSUM will then point to the 4th bank in the family. This function returns the extra variable IDOUT which is the bank ID of the bank that is found. This will be 4 if the bank we were looking for was found or will be zero if the 4th bank did not exist.

Pointer Method: Getting the Bank ID from the Pointer

To find the ID of a bank, given the pointer, use the %(JB$ID) construction. For example:
   IPH = P_PHPSUM%(JB$ID);
IPH will then be the ID of the bank pointed to by P_PHPSUM.

Pointer Method: Moving a Pointer Ahead One Bank

To move a pointer ahead one bank, use the JB$FORPT construction. For example:
   P_PHPSUM = P_PHPSUM%(JB$FORPT);

Pointer Method: Looping Over All Banks in a Family

To loop over all banks in a family, use the BANKLOOP construction.

This construction requires that you first declare two pointers to the family and that you set one of these pointers to the head of the family.

   POINTER F_PHPSUM --> PHPSUM,
           P_PHPSUM --> PHPSUM;

   LOGICAL FIRST /.TRUE./;

   IF FIRST
   [
     $CALL JZBLOC( 'PHPSUM', F_PHPSUM ) ERROR RETURN;
     FIRST = .FALSE. ;
   ]
The following construction will cause P_PHPSUM to point to each PHPSUM bank in turn:
   BANKLOOP F_PHPSUM, P_PHPSUM
      ... your code here
   ENDLOOP

Pointer Method: Accessing a Jazelle Variable

To access a Jazelle variable, use the pointer followed by the percent sign. For example:
   CHARGE = P_PHPSUM%(CHARGE);

Pointer Method: Following a Pointer in One Bank to a Pointer in Another

The full power of working with pointers becomes clear when you try to follow them from one bank to another bank.

Here is an example in which we get a variety of information about a particular particle by following pointers from one bank to another:

   POINTER P_PHPSUM  --> PHPSUM,
           P_PHPOINT --> PHPOINT,
           P_PHCHRG  --> PHCHRG,
           P_PHKLUS  --> PHKLUS;

   " Assume that our particle of interest is pointed to by P_PHPSUM "

   CHARGE = P_PHPSUM%(CHARGE);

   P_PHPOINT = P_PHPSUM%(PHPOINT);  "PHPSUM contains a pointer to PHPOINT"

   P_PHCHRG  = P_PHPOINT%(PHCHRG);  "PHPOINT contains a pointer to PHCHRG"
   IMPACT = P_PHCHRG%(IMPACT);

   P_PHKLUS  = P_PHPOINT%(PHKLUS);  "PHPOINT contains a pointer to PHKLUS"
   ERAW = P_PHKLUS%(ERAW);

The Indexed Pointer Method

Before we tell you how to set up a routine to work with the indexed pointer method, let us show you what the code looks like to access a Jazelle variable using this method.

Here is an example. The charge of the second PHPSUM partcle can be found as follows:

   CHARGE = PHPSUM(2)%(CHARGE);
The charge of the fifth PHPSUM particle can be found as follows:
   CHARGE = PHPSUM(5)%(CHARGE);
A variable can be used an the index as follows:
   CHARGE = PHPSUM(IPART)%(CHARGE);
where IPART would be some integer variable.

You see that instead of having a standard pointer on the left side of the percent sign, you instead have something that looks like an old fashioned Fortran array. This is comforting to people who are very used to Fortran, but is much less powerful than the regular pointer method.

The method works by having you first create an array called PHPSUM which contains all of the pointers to all of the PHPSUM banks.

Indexed Pointer Method: Limitations

The indexed pointer method can only be used with Jazelle families that have a MAXID set in their templates. This MAXID tells Jazelle the maximum number of banks that can ever exist for this family. Jazelle needs this information in order to set up some memory where it will store an index of pointers for this family.

An example of a bank that can be used with indexed pointers is PHPSUM. It contains the line:

   Bank PHPSUM Context=DST Maxid=1000 "Particle parameters"
Some banks can not be used with indexed pointers since they do not have a MAXID set in their templates. When a bank is not going to be used with indexed pointers, there is no need for Jazelle to set up an index in advance. The user is free to make any number of banks in that family.

An example of a bank that can not be used with indexed pointers is PHMTOC. It contains the line:

   Bank PHMTOC CONTEXT=JAZELLE NOMAXID

When you use only the indexed pointer method in your routine, your routine does not need to include the statement

   "&COMMON /JAZELL/"
But it does not hurt if you accidentally include it.

You save including that one line, but you need to include some other things that are much worse.

When you need to use constructions that involve banks that point to banks that point to other banks, you will find the pointer method much easier to use than the indexed pointer method.

Indexed Pointer Method: Declaring an Indexed Pointer Array

Before you can use a particular family with the indexed pointer method, you must do two things. You must declare the appropriate indexed pointer array and you must fill the appropriate indexed pointer array.

You declare the indexed pointer array by putting a $USEBANK statement in the declarations part of your routine. For example:

   $USEBANK PHPSUM;
This statement includes an indexed pointer array, called PHPSUM, which contains one pointer for each bank in the PHPSUM family.

You then fill the indexed pointer array with a call to the routine JZPIDX. For example:

   $CALL JZPIDX( 'PHPSUM', PHPSUM ) ERROR RETURN;

This routine must be called only once for each family that is to be used with indexed pointers. If someone else has already made this call in their routine, your routine may not need this call. But it does not hurt to call it a second time.

If you try to access a bank using indexed pointers and the appropriate JZPIDX call has never been made, your routine will crash. So it is best to include such a call in an IF FIRST block at the start of your routine.

The pointer to the first bank will then be PHPSUM(1).

The pointer to the second bank would be PHPSUM(2).

And, as mentioned above, you could access a Jazelle variable as follows:

   CHARGE = PHPSUM(2)%(CHARGE);

Indexed Pointer Method: Finding the Total Number of Banks in a Family

To find the total number of banks in a family, use the special variable, J$NUMBER. This variable does not use the percent sign. For example:
   NCHARGE = PHPSUM(J$NUMBER);

Indexed Pointer Method: Finding the First Bank in a Family

To find the first bank in a family (which may not necessarily be bank ID 1), use the special variable, J$FIRST. For example:
   FIRSTID = PHPSUM(J$FIRST);
Note that this construction does not include the percent sign. That is because this value is not a variable in a bank, it is a variable that tells about the banks.

Indexed Pointer Method: Finding the Last Bank in a Family

To find the last bank in a family, use the special variable, J$LAST. For example:
   LASTID = PHPSUM(J$LAST);
Again note that this construction does not include the percent sign.

Indexed Pointer Method: Looping Over All Banks in a Family

To loop over all banks in a family, use the above ideas about J$FIRST and J$LAST.

For example:

   DO ITRACK = PHPSUM(J$FIRST), PHPSUM(J$LAST)
   [
      ... your code here
   ]

Mixing The Two Different Ways of Using Jazelle from Prepmort

Since the indexed pointer array is actually just an array of pointers, you will occasionally see code in which pointers are passed back and forth between the two different methods.

To fill a regular pointer from an indexed pointer, just use =. For example:

   P_PHPSUM = PHPSUM(22);
The above would set the pointer P_PHPSUM to point to the 22nd PHPSUM bank.
  P_PHPSUM = PHPSUM(J$LAST);
The above would set the pointer P_PHPSUM to point to the last PHPSUM bank.

To find the indexed pointer that matches a regular pointer, use the %(JB$ID) construction. For example:

   IPH = P_PHPSUM%(JB$ID);
   CHARGE = PHPSUM(IPH)%(CHARGE);

Adding, Deleting and Copying Jazelle Banks from Prepmort

A set of functions are available which you can call from Prepmort to add, delete or copy banks. A few of the most commonly used are as follows:

Adding Banks

Call the routine JZBADD to add a bank.

For example, the following would add a KTAG bank, returning its pointer as P_KTAG:

    $CALL JZBADD( 'KTAG', P_KTAG ) ERROR RETURN;

Deleting Banks

Call the routine JZBPDEL to delete a bank.

For example, the following would delete the KTAG bank pointed to by P_KTAG:

    $CALL JZPDEL( P_KTAG ) ERROR RETURN;
There is also the routine JZBDEL to delete a bank given its family name and bank ID rather than its pointer.

For example, the following would delete the KTAG bank with ID of IKTAG:

   $CALL JZBDEL( 'KTAG', IKTAG ) ERROR RETURN;
If the second argument is deleted, all banks of the given family are deleted.

For example, the following would delete all KTAG banks from the current event:

   $CALL JZBDEL( 'KTAG' ) ERROR RETURN;

Copying Banks

Call the routine JZPCPY to copy a bank to a new bank, leaving the old bank unchanged.

For example, the following would copy the KTAG bank pointed to by P_OLDKTAG to a new bank pointed to by P_NEWKTAG:

   $CALL JZPCPY( P_OLDKTAG, P_NEWKTAG ) ERROR RETURN;

See the Jazelle Manual for More Information

The Jazelle manual is one of the best pieces of documentation in SLD. It describes many more commands than have been listed here and gives additional optional arguments for the commands you have learned.

The Jazelle Manual is available nicely bound from SLAC Publications as SLAC Report 362 and can also be obtained from the SLD Offline Software Documentation Center, SLAC Central Lab Annex Room B105. At least one copy belongs in every SLD bookshelf.


Back to Writing Code

Joseph Perl
14 February 1995