Trailing-Edge
-
PDP-10 Archives
-
bb-h138f-bm
-
7-sources/ipagen.mac
There are 2 other files named ipagen.mac in the archive. Click here to see a list.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.189 29-Sep-87 18:02:25, Edit by GSCOTT
;(17) Bug in last edit.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.186 29-Sep-87 17:59:03, Edit by GSCOTT
;(16) Stupid coding error was smashing the microwords that load the version.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.185 29-Sep-87 16:22:00, Edit by GSCOTT
;(15) Account for monitor storing version incorrectly in UCDVER
;WORK:<GSCOTT.IPA>IPAGEN.MAC.183 29-Sep-87 15:57:00, Edit by GSCOTT
;(14) Move text to literal for IMOK.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.180 29-Sep-87 15:56:29, Edit by GSCOTT
;(13) Get version number from entry vector
;WORK:<GSCOTT.IPA>IPAGEN.MAC.177 29-Sep-87 15:49:34, Edit by GSCOTT
;(12) Output version number even if user is starting.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.170 29-Sep-87 13:22:59, Edit by GSCOTT
;(11) Add some more comments about program use.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.167 29-Sep-87 13:07:06, Edit by GSCOTT
;(10) Rearrange storage, put a WARNING in about the memory layout.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.157 28-Sep-87 22:50:36, Edit by GSCOTT
;(7) Clean up listing
;WORK:<GSCOTT.IPA>IPAGEN.MAC.152 28-Sep-87 22:35:13, Edit by GSCOTT
;(6) Dump JFN of CI20 file properly.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.146 28-Sep-87 22:22:43, Edit by GSCOTT
;(5) Set starting address after microcode loaded.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.140 28-Sep-87 22:08:31, Edit by GSCOTT
;(4) Rearrange storage so that old monitors can still use new IPAGEN.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.132 28-Sep-87 17:51:00, Edit by GSCOTT
;(3) Store version number in entry vector
;WORK:<GSCOTT.IPA>IPAGEN.MAC.129 28-Sep-87 17:42:26, Edit by GSCOTT
;(2) Insert SKIPAs before DIAG for debugging.
;WORK:<GSCOTT.IPA>IPAGEN.MAC.3 28-Sep-87 11:47:30, Edit by GSCOTT
;(1) Creation.
TITLE IPAGEN - Generate IPALOD for loading CI20 microcode
SUBTTL Gregory A. Scott
Subttl Table of Contents
; Table of Contents for IPAGEN
;
; Section Page
;
;
; 1. Use of this program . . . . . . . . . . . . . . . . . 3
; 2. Definitions . . . . . . . . . . . . . . . . . . . . . 4
; 3. Startup . . . . . . . . . . . . . . . . . . . . . . . 5
; 4. Have monitor load microcode . . . . . . . . . . . . . 6
; 5. Load microcode file into memory . . . . . . . . . . . 7
; 5.1 Loop to load ucode buffer . . . . . . . . . . 8
; 5.2 Finish up ucode buffer . . . . . . . . . . . . 9
; 5.3 Save loaded image . . . . . . . . . . . . . . 10
; 5.4 Close files and exit . . . . . . . . . . . . . 11
; 6. Read line of microcode . . . . . . . . . . . . . . . . 12
; 7. Subroutines . . . . . . . . . . . . . . . . . . . . . 15
; 8. Storage
; 8.1 Pure . . . . . . . . . . . . . . . . . . . . . 16
; 8.2 Impure . . . . . . . . . . . . . . . . . . . . 17
; 9. End of IPAGEN . . . . . . . . . . . . . . . . . . . . 19
SUBTTL Use of this program
COMMENT ~
This program is used to generate the file IPALOD.EXE, which resides in
PS:<SYSTEM> of a TOPS-20 system to load the CI20 microcode. To use it,
perform the following steps:
1) Copy the desired microcode into a file called CI20.ULD.
2) Run IPAGEN, it then loads the microcode. IPAGEN saves itself in
the file IPALOD.EXE.edit, where "edit" is the microcode's edit.
3) Copy the resultant IPALOD.EXE.edit into PS:<SYSTEM>
4) Reload the system.
An IPALOD.EXE can also generate another IPALOD by having a CI20.ULD in the
connected directory. To do this:
1) Copy the desired microcode into a file called CI20.ULD.
2) GET PS:<SYSTEM>IPALOD, and then REENTER it. IPALOD then loads
the microcode and saves itself in the file IPALOD.EXE.edit,
where "edit" is the microcode's edit number.
3) Copy the resultant IPALOD.EXE.edit into PS:<SYSTEM>
4) Reload the system.
PHYKLP reads the file PS:<SYSTEM>IPALOD.EXE early in its KLIPA initialization
code and store the microcode in extended resident memory. Job 0 then starts
up IPALOD at entry vector offset 4, causing two DIAG JSYSes to be executed
which load the microcode from the copy in memory. When a user runs IPALOD
(entry vector offset 0) the same two DIAG JSYSes are executed. Entry vector
offset 1 (REENTER) is used to load a new CI20 microcode into memory and then
save it. Entry vector offset 3 contains the version of the microcode loaded.
END OF COMMENT ~
SUBTTL Definitions
;Search the usual things, set up the usual AC defs
SEARCH MONSYM,MACSYM ;Search the usual universals
SALL ;Clean listing
STDAC. ;Standard ACs today
.DIREC FLBLST ;First line binary listing please
SALL ;Clean listing
;Version of KLPLOD
VMAJ==1 ;Major version
VMIN==0 ;Minor version
VEDI==17 ;Edit
VWHO==0 ;Who else but DEC development?
LOC 400000 ;Get us out of the monitor's way
SUBTTL Startup
;Two entry points are used: one for the monitor, and one for the user.
MSTART: TDZA P2,P2 ;Monitor starts here
USTART: SETO P2, ;User starts here
;Set up the stack, and enter user i/o mode (not sure why you need to do that).
MOVE P,[IOWD PDLEN,PDL] ;Load up the stack
USRIO% ;Get into user I/O mode to deal with KLIPA
ERJMP UFAIL ;Punt if error
JUMPE P2,MLOAD ;Jump if monitor loading it
;User is loading CI20 microcode - we don't know what version he will get today
ULOAD: MOVEI T1,.SNPSY ;Get a monitor symbol
MOVE T2,[RADIX50 0,UCDVER] ;This is where the version is stored
MOVE T3,[RADIX50 0,PHYKLP] ;This is where that symbol lives
SNOOP% ;Get the value of that symbol
ERJMP ULOAD2 ;Oops, forget it
MOVEI T1,(T2) ;Section 0 address of the data
HRLI T1,1 ;One word today
MOVEI T2,T4 ;Store it in T3
PEEK% ;Get word from monitor into T4
ERJMP ULOAD2 ;Punt if error
HRROI T1,[ASCIZ/[IPALOD: Reloading resident CI20 microcode version /]
PSOUT% ;Telling me that is easy enough
CALL PVERS1 ;(T4/) Print ucode version
CALL CLOSB ;() Output close bracket
JRST LOADIT ;Try and loadit
ULOAD2: HRROI T1,[ASCIZ/[IPALOD: Reloading resident CI20 microcode]/]
PSOUT% ;Telling me that is easy enough
JRST LOADIT ; and then try and load it
;Here if the monitor is running us, output the version of the ucode loading.
MLOAD: HRROI T1,[ASCIZ/
[IPALOD: Loading CI20 microcode version /] ;Start of the message
PSOUT% ;Telling me that is easy enough
CALL PVERS ;() Print ucode version
CALL CLOSB ;() Output close bracket
;Fall through to LOADIT
SUBTTL Have monitor load microcode
;Here to load the microcode that the monitor has picked out of us earlier.
LOADIT: MOVE T1,[-2,,[EXP .DGUCD,.DGRIP]] ;Get reload ucode function
DIAG% ;Ask the monitor to do it for us
ERJMP LFAIL ;Fail if it didn't work properly
CALL IMOK ;() Output the OK message
MOVE T1,[-2,,[EXP .DGUCD,.DGRLC]] ;Reload is now complete
DIAG% ;Tell the monitor
ERJMP .+1 ;Ignore errors
;Done, halt this fork
UEXIT: HALTF% ;That's all
JRST .-1 ;Prevent restarts
;Here if the loading failed
LFAIL: HRROI T1,[ASCIZ/ [FAILED]
/] ;Load failed message
PSOUT% ;Output that message
UFAIL: HRROI T1,[ASCIZ/IPALOD: /] ;Start the error string out
ESOUT% ; on the terminal
CALL PERROR ;() Dump the last error
JRST UEXIT ;Exit the program
SUBTTL Load microcode file into memory
;Here to read the microcode from a file and store it in UCBUFF.
READIT: RESET% ;Reset the world
MOVE P,[IOWD PDLEN,PDL] ;Load up the stack
;Get a open JFN on the file.
MOVX T1,GJ%SHT!GJ%OLD ;Load short form old file
HRROI T2,[ASCIZ/CI20.ULD/] ;Standard filename
GTJFN% ;Get a JFN for it
ERJMP RFAIL1 ;Read failed
MOVX T2,FLD(7,OF%BSZ)!OF%RD ;Open for 7 bit bytes and reading
OPENF% ;Pry it open
ERJMP RFAIL2 ;Punt if it didn't work
MOVEM T1,RJFN ;Store the JFN
;Let me know what file I am reading today.
HRROI T1,[ASCIZ/[IPAGEN: Reading /] ;Load a label
PSOUT% ;Output that
MOVE T2,RJFN ;Copy JFN back to T2
MOVEI T1,.PRIOU ;Output to primary
MOVX T3,FLD(.JSAOF,JS%DEV)!FLD(.JSAOF,JS%DIR)!FLD(.JSAOF,JS%NAM)!FLD(.JSAOF,JS%TYP)!FLD(.JSAOF,JS%GEN)!JS%PAF
JFNS% ;Output that
ERJMP .+1 ;Can't fail
CALL CLOSB ;() Output close bracket
SUBTTL Load microcode file into memory -- Loop to load ucode buffer
;Microcode file is open, read it scanning the important lines. P1 will point
;to the location in UCBUFF, P2 will hold the number of microwords that we are
;storing. Microcode location 135 holds the major version number in bits 21-23
;and minor version in bits 24-29. Microcode location 137 holds the edit number
;in bits 20-29, which is stored for the monitor's use later.
SETZB P1,P2 ;Clear both of them
RLOOP: CALL GUCODE ;(/Q1,Q2,Q3,T4) Get a microword
JRST RFINI ;Finish up
CAIE T4,136 ;Version word?
IFSKP. ;Yes
MOVE T2,Q2 ;Copy the word to T2
LSH T2,-6 ;Shift down
MOVEI T3,(T2) ;Copy the whole version over
ANDI T3,77 ;Get just the minor version
LSH T2,-6 ;Shift down the major version
ANDI T2,7 ;Zap the junk away
MOVEM T2,UVERS ;Store major version
MOVEM T3,UMINO ;Store
ENDIF.
CAIE T4,137 ;Edit word?
IFSKP. ;Yes
MOVE T2,Q2 ;Copy the word over to T2
LSH T2,-6 ;Shift down
ANDI T2,3777 ;Get just the edit number
MOVEM T2,UEDIT ;Store edit number
ENDIF.
DMOVEM Q1,UCBUFF(P1) ;Store Q1 and Q2
MOVEM Q3,UCBUFF+2(P1) ; and Q3
ADDI P1,3 ;Point to next free word
AOJA P2,RLOOP ;Continue until all has been read
SUBTTL Load microcode file into memory -- Finish up ucode buffer
;Here when end of file detected, finish buffer with words containing -1, major,
;minor, and edit for the monitor's use.
RFINI: MOVEM P1,WORDS ;Save number of words loaded today
SETOM UCBUFF(P1) ;Put a -1 at end of microcode stored
DMOVE T1,UVERS ;Get major and minor version
DMOVEM T1,UCBUFF+1(P1) ;Store major and minor version for monitor
DPB T1,[POINT 9,VERSIO,11] ;Store the major version in entry vector
DPB T2,[POINT 6,VERSIO,17] ;Store minor version in entry vector
MOVE T1,UEDIT ;Load edit number
MOVEM T1,UCBUFF+3(P1) ;Store the edit number for monitor
HRRM T1,VERSIO ;Store edit number in entry vector
MOVEI T1,USER ;Load user starting address
HRRM T1,ENTRY ;Store it in the entry vector
;Say what version we loaded today.
CALL IMOK ;() Output OK message
HRROI T1,[ASCIZ/[IPAGEN: /] ;Output next label
PSOUT% ;Output that next
MOVEI T1,.PRIOU ;Output to primary
MOVE T2,WORDS ;Get number of words
IDIVI T2,3 ;Account for 3 of our words for each of his
MOVEI T3,^D10 ;Radix ten
NOUT% ;Output that
ERJMP .+1 ;Punt errors
HRROI T1,[ASCIZ/ microwords loaded, version /]
PSOUT% ;Output that
CALL PVERS ;() Output what version
CALL CLOSB ;() Output closing bracket
SUBTTL Load microcode file into memory -- Save loaded image
;Create filename and save it.
HRROI T1,FBUFF ;Make the filename next
HRROI T2,[ASCIZ/IPALOD.EXE./] ;Start with the name
SETZB T3,T4 ;Terminate on a null
SOUT% ;String OUTput that (slow, dumb)
MOVE T2,UEDIT ;Load edit number
MOVEI T3,10 ;Load radix 8
NOUT% ;Output that number
ERJMP .+1 ;Punt any errors away
MOVX T1,GJ%SHT!GJ%FOU ;Load short form bit
HRROI T2,FBUFF ;Point back to the filename
GTJFN% ;Get a JFN on it
ERJMP RFAIL3 ;Punt if failure
MOVE T2,T1 ;Copy JFN back to T2
HRROI T1,[ASCIZ/
[IPAGEN: Saving as /] ;Load a label
PSOUT% ;Output that
MOVEI T1,.PRIOU ;Output to primary
MOVX T3,FLD(.JSAOF,JS%DEV)!FLD(.JSAOF,JS%DIR)!FLD(.JSAOF,JS%NAM)!FLD(.JSAOF,JS%TYP)!FLD(.JSAOF,JS%GEN)!JS%PAF
JFNS% ;Output that
ERJMP .+1 ;Can't fail
CALL CLOSB ;() Output close bracket
MOVEI T1,(T2) ;Get JFN back to T2
HRLI T1,.FHSLF ;Make fork,,JFN
MOVE T2,[-1000,,SS%CPY!SS%RD!SS%EXE] ;All of the pages this fork
SETZ T3, ;No additional data
SSAVE% ;Save us
ERJMP RFAIL4 ;Punt if failure
CALL IMOK ;() OK
;Fall through to RCLOSE
SUBTTL Load microcode file into memory -- Close files and exit
;Here to close JFNs and exit.
RCLOSE: SKIPE T1,RJFN ;Do we have a JFN?
CLOSF% ;Close it
ERJMP .+1 ;Ignore errors
SETZM RJFN ;Remember that we dumped the JFN
HALTF% ;Stop
JRST .-1 ;Don't continue
;Here when there is a problem, report it
RFAIL4: JSP T1,RFAIL0 ;Here if can't open file
ASCIZ/IPAGEN: Can't save IPALOD.EXE - /
RFAIL3: JSP T1,RFAIL0 ;Here if can't open file
ASCIZ/IPAGEN: Can't get JFN for IPALOD.EXE - /
RFAIL2: JSP T1,RFAIL0 ;Here if can't open file
ASCIZ/IPAGEN: Can't open CI20.ULD - /
RFAIL1: JSP T1,RFAIL0 ;Here if can't get jfn
ASCIZ/IPAGEN: Can't get JFN for CI20.ULD - /
RFAIL0: TLO T1,-1 ;Make -1,,address
ESOUT% ;Output that string
CALL PERROR ;() Print the error
JRST RCLOSE ;Dump JFN and exit
SUBTTL Read line of microcode
;Here to read a word of microcode from the file. The format of the file is as
;follows. If the first character on a line is not a "[" then this line is not
;part of the microcode. The number following the "[" is the location that this
;microword is for. After the location comes a "]=". The actual microword is
;next. A CRLF terminates the line.
;
;Assumes that ULD file is open and JFN points at beginning of line.
;
;Returns: never if some error
; +1 if end of file
; +2 if microword found with
; Q1/ first load format word
; Q2/ second load format word
; Q3/ third load format word
; T4/ address of this microword
GUCODE: MOVE T1,RJFN ;Load the JFN of the file
BIN% ;Get a 7 bit byte
ERJMP GCHECK ;Check error
CAIN T2,"[" ;Start of microcode line?
JRST GUC1 ;Yes
;Not a microcode load line, eat until end of line seen
GUC0: BIN% ;Get a character
ERJMP GCHECK ;Check if error
CAIE T2,.CHLFD ;Line feed?
JRST GUC0 ;Nope, loop for more
JRST GUCODE ;Rough and ready to ride again
;Read in the microaddress, save it in T4
GUC1: MOVEI T3,10 ;Load octal radix
NIN% ;Input that number to T2
ERJMP GCHECK ;Check errors
MOVE T4,T2 ;Copy address to T4
;Check for next two characters being "]" and "="
BKJFN% ;Get the termination character back please
ERJMP GCHECK ;Check for errors
BIN% ;Get next character
ERJMP GCHECK ;Check errors
CAIE T2,"]" ;Closed properly?
JRST GCFERR ;Nope
BIN% ;Get next character
ERJMP GCHECK ;Check errors
CAIE T2,"=" ;Formatted properly?
JRST GCFERR ;Nope
;Format Q1 with the address and select bits (B0!<addr>B12!B13)
MOVEI Q1,(T4) ;Copy the address
LSH Q1,^D35-^D12 ;Shift properly
TXO Q1,1B0!1B13 ; and set the constant bits
;Read the microword into memory, splitting it into two ten character pieces
HRROI T2,RBUFF1 ;Point to read buffer
MOVNI T3,^D10 ;Reading ten characters today
SIN% ;Read them
ERJMP GCHECK ;Check errors
HRROI T2,RBUFF2 ;Point to read buffer
MOVNI T3,^D10 ;Reading ten characters today
SIN% ;Read them
ERJMP GCHECK ;Check errors
;Insure that there is a CR LF pair at the end of the line
BIN% ;Get the next character
ERJMP GCHECK ;Check errors
CAIE T2,.CHCRT ;Is it a return
JRST GCFERR ;No, format error
BIN% ;Get the next character
ERJMP GCHECK ;Check errors
CAIE T2,.CHLFD ;Is it a return
JRST GCFERR ;No, format error
;Convert the ASCIZ numbers in the read buffers to numbers for storage
HRROI T1,RBUFF1 ;Point to the first word
MOVEI T3,10 ;Octal radix
NIN% ;Read that
ERJMP GCHECK ;Check errors
MOVE Q2,T2 ;Copy data to Q2
HRROI T1,RBUFF2 ;Point to the second word
NIN% ;Read that
ERJMP GCHECK ;Check errors
MOVE Q3,T2 ;Copy data to Q3
;All went well, so we can return now
RSKP: AOS (P) ;Skip and
R: RET ; return
;Here on a format error
GCFERR: HRROI T1,[ASCIZ/IPAGEN: Format error with file
/]
ESOUT% ;Output that error
JRST RCLOSE ;Lose JFN and exit
;Here on a ERJMP from a JSYS while reading the file
GCHECK: MOVEI T1,.FHSLF ;Load this fork's JFN
GETER% ;Get that error
TLZ T2,-1 ;Zap the fork
CAIN T2,IOX4 ;End of file reached?
RET ;Yes, return+1 now
HRROI T1,[ASCIZ/IPAGEN: IO error reading microcode file - /]
ESOUT% ;Output that string
CALL PERROR ;() Print whatever error it was
JRST RCLOSE ;() Lose JFN and exit
SUBTTL Subroutines
;Small routine to print OK message
IMOK: HRROI T1,[ASCIZ/ [OK]
/] ;Output the OK message
PSOUT% ; to the terminal
RET ; and return
;Small routine to print closing bracket
CLOSB: MOVEI T1,"]" ;Output ending square bracket
PBOUT% ; to the terminal
RET ; and return
;Small routine to print out the last JSYS error
PERROR: MOVEI T1,.PRIOU ;Output to terminal
HRLOI T2,.FHSLF ;This fork's last error
SETZ T3, ;No limit
ERSTR% ;Output the string to terminal
JFCL ;Forget
JFCL ; any errors
RET ; and return
;Small routine to print microcode version
PVERS: MOVE T4,VERSIO ;Print version from entry vector
PVERS1: MOVEI T1,.PRIOU ;Output to primary
LDB T2,[POINT 9,T4,11] ;Load the major version
CAIN T2,10 ;Is it version 10?
MOVEI T2,1 ;Yes, it is really version 1
MOVEI T3,10 ;Octal radix
NOUT% ;Output that number
ERJMPS .+1 ;Ignore error, preserve T1
LDB T2,[POINT 6,T4,17] ;Get minor version
JUMPE T2,PVERS2 ;Jump if none
MOVEI T2,"." ;Load a dot
BOUT% ;Output it
ERJMPS .+1 ;Ignore error, preserve T1
LDB T2,[POINT 6,T4,17] ;Get minor version again
NOUT% ;Output that
ERJMPS .+1 ;Ignore error, preserve T1
PVERS2: MOVEI T2,"(" ;Output paren
BOUT% ; to terminal
ERJMPS .+1 ;Ignore error, preserve T1
MOVEI T1,.PRIOU ;Output to primary
HRRZ T2,T4 ;Load edit number
NOUT% ;Output that number
ERJMPS .+1 ;Ignore error, preserve T1
HRROI T1,[ASCIZ/)/] ;End that text
PSOUT% ;Output that and fall thru
RET ;Return
SUBTTL Storage -- Pure
;Dump literals (XLISTed)
LIT..: XLIST ;LIT
LIT
ELIT..: LIST
SUBTTL Storage -- Impure
; WARNING
;CAUTION: If you change any locations in low memory, you have to change PHYKLP
;so that it works right - the KLPUCD routine to which does a RIN% with 1146 in
;AC3 to pick up what is in location WORDS below. WORDS should equal location
;146 in the image saved, and should be the 1146th word in the file. The
;microcode is read in starting at word 2000. Since page 0 of the EXE file is
;the EXE file directory, and page 1 of the EXE file must be page 0 of the
;memory image, and page 2 start the microcode, there cannot be anything in page
;1 of the image before it is saved. This means that the layout of the first
;few pages of the EXE file must be:
;
; Page 0 EXE file directory
; Page 1 Entry vector, code startup (memory page 0)
; Page 2 Start of microcode (memory page 2)
; Page 31 End of microcode (memory page 31)
; The foramt of the rest of the EXE file doesn't matter.
LOC 140 ;Start here
;Entry vector
ENTRY: JRST READIT ;(replaced with JRST USER)
JRST READIT ;User wants to read new microcode
VERSIO: BYTE (3)VWHO(9)VMAJ(6)VMIN(18)VEDI ;Version
JRST MONITR ;Monitor wants microcode loaded
;Start locations
USER: JRST USTART ;User tries to run IPALOD comes here
MONITR: JRST MSTART ;Monitor loads CI microcode at system startup
WORDS: Z ;Monitor looks here for number of words
;End of CAUTION
;Other impure storage goes here
PDL: BLOCK <PDLEN==10> ;The stack
UVERS: BLOCK 1 ;Microcode major version
UMINO: BLOCK 1 ;Microcode minor version
UEDIT: BLOCK 1 ;Microcode edit
RJFN: BLOCK 1 ;JFN of microcode file we are reading
RBUFF1: BLOCK 3 ;Place to read firsthalf of microword into
RBUFF2: BLOCK 3 ;Place to read second half of microword into
FBUFF: BLOCK <^D20/5> ;Place to create filename
;The microcode is wired in starting at location 2000, and there can't be a page
;1 in the pagemap (see previous page's WARNING). Don't let an overflow occur
;to page 1.
FREE==. ;Beginning of page 0 free space
IF1,IFG FREE-777,<PRINTX ?Storage overflows location 777>
LOC 2000
UCBUFF: BLOCK ^D4097*3 ;4K ucode storage, 3 words for each uword
BLOCK 4 ;Space for -1 and version information
SUBTTL End of IPAGEN
END <4,,ENTRY>