Trailing-Edge
-
PDP-10 Archives
-
decuslib10-05
-
43,50337/24/pack.mac
There are 2 other files named pack.mac in the archive. Click here to see a list.
COMMENT * SIMULA specification;
OPTIONS(/E:CODE,NOCHECK,packent);
BOOLEAN PROCEDURE pack;
!*;! MACRO-10 code !*;!
TITLE pack
SUBTTL SIMULA utility, PACK procedure
;!*** Copyright 1975 by the Swedish Defence Research Institute. ***
;!*** Copying is allowed. ***
;!Author: Stephan Oldgren, ENEA, Sept 1975
;!Modified by: Lars Enderin, FOA, Jan 1976
;!Version: 3A [150]
;!Purpose: external procedure to pack data in a
;! SIMULA program
;!Contents: PUCCS convert character from ASCII to SIXBIT
;! PUPI pack INTEGER, BOOLEAN and CHARACTER
;! PUPL pack LONG REAL
;! PUPR pack REAL
;! PUPT pack TEXT
;! PUSPV store packed variable
;! MAINPROGRAM procedure control
SEARCH SIMMAC,SIMMCR,SIMRPA
SALL
MACINIT
ENTRY PACKENT
;! Offsets in procedure block
result==ZBI%S ;! Function value
PAREA== result+1 ;! Parameter (ZFL) for packed area
PBYP== PAREA+2 ;! ZFL for number of bits to bypass in packed area
UAREA== PBYP+2 ;! ZFL for unpacked area (array or variable)
ISIZE== UAREA+2 ;! ZFL for item size (bits)
;! Ac assignments
XIND= 3 ;! Offset of current UAREA relative to first UAREA (0,2,4 etc)
XPADR= 4 ;! Address (dynamic) of packed area
XPMAX= 5 ;! Max offset relative to XPADR or max XPADR value
XPOFF= 6 ;! Current bit offset within packed area
XPBYP= 7 ;! Number of bits to bypass in current packed word
XUTYP= XPBYP ;! Type of unpacked area
XUADR= 10 ;! Address (dynamic) of unpacked area (UAREA)
XUMAX= 11 ;! Max offset or address in UAREA
XUNBY= XUMAX ;! Number of bytes left in unpacked area
XSIZ= 12 ;! Bit size of packed item
XUBYT= 1 ;! Number of bytes to skip in unpacked text
XA= 0 ;! Work ac
XB= XUBYT ;! - " -
XC= 2 ;! - " -
XD= XPBYP ;! - " -
XE= 13 ;! - " -
XF= 14 ;! - " -
XAREA= 16 ;! Used to save XUADR, XUMAX in PUUT
XG= XAREA ;! Work ac, also JSP ac for NEXT and ERROREXIT (simplifies debug)
;! CONSTANTS DEFINITIONS
QWL= ^D36 ;!word length
QHWL= QWL/2 ;!half word length
QQWL= QWL/4 ;!quarter word length
QDWL= QWL*2 ;!double word length
QBYA= 7 ;!byte length ASCII
QBYS= 6 ;!byte length SIXBIT
QNBA= 5 ;!number of bytes in one word ASCII
OPDEF ERROREXIT [JSP XG,NOGOOD]
OPDEF NEXT [JSP XG,NEXT]
OPDEF STOREPACKED [PUSHJ XPDP,PUSPV]
;! ERROR MESSAGES
ERPM1::! ASCIZ/Parameter missing in PACK/
SUBTTL PUPI
;!Purpose: pack routine for variable of type integer,boolean
;! or character
;! packing is done by deleting the necessary bits to
;! the right of the sign bit
;!Entry: PUPI
;!Input arguments: XPADR address of block instance of area to
;! pack data into
;! XPMAX max offset of area to pack into
;! XPOFF start offset of area to pack into
;! XUADR address of area to be packed
;! XUMAX max address of area to be packed
;! XSIZ size of packed variable
;!Normal exit: NEXT
;! XUTYP contains type of variable
;!Error exit: ERROREXIT (BRANCH NOGOOD)
;!Output arguments: XPOFF (see above) now points at first bit
;! after the now packed variable
;!Call format: EXEC PUPI
;!Used subroutine: PUSPV
PUPI: PROC
;!compute number of bits to be deleted in each element
LI XC,QWL
SUB XC,XSIZ
;!construct bit mask with zeroes in place of the packed
;!variable and ones in the rest
SETO XE,
LSH XE,(XC)
SETCA XE,XE
WHILE ;! there are any elements left in the variable
CAMLE XUADR,XUMAX
GOTO FALSE
DO
;!load element and increment address
L XA,(XUADR)
ADDI XUADR,1
IF ;! CHARACTER
CAIE XUTYP,QCHARACTER
GOTO FALSE
THEN
LSH XA,(XC)
ELSE ;! BOOLEANs or INTEGERs
;!initialize XB with sign bit from XA
;!pack the variable to the left part of the word XA
;!the truncated bits are moved into XB
SETZ XB, ;! [211]
SKIPGE XA ;! [211]
SETO XB,
ROTC XA,1(XC)
MOVN XC,XC
ROT XB,(XC)
MOVM XC,XC
ROTC XA,-1
ANDCM XA,XE
IF ;! NOT BOOLEAN
CAIN XUTYP,QBOOLEAN
GOTO FALSE
THEN ;! ERROR if truncated bits are significant
JUMPG XB,NOGOOD
AOJL XB,NOGOOD
FI FI
STOREPACKED
ERROREXIT ;! If something was wrong
OD
NEXT
EPROC
SUBTTL PUPL
;!Purpose: pack routine for variable of type long real
;! packing is done by deleting necessary bits
;! at the end of each element
;!Entry: PUPL
;!Input arguments: XPADR address of block instance of area to
;! pack data into
;! XPMAX max offset of area to pack into
;! XPOFF start offset of area to pack into
;! XUADR address of area to be packed
;! XUMAX max address of area to be packed
;! XSIZ size of packed variable
;!Normal exit: NEXT
;!Error exit: ERROREXIT
;!Output arguments: XPOFF (see above) now points at first bit
;! after the now packed variable
;!Call format: EXEC PUPL
;!Used subroutine: PUSPV
PUPL: PROC
;!if size of packed field not greater than word length
;!skip the second word of every element and treat
;!only the first word
;!else treat both words
IF
CAILE XSIZ,QWL
GOTO FALSE
THEN
;!make a bit mask with zeroes in bits corresponding
;!to the packed variable and ones in the rest
SETO XE,
LI XF,QWL
SUB XF,XSIZ
LSH XE,(XF)
SETCA XE,XE
;!while there are remaining elements in the variable
WHILE
CAMLE XUADR,XUMAX
GOTO FALSE
DO
;!load first word of element and increment address
L XA,(XUADR)
ADDI XUADR,2
ANDCM XA,XE ;!delete necessary bits to the right
STOREPACKED
ERROREXIT
OD
ELSE
;!make a bit mask with zeroes in bits corresponding
;!to the packed variable and ones in the rest
SETO XF,
LI XE,QWL
SUB XE,XSIZ
LSH XF,(XE)
SETZ XE,
;! save XSIZ-word length
L XC,XSIZ
SUBI XC,QWL
HRLM XC,(XPDP)
;!while there are remaining elements in variable
WHILE
CAMLE XUADR,XUMAX
GOTO FALSE
DO ;!load first word of element
;!store the whole word in area
;!to pack data into
L XA,(XUADR)
SETZ XE, ;!make bit mask
LI XSIZ,QWL
EXEC PUSPV
ERROREXIT
;!error return if second word of element is
;!outside the variable
CAILE XUADR,1(XUMAX)
ERROREXIT
;!load second word of element and increment address
IF ;! Special place
CAIE XUADR,PBYP+1(XCB)
GOTO FALSE
THEN ;! Take 2nd word from ZFL for UAREA
LI XA,UAREA+1(XIND)
ADDI XA,(XCB)
L XA,@XA
ELSE ;! take it from next word
L XA,1(XUADR)
FI
ADDI XUADR,2
HLRZ XSIZ,(XPDP)
L XE,XF
ANDCM XA,XE ;! Delete bits to the right
STOREPACKED
ERROREXIT
OD
FI
NEXT
EPROC
SUBTTL PUPR
;!Purpose: pack routine for variable of type real
;! packing is done by deleting necessary bits
;! at the end of each element
;!Entry: PUPR
;!Input arguments: XPADR address of block instance of area to
;! pack data into
;! XPMAX max offset of area to pack into
;! XPOFF start offset of area to pack into
;! XUADR address of area to be packed
;! XUMAX max address of area to be packed
;! XSIZ size of packed variable
;!Normal exit: NEXT
;!Error exit: ERROREXIT
;!Output arguments: XPOFF (see above) now points at first bit
;! after the now packed variable
;!Call format: EXEC PUPR
;!Used subroutine: PUSPV
;!
PUPR: PROC
;!make bit mask with zeroes in the place of
;!the packed variable and ones in the rest
SETO XE,
LI XF,QWL
SUB XF,XSIZ
LSH XE,(XF)
SETCA XE,XE
;!while there are remaining elements in the variable
WHILE
CAMLE XUADR,XUMAX
GOTO FALSE
DO
;!load variable and increment address
L XA,(XUADR)
ADDI XUADR,1
ANDCM XA,XE ;! Delete bits to the right
STOREPACKED
ERROREXIT
OD
NEXT
EPROC
SUBTTL PUPT
;!Purpose: pack routine for variable of type text
;! packing is done by converting each character
;! to sixbit or by moving the whole character to output
;!Entry: PUPT
;!Input arguments: XPADR address of block instance of area to
;! pack data into
;! XPMAX max offset of area to pack into
;! XPOFF start offset of area to pack into
;! XUADR address of text specification
;! XUMAX max address of text specification
;! XSIZ size of packed field
;!Normal exit: NEXT
;!Error exit: ERROREXIT
;!Output arguments: XPOFF (see above) now points at first bit
;! after the now packed variable
;!Call format: EXEC PUPT
;!Used subroutine: PUSPV
PUPT: PROC
;!make bit mask for SIXBIT or ASCII character
SETZ XF,
SETO XE,
IF
CAIE XSIZ,6
GOTO FALSE
THEN
ROTC XE,-QBYS
ELSE
ROTC XE,-QBYA
FI
WHILE
CAMLE XUADR,XUMAX
GOTO FALSE
DO
;!save address
L XAREA,XUADR
HRL XAREA,XUMAX
L XUADR+1,XUADR
LD XUADR,(XUADR+1)
;!error exit if text specification empty
JUMPE XUADR,NOGOOD
HLRZ XA,XUADR
HLLI XUADR,0
HLRZ XUNBY,XUNBY
;!compute start address
IDIVI XA,QNBA
ADDI XA,2
ADD XUADR,XA
;!observe that XB=XUBYT now contains number of bytes to be
;!bypassed before start of text in the word(XUADR)
;!initiate counter for number of bytes in one word and
;!byte pointer to text variable
L XF,[POINT QBYA,(XUADR)]
;!move byte pointer to first byte to be treated
IF JUMPLE XUBYT,FALSE
THEN
LOOP IBP XF
AS SOJG XUBYT,TRUE
SA
FI
WHILE ;! Bytes remain in text variable
JUMPLE XUNBY,FALSE
DO
;!load byte with ASCII character
;!convert to SIXBIT and store in
;!area to pack data into
ILDB XA,XF
SUBI XUNBY,1
IF
CAIE XSIZ,6
GOTO FALSE
THEN
SUBI XA,40 ;! Convert to SIXBIT
IF ;! In range
JUMPLE XA,FALSE
CAILE XA,137
GOTO FALSE
THEN ;! Subtract 40 again for lower case
CAILE XA,77
SUBI XA,40
ROT XA,-QBYS ;! Place in 1st byte
ELSE ;! Convert to SIXBIT space char
SETZ XA,
FI
ELSE
ROT XA,-QBYA
FI
STOREPACKED
ERROREXIT
OD
;!reinitialize address to text specification and increment
;!it to point at the next text element if any
HRRI XUADR,2(XAREA)
HLR XUMAX,XAREA
OD
NEXT
EPROC
LIT
SUBTTL PUSPV
;!;!
;!Purpose: store packed variable in area to pack data into
;!Entry: PUSPV
;!Input arguments: XPADR address of block instance of area to
;! pack data into
;! XPMAX max offset of area to pack into
;! XPOFF start offset of area to pack into
;! XSIZE size of packed variable
;! XA packed element left adjusted
;! XE bit mask corresponding to packed element
;! with zeroes in place of packed element
;! and ones in the rest
;!Normal exit: SKIP RETURN
;!Error exit: RETURN with PACK = 0 (false)
;!Output arguments: XPOFF (see above) now points at first bit
;! after the now packed element
;!Call format: STOREPACKED (EXEC PUSPV)
;!Used subroutine: PUSPV
PUSPV: PROC
SAVE <XE,XF,XPBYP>
N==3 ;! Number of words saved
;!error return if overflow in area to pack data into
L XC,XPOFF
ADD XC,XSIZ
CAMLE XC,XPMAX
GOTO L9
;!make a word offset from the bit offset
IDIVI XPOFF,QWL
;!now XPOFF contains word offset and
;!XPOFF+1 = XPBYP contains number of bits to be bypassed
;!compute address to area to pack data into and store it in XPOFF
ADD XPOFF,XPADR
SETZ XB,
SETO XF,
;!rotate packed variable and bit mask to position
;!defined by XPBYP
MOVN XPBYP,XPBYP
ROTC XA,(XPBYP)
ROTC XE,(XPBYP)
MOVM XPBYP,XPBYP
;!move corresponding part of packed variable to first word
;!of area to pack data into
L XC,(XPOFF)
AND XC,XE
IOR XC,XA
ST XC,(XPOFF)
;!increment bit pointer with size of packed variable
ADD XPBYP,XSIZ
IF ;! the whole variable is not yet treated
CAIGE XPBYP,QWL
GOTO FALSE
THEN ;! Increment offset
ADDI XPOFF,1
SUBI XPBYP,QWL
IF ;! More bits left
JUMPE XPBYP,FALSE
THEN ;! Must pack rest into next word
L XC,(XPOFF)
AND XC,XF
IOR XC,XB
ST XC,(XPOFF)
FI FI
AOS -N(XPDP) ;! Ok, Skip return
L9():! ;!reset offset to bit offset
SUB XPOFF,XPADR
IMULI XPOFF,QWL
ADD XPOFF,XPBYP
RETURN
EPROC
SUBTTL MAINPROGRAM
;!Purpose: To pack a number of variables defined by a
;! SIMULA program into another variable also
;! defined by the SIMULA program
;!Entry: PACKENT
;!Used subroutines: PUPI pack integer,boolean or character
;! PUPL pack long real
;! PUPR pack real
;! PUPT pack text
;!
PACKENT:;! Execution starts here for PACK routine
SETOM result(XCB) ;! Assume true result as a start
SETZ XIND,
IF ;! ISIZE was not given
SKIPE ISIZE(XCB)
GOTO FALSE
THEN ;! Error, not enough parameters
OUTSTR ERPM1
RTSERR QDSCON,214
ERROREXIT
FI
SETZB XE,XB
;!read parameters for area to pack data into and number of bits
;!to be bypassed at the beginning of that area
;!ie the first two parameters
BEGIN
;!error exit if area to pack data into is a constant or an
;!expression
LF XA,ZFLDTP(XCB,PAREA)
CAIL XA,QDTCON
ERROREXIT
;!check type of area
;!error exit if not REAL,LONG REAL,INTEGER,BOOLEAN
;!** GETTYPE XD,PAREA
LF XD,ZFLATP(XCB,PAREA)
CAIG XD,QBOOLEAN
CAIN XD,QCHARACTER
ERROREXIT
;!check kind of area,error exit if not ARRAY or SIMPLE
;!** GETKIND XE,PAREA
LF XE,ZFLAKD(XCB,PAREA)
IF ;! NOT array
CAIN XE,QARRAY
GOTO FALSE
THEN ;! Must be simple variable
CAIE XE,QSIMPLE
ERROREXIT
;!treat simple variable
;!load dynamic address and compute max bit offset and bit offset
;!to first bit in variable
;!** GETADD PAREA,<XPADR-XWAC1>
IF ;! No thunk
SKIPL PAREA(XCB)
GOTO FALSE
THEN ;! Get address the easy way
LF XPADR,ZFLZBI(XCB,PAREA)
HRL XPADR,PAREA+1(XCB)
ELSE ;! Use PHFA
LI XPADR,(XCB)
HRLI XPADR,PAREA
EXEC PHFA
XWD XPADR-XWAC1,[0]
FI
HLRZ XPMAX,XPADR
CAIN XD,QLREAL
ADDI XPMAX,1
IMULI XPMAX,QWL
ADDI XPMAX,QWL
HLRZ XPOFF,XPADR
IMULI XPOFF,QWL
HLLI XPADR
ELSE ;!treat array variables
;!load dynamic address and compute number of bits in array
;!** GETAADD PAREA,3
IF ;! No thunk
SKIPL PAREA(XCB)
GOTO FALSE
THEN ;! Get address the easy way
LF XPADR,ZFLZBI(XCB,PAREA)
ADD XPADR,PAREA+1(XCB)
L XPADR,(XPADR)
ELSE ;! Use PHFM
LI XPADR,(XCB)
HRLI XPADR,PAREA
EXEC PHFM
XWD XPADR-XWAC1,[0]
FI
LF XPMAX,ZARLEN(XPADR)
IMULI XPMAX,QWL
;!compute offset to first element
LF XPOFF,ZARSUB(XPADR)
IMULI XPOFF,3*QWL
ADDI XPOFF,3*QWL
FI
;!read parameter for number of bits to be bypassed
;!at the beginning of area to pack data into
;!error exit if not simple integer
;!** GETTYPE XC,PBYP
LF XA,ZFLAKD(XCB,PBYP)
LF XC,ZFLATP(XCB,PBYP)
CAIN XA,QSIMPLE
CAIE XC,QINTEGER
ERROREXIT
;!** GETVAL PBYP,6,<XPADR>
IF ;! No thunk
SKIPL PBYP(XCB)
GOTO FALSE
THEN ;! Simple value access
LF XPBYP,ZFLZBI(XCB,PBYP)
ADD XPBYP,PBYP+1(XCB)
L XPBYP,(XPBYP)
ELSE ;! Do it the hard way
LI XPBYP,(XCB)
HRLI XPBYP,PBYP
EXEC PHFV
XWD XPBYP-XWAC1,[1B<XPADR-XWAC1>]
FI
;!error exit if negative value
JUMPL XPBYP,NOGOOD
;!add number of bits to bypass to offset
ADD XPOFF,XPBYP
;!
;!now the contents of the registers are as follows
;! XPADR block instance of area to pack into
;! XPMAX max bit offset
;! XPOFF bit offset to first bit in area to pack into
;!
ENDD
GETNXT: ;!read parameters for area to pack and size of packed variable
;!ie the next two parameters
;!XIND contains index to parameter table
BEGIN
;!check type of area,
;!error exit if not REAL,LONG REAL,INTEGER,BOOLEAN,
;!CHARACTER or TEXT
;!** GETTYPE XUTYP,UAREA,XIND
LI XUADR,UAREA(XIND)
ADDI XUADR,(XCB)
LF XUTYP,ZFLATP(XUADR)
CAILE XUTYP,QTEXT
ERROREXIT
;!check kind of area,error exit if not ARRAY or SIMPLE
;!** GETKIND XE,UAREA,XIND
LF XE,ZFLAKD(XUADR)
IF ;! Not array
CAIN XE,QARRAY
GOTO FALSE
THEN ;! Must be simple
CAIE XE,QSIMPLE
ERROREXIT
;!treat simple variable
;!load value and store it, if necessary, then set XUADR
;!to point at first word of value
;!** GETVAL UAREA(XIND),7,<XPADR>
IF ;! No thunk
SKIPL (XUADR)
GOTO FALSE
THEN ;! Get dynamic address
HRL XUADR,1(XUADR)
HRR XUADR,(XUADR)
ELSE ;! Compute value to ac's first
HRLI XUADR,UAREA(XIND)
HRRI XUADR,(XCB)
EXEC PHFV
XWD XUADR-XWAC1,[1B<XPADR-XWAC1>]
IF ;! TEXT
CAIE XUTYP,QTEXT
GOTO FALSE
THEN ;! Change ZFL to ZTV
;! Garbage collector does not care
LI XB,UAREA(XIND)
ADDI XB,(XCB)
STD XUADR,(XB)
LI XUADR,(XCB)
HRLI XUADR,UAREA(XIND)
ELSE ;! Save first word in PBYP+1
ST XUADR,PBYP+1(XCB)
IF ;! LONG REAL
CAIE XUTYP,QLREAL
GOTO FALSE
THEN ;! Also use 2nd word of this par ZFL
LI XB,UAREA(XIND)
ADDI XB,(XCB)
ST XUADR+1,1(XB)
LI XUADR,(XCB)
HRLI XUADR,UAREA(XCB)
FI FI FI
HLRZ XUMAX,XUADR
CAIE XUTYP,QLREAL
CAIN XUTYP,QTEXT
ADDI XUMAX,1
ELSE ;!treat array variables
;!load dynamic address and compute max offset and start offset
;!** GETAADD UAREA(XIND),7,<XPADR>
IF ;! No thunk
SKIPL (XUADR)
GOTO FALSE
THEN ;! Simple computation of array address
LF XB,ZFLZBI(XUADR)
ADD XB,1(XUADR)
L XUADR,(XB)
ELSE ;! Use PHFM
LI XUADR,(XCB)
HRLI XUADR,UAREA(XIND)
EXEC PHFM
XWD XUADR-XWAC1,[1B<XPADR-XWAC1>]
FI
LF XUMAX,ZARLEN(XUADR)
SUBI XUMAX,1
LF XE,ZARSUB(XUADR)
IMULI XE,3
ADDI XE,3
HRL XUADR,XE
FI
;!read argument for size of packed variable
;!error exit if not of type integer and of kind simple or
;!if size greater than double word length for long real variables or
;! greater than word length for other variables
;!** GETTYPE XE,ISIZE,XIND
LI XSIZ,ISIZE(XIND)
ADDI XSIZ,(XCB)
LF XB,ZFLAKD(XSIZ)
LF XE,ZFLATP(XSIZ)
CAIN XE,QINTEGER
CAIE XB,QSIMPLE
ERROREXIT
;!** GETVAL ISIZE(XIND),11,<XPADR,XUADR>
IF ;! No thunk
SKIPL (XSIZ)
GOTO FALSE
THEN ;! Simple evaluation
LF XB,ZFLZBI(XSIZ)
ADD XB,1(XSIZ)
L XSIZ,(XB)
ELSE ;! Use PHFV
LI XSIZ,(XCB)
HRLI XSIZ,ISIZE(XIND)
EXEC PHFV
XWD XSIZ-XWAC1,[1B<XPADR-XWAC1>+1B<XUADR-XWAC1>]
FI
;!error exit if size is as follows:
;!type of var greater than less than
;!INTEGER WORD LENGTH 2
;!REAL - " - 10
;!CHARACTER - " - 7
;!BOOLEAN - " - 1
;!LONG REAL DOUBLE WORD LENGTH 10
;!TEXT 7 6
L XB,SIZTAB-1(XUTYP)
HLRZ XB
CAIL XSIZ,(XB)
CAMGE XSIZ
ERROREXIT
;!change dynamic address to real address and max offset to max address
HLRZ XE,XUADR
HLLI XUADR,
ADD XUMAX,XUADR
ADD XUADR,XE
;!now the contents of the ac's are as follows
;! XUTYP type of area to pack
;! XUADR address of first word of area to pack
;! or if text, address to first text specification
;! XUMAX max address of area to pack (not if text)
;! or if text, max address of text specifications
;! XSIZ size of packed variable
;!
ENDD
;!select correct subroutine for each type of variable
XCT ROUTAB-1(XUTYP)
NEXT: ;!Check for more arguments
ADDI XIND,2*2 ;! Step to next UAREA, ISIZE pair
LI XB,(XCB)
ADDI XB,(XIND)
SKIPN UAREA(XB)
GOTO FINISH
IF ;! There is room for both UAREA and ISIZE parameters
Q==2*<<^D31/2>*2-4>
CAILE XIND,Q
GOTO FALSE
THEN ;! Handle next pair if ISIZE is given
SKIPE ISIZE(XB)
GOTO GETNXT
FI
;! *** ERROR, wrong number of parameters *** ;!
OUTSTR ERPM1
RTSERR QDSCON,214
NOGOOD: SETZM result(XCB)
GOTO FINISH
FINISH=CSEP
SIZTAB: XWD QWL,2 ;! INTEGER
XWD QWL,10 ;! REAL
XWD 2*QWL,10 ;! LONG REAL
XWD QWL,7 ;! CHARACTER
XWD QWL,1 ;! BOOLEAN
XWD 7,6 ;! TEXT
ROUTAB: BRANCH PUPI
BRANCH PUPR
BRANCH PUPL
BRANCH PUPI
BRANCH PUPI
BRANCH PUPT
LIT
END;