* IPL VERSION 0.2 - JULY 2 2008
*
* IPL IS REQUIRED TO LOAD AND START, AFTER BOOTING THE SYSTEM, A PARTICULAR 
* PROGRAM FROM DISK. THAT PROGRAM NORMALLY IS THE OPERATING SYSTEM KERNEL
* STORED ON THE DISK AS A RELOCATABLE LOAD MODULE (LM). 
* THE ORIGINAL P800-DISK-IPL IS NOT AVAILABLE; THIS PROGRAM IS AN ATTEMPT TO 
* SUPPLY A REPLACEMENT IN ORDER TO GET THE SYSTEM STARTED FROM DISK.
* LOADED AND STARTED BY THE DISK BOOT PROGRAM FROM DISK LOGICAL SECTOR 1 
* (== PHYSICAL SECTOR 3), IPL LOADS A RELOCATABLE LM FROM DISK FROM A PREDEFINED 
* LOCATION AND STARTS THAT LM AFTER LOADING. 
* THE LM MUST BE STORED IN CONSECUTIVE  GRANULES, STARTING WITH GRANULE 2, 
* WHICH IS ON LOGICAL==PHYSICAL SECTOR /10 (16).
* THE 1ST SECTOR OF THE LM IS SECTOR /12 (/16 PHYSICAL) ON DISK AND CONTAINS THE 
* REMAINING LOAD INFO OF THE LM:
* - START ADDRESS, 
* - NUMBER OF SECTORS TO LOAD,
* - AND PROGRAM LENGTH IN WORDS, SPECIFIED IN BYTES (SO BIT 15 IS ALWAYS 0).
* THE DISK PARAMETERS OF THE USED DISK TO LOAD FROM, ARE EXTRACTED FROM THE 
* DISK BOOT PROGRAM (LOCATED IN MEMORY AT THE ADDRESSES 0../3E. 
* FOR THAT, IPL STARTS BY LOADING THE FOLLOWING REGISTERS WITH INFO FROM THE 
* DISK BOOTSTRAP:
* A1 32 CIO   A5,S,0
* A2 34 SST   A5,0
* A3 36 RB(4) *-2
* A4 38 ABR   A4
* A5 3A DATA  /4E66 MPX CONTROL WORD1 (INPUT 410 BYTES IN WORD MODE)
* A6 3C DATA  /7E00 MPX CONTROL WORD2 (END ADDRESS OF SECTOR BUFFER LOADED BY BOOT)
* A7 3E DATA  /0002 DISK DEVICE ADDRESS (DEVICE NUMBER 0)
*
* THE IPL PROGRAM ITSELF IS A RELOCATABLE PROGRAM IN ORDER TO CHANGE ITS LOAD 
* LOCATION DEPENDENT ON THE MEMORY SIZE OF THE USED COMPUTER. ITS LOAD LOCATION 
* IS DETERMINED BY THE BOOT PROGRAM (WORD /3C CONTAINS THE END ADDRESS OF THE AREA 
* WHERE IPL IS LOADED). NORMALLY THE IPL PROGRAM IS LOADED SOMEWHERE IN THE 
* HIGH END OF MEMORY; THE ONLY CONDITION IS THAT A WORKAREA OF ABOUT 240 WORDS 
* MUST BE AVAILABLE ABOVE THE IPL PROGRAM TO CONTAIN A 205 WORD DISK SECTOR 
* BUFFER AND OTHER WORKING SPACE USED BY IPL. 
* THE IPL PROGRAM ITSELF IS ONE DISK SECTOR LONG (205 WORDS OF WHICH 200 WITH 
* CODE MAXIMUM) AND SHOULD OF COURSE NOT BE OVER WRITTEN BY THE PROGRAM IT LOADS
* (FOR A 16KW MEMORY, THE CONTENT OF /3C IN THE BOOT PROGRAM MUST NOT BE LARGER 
* THAN /7E00; THE AREA /7E00 .. /7FFE IS USED THEN BY IPL AS WORKAREA).
* SO THE IPL PROGRAM MUST BE RELOCATABLE, BUT BECAUSE THE BOOT PROGRAM, WHICH
* LOADS IPL, DOES NOT RELOCATE, THE IPL PROGRAM MUST BE WRITTEN IN SUCH A WAY
* THAT IS DOES NOT NEED  RELOCATION; IN OTHER WORDS IT SHOULD NOT CONTAIN 
* ANY RELOCATIONAL DATA AND OPERAND ADDRESSES.
*
* IPL WORK AREA (WITH A14 AS POINTER TO THIS WORKAREA):
* THE IPL PROGRAM STARTS AT THE 3RD WORD OF LOGICAL DISK SECTOR 1 (PHYSICAL DISK
* SECTOR 3). BEHIND THE 200 CODE/DATA WORDS ARE 3 EMPTY WORDS (THE LAST 3
* TRAILER WORDS OF THE SECTOR). THE LAST WORD OF THOSE 3 (WHICH IS THE LAST WORD
* LOADED BY BOOT) IS THE START LOCATION OF THE WORKAREA. IN IPL, A14 IS ALWAYS
* POINTING TO THAT WORD AND IT IS USED AS REFERENCE IN MEMORY FOR THE CODE AND 
* DATA WITHIN IPL.
*
* MODIFICATIONS:
* VERSION 0.2  ADAPTED TO 'LOAD MODULES' WITH LENGTH SPECIFIED IN BYTES (WORD 3)
*
****************************************************************************
* THIS IPL IS MEANT TO BE A FUNCTIONAL REPLACEMENT OF THE ORIGINAL P800 DISK
* IPL PROGRAM; ITS CODE IS DIFFERENT, BUT ITS OPERATION IS EXPECTED TO BE
* SIMILAR AS THE ORIGINAL ONE.
*
* PHILIPS P800 16 BIT COMPUTER SOFTWARE.
* THE PROGRAM IS CREATED BY: THEO ENGEL (THEO.ENGEL@HETNET.NL)
****************************************************************************
 EJECT
 IDENT IPL
 AORG /7C6C ***REMOVE***
BA EQU /40
S EQU 1
H EQU 0
ASR EQU /10 DEVICE ADDRESS OF THE ASR 
PTR EQU /20 DEVICE ADDRESS OF THE PTR
* THE 1ST 4 WORDS OF THE LOAD MODULE, I.E. START ADDRESS, NUMBER OF SECTORS TO
* LOAD, PROGRAM LENGTH, AND A RESERVED WORD, ARE NOT LOADED INTO MEMORY. SO THE
* 1ST WORD LOADED INTO MEMORY IS WORD 4 OF THE LOAD MODULE. FOR NON-IPLED
* LOAD MODULES, THESE 4 WORDS ARE LOADED INTO MEMORY.
* 
RELOC EQU BA-8 RELOCATOR FOR THE LM TO LOAD: COMPENSATES FOR SKIPPING THE 1ST 4 WORDS
*
* START ADDRESS
IPL ML 7,/32 LOAD A1-A7 FROM THE BOOTSTAP
 LDR A14,A6 A14 IS POINTER TO IPL WORK AREA + DISK IO ROUTINE
 LDR A13,A14
 ADKL A13,LST A13 IS LINKSTACK POINTER
 LDR A9,A14 **
 ADKL A9,ASCOUT ** A9 IS POINTER TO THE PRINT ASCII ROUTINE
 LDR A7,A7
 RF(1) DBOOT DISK BOOTSTRAP WAS REQUESTED
*************************************************************
* THE PAPERTAPE BOOTSTRAP (EMBEDDED IN IPL) WAS REQUESTED   *
*************************************************************
* MODE IS ALREADY AND STILL IS INHIBITED
 CIO A1,S,PTR
SEARCH INR A2,0,PTR SKIP LEADER AND SEARCH
 RB(4) *-2 FOR A RUBOUT
 ANK A2,/7F
 RB(0) SEARCH
 LDK A7,4 READ 4 BYTES: WORDCOUNT AND BEGINADDR-2
 LDK A4,/40 /40=WORDCOUNT ADDRESS, /42=BEGIN ADDRESS - 2
INPUT INR A2,0,PTR
 RB(4) *-2
 SCR A2,A4 STORE BYTE
 ADK A4,1 INCR ADDR POINTER
 SUK A7,1 DECR BYTE COUNT
 RB(1) INPUT READ NEXT BYTE IF > 0
 RF(2) CODE < 0
* A7=0 => PREPARE FOR READING CODE
* THE WORKSPACE AT ADDRESS /40 IS MADE FREE BEFORE CODE IS READ.
* SO THE ADDRESSES /40 AND /42 CAN BE USED BY THE CODE READ BY THE BOOTSTRAP
 ML 4,/3C A1=/3C A2=/3E A3=/40=WC A4=/42=BA-2
 LDK A1,0 A1 = CHECKSUM = 0 AS START VALUE
 SLL A3,1 WORD COUNT BECOMES BYTE COUNT
 ADK A4,2 A4=BEGIN ADDRESS
 LDR A6,A4 A6=BEGIN ADDRESS
 RB INPUT
*
CODE ECR A1,A1 A1 = CHECKSUM
 XRR A1,A2
 SUK A3,1 BYTECOUNT = BYTECOUNT - 1
 RB(4) INPUT READY?
* PAPERTAPE LOAD READY. JUMP OVER A6 TO PROGRAM
* BUT 1ST PRINT A SMALL MESSAGE
 SST A2,PTR
 RB(4) *-2 PTR TO INACTIVE MODE
LR LDK A1,'I'
 CFR A13,A9
 LDK A1,'P'
 CFR A13,A9
 LDK A1,'L'
 CFR A13,A9
 LDK A1,/0D
 CFR A13,A9
 LDK A1,/0A
 CFR A13,A9
 ABR A6 YES, JUMP TO BEGIN/START ADDRESS
*
* END OF DISK IPL, PRINT MESSAGE AND JUMP TO PROGRAM
EXIT LD A6,SA,A14 GET RELOCATED START ADDRESS 
 RB LR
 RES 5
 EJECT
**************************************************************
* DISK IPL                                                   *
**************************************************************
DBOOT LDKL A4,/F036 REPLACE ABR A4 BY RTN A13 (A13 USED AS SUBR LINK STACK POINTER)
 ADKL A6,/1FE END OF THE SECTOR BUFFER USED BY IPL
 ANK A7,/3F ISOLATE DEVICE ADDRESS
 ADR A1,A7 CIO WITH DEVICE ADDRESS OF USED DISK
 ADR A2,A7 SST WITH DEVICE ADDRESS OF USED DISK
 MSR 7,A14 FILL THE 1ST 7 WORDS OF THE IPL WORK AREA
 SLL A7,2
 ADK A7,/80
 ST A7,MPXAD,A14 SAVE MPX CHANNEL ADDRESS OF THE USED DISK
* SEEK TO CYLINDER 0
 LDK A5,3 
 CFR A13,A14  DO DISK IO
*
* LOAD THE 1ST CODE SECTOR OF THE LOAD MODULE 
* THE LOAD MODULE STARTS IN GRANUNE 2: PHYSICAL SECTOR /10 == LOGICAL SECTOR /10
* THE 1ST CODE SECTOR IS THE 2ND LOGICAL SECTOR (WHEN COUNTING IS STARTED WITH 0)
* IN THE LOAD MODULE FILE, WHICH IS PHYSICAL SECTOR /16
 ML 2,CW1,A14
 MS* 2,MPXAD,A14 STORE MULTIPLEX WORDS
* READ PHYSICAL SECTOR /16 IN CYLINDER 0
 LDK A5,/58 10110 00
 CFR A13,A14 DO DISK IO
 SUK A6,202
 SUK A6,202
 ST A6,SCODE,A14 SAVE CODE ENTRY POINTER (A6) INTO SECTOR BUFFER
 MLR 3,A6 A1=START ADDRESS, A2=NUMBER OF SECTORS, A3=LENGTH IN BYTES
 ADKL A1,RELOC RELOCATE START ADDRESS
 MS 3,SA,A14 AND STORE IN WORK AREA
 LDK A2,/12
 ST A2,SNBR,A14 INITIAL LOGICAL LOADED SECTOR 
 LDKL A10,BA START LOADING AND RELOCATION IN MEMORY HERE
 LDK A7,8 A7 IS CURRENT INDEX INTO SECTOR BUFFER
 LDR A12,A7 A12 IS CURRENT LOADED NUMBER OF BYTES (OF WHICH THE 1ST 8 ARE SKIPPED)
 LDR A11,A7 A11 IS CURRENT RELOCATED NUMBER OF BYTES
*
* READING, LOADING AND RELOCATION LOOP
*
*
* LOAD THE SECTOR AS BUFFERED IN THE SECTOR BUFFER
LOOP LDK A1,'.' **
 CFR A13,A9 ** PRINT DOT TO SHOW ACTIVITY
 LDR A2,A10 START LOADING THE SECTOR (A2=MEMORY POINTER)
LNW LD A8,SCODE,A14 POINTER TO CODE IN SECTOR BUFFER
 ADR A8,A7 INDEX THE POINTER 
 LDR* A1,A8 GET WORD FROM SECTOR BUFFER
 STR A1,A2 AND STORE INTO LOAD AREA
 ADK A2,2 INCR LOAD AREA POINTER
 ADK A7,2 INCR SECTOR BUFFER INDEX
 ADKL A12,2 INCR NUMBER OF WORDS LOADED IN MEMORY 
 CW A12,LLM,A14 ALL REQUESTED WORDS LOADED?
 RF(0) RTAB YES, PROGRAM LOAD READY
 CWK A7,376 188*2 END OF CODE PART IN SECTOR?
 RF(0) RTAB SECTOR LOAD READY, START RELOCATING THE SECTOR
 RB LNW LOAD NEXT WORD
* SKIP TO THE 12 WORD RELOCATION TABLE IN SECTOR BUFFER
RTAB LDKL A7,376 188*2 A7 POINTS TO SECTOR RELOCATION TABLE
 LDK A3,188 RELOCATE 188 WORDS MAXIMUM
 LDKL A2,0 1ST SECTOR ?
FLAG EQU *-2 FLAG=0 FOR 1ST SECTOR AND NE 0 FOR SUBSEQUENT SECTORS
 RF(4) REL NO 
* SKIP FOR THE 1ST SECTOR THE 1ST 4 RELOCATION BITS
 ADR A6,A7 POINTER TO SECTOR RELOCATION TABLE
 ADK A7,2 INCR INDEX FOR ACCESSING NEXT WORD
 LDR* A1,A6 GET 1ST WORD WITH 16 RELOCATION BITS
 LDK A2,12 SET RELOCATION BIT COUNTER TO 16-4
 LDK A3,184 RELOCATE 188-4 WORDS MAXIMUM
 SLL A1,4 DELETE THE 1ST 4 BITS
 ST A2,FLAG FLAG IS NOW NONZERO; THE 1ST SECTOR WAS PROCESSED
 RF CNW
*
* RELOCATE THE LOADED SECTOR
REL LDK A2,16 RELOCATION BIT COUNTER 16..1
 LD A8,SCODE,A14 POINTER TO CODE IN SECTOR BUFFER
 ADR A8,A7 INDEX THE POINTER
 ADK A7,2 INCR INDEX FOR ACCESSING NEXT WORD
 LDR* A1,A8 GET WORD WITH 16 RELOCATION BITS
CNW RF(2) RELW A 1 BIT, SO RELOCATE
RL ADKL A10,2 INCR POINTER TO NEXT MEMORY WORD TO RELOCATE
 ADKL A11,2 PROGRAM LENGHT RELOCATED
 CW A11,LLM,A14 ALL REQUESTED WORDS RELOCATED?
 RB(0) EXIT YES, PROGRAM LOAD AND RELOCATION READY; GOTO STARTADDRESS
 SUK A3,1 END OF SECTOR RELOCATION TABLE?
 RF(0) READ SECTOR RELOCATION READY, READ AND LOAD NEXT SECTOR
 SUK A2,1 END OF RELOCATION WORD?
 RB(0) REL YES, GET NEXT RELOCATION WORD 
 SLL A1,1 GET NEXT RELOCATION BIT
 RB CNW
* RELOCATE A WORD IN MEMORY
RELW LDR* A4,A10
 ADKL A4,RELOC
 STR A4,A10
 RB RL
*
* GET NEXT SECTOR FROM DISK
READ LD A5,SNBR,A14 LOGICAL SECTOR NUMBER
 ADK A5,1 A5 = REQUESTED LOGICAL SECTOR
 ST A5,SNBR,A14 A5 = REQUESTED LOGICAL SECTOR
 ANK A5,/20 END OF CYLINDER?
 RF(0) CVSN NO
* IN CASE AN SECTOR 32 IS REQUESTED, SEEK TO NEXT CYLINDER
 LDK A5,/E SEEK +1 (1110)
 CFR A13,A14  DO DISK IO
 LDK A5,0 
 ST A5,SNBR,A14 RESET LOGICAL SECTOR NUMBER TO 0 
* CONVERT TO PHYSICAL SECTOR NUMBER
CVSN LD A5,SNBR,A14 
 LDR A6,A5
 ANK A6,/10 A6 = HEAD
 ANK A5,/F A5 = LOGICAL SECTOR IN TRACK
 LDR A1,A5
 SLL A5,1 *2
 ADR A5,A1 *3
 CWK A5,16
 RF(5) ADH <= 16
 SUK A5,16
 CWK A5,16
 RF(5) ADH <= 16
 SUK A5,16
ADH ADR A5,A6 + HEAD => A5 = PHYSICAL SECTOR NUMBER
 ML 2,CW1,A14
 MS* 2,MPXAD,A14 STORE MULTIPLEX WORDS
* READ PHYSICAL SECTOR 
 SLL A5,2
 CFR A13,A14 DO DISK IO
 LDK A7,0 RESET SECTOR BUFFER INDEX
 RB LOOP LOAD AND RELOCATE NEXT SECTOR INTO MEMORY
*
ASCOUT EQU -24  !!!! THIS IS AN OFFSET TO WAREA !!!!
 LDK A2,0 OUTPUT MODE
 CIO A2,S,ASR START
 RB(4) *-2
 OTR A1,0,ASR PRINT BYTE
 RB(4) *-2
 CIO A2,H,ASR STOP
 SST A2,ASR WAIT TILL ACCEPTED
 RB(4) *-2
 RTN A13
 DATA 0 SPARE WORD, AT ADDRESS 7DFA !!
***************** IPL CODE STOPS HERE (200 WORDS) ************************
 EJECT
*      DATA 0       1ST WORD OF LAST 3 WORDS OF IPL SECTOR
*      DATA 0       2ND WORD OF LAST 3 WORDS OF IPL SECTOR
* WORK AREA
WAREA EQU 0 <= POINTED TO BY A14 (LAST BOOT LOADED WORD OF IPL SECTOR)
DIO EQU 0 DO DISK IO
*      CIO    A5,S,DA DISK IO ROUTINE
*      SST    A5,DA
*      RB(4)  *-2
*      RTN    A13
CW1 EQU 8 DATA   /4E66 MPX CONTROL WORD1 (INPUT 410 BYTES IN WORD MODE)
CW2 EQU /A DATA   /7FFE MPX CONTROL WORD2 (END ADDRESS OF SECTOR BUFFER USED BY IPL)
DA EQU /C DEVICE ADDRESS USED BY DISK. 
* DA (DEVICE ADDRESS HAS POSSIBLY THE MS-BIT=1, INDICATING REQUEST FOR PAPERTAPE BOOT
MPXAD EQU /E MPX CHANNEL ADDRESS OF THE USED DISK UNIT
SCODE EQU /10 CODE ENTRY POINTER INTO SECTOR BUFFER
SA EQU /12 RELOCATED START ADDRESS
NSEC EQU /14 NUMBER OF SECTORS IN LOAD MODULE
LLM EQU /16 NUMBER OF BYTES IN LOAD MODULE
SNBR EQU /18 LOGICAL SECTOR READ FROM DISK
LST EQU SNBR+4 SUBR LINK STACK
 END IPL
