Once we have determined the highest memory address available we can copy our loader code into high memory.

         LR    R4,R9              HIGH MEM ADDRESS
         SR    R4,R3              BACK UP LENGTH OF CODE
         S     R4,M32K            LEAVE A 32K BUFFER
         N     R4,MASK            START ON A CLEAN BOUNDRY
         LR    R8,R4              SAVE START ADDRESS IN R8
         LA    R1,256             MAX MVC LENGTH

We start by loading the address of our loader routine into Register 2 and the length of the routine into Register 3.  We copy the highest memory address into Register 4 and then subtract the length of the code.  Because we use the storage immediately following our  loader code for the disk I/O buffer we subtract out another 32k leaving more then plenty of room.  Finally we use a logical AND to start loading on an even boundary (we at least have to start on a double word boundary to avoid alignment errors).  Finally save the beginning load address into Register 8 (so we can branch to it when relocation is completed) and we set Register 1 to 256 or the maximum length for a MVC instruction.

MCOPY    DS    0H
         CR    R3,R1              CHECK FOR MAX LEGNTH
         BL    MCOPY010           NO - SHORT MOVE
         MVC   0(256,R4),0(R2)    MOVE 256 BYTES
         AR    R2,R1              NEXT AREA
         AR    R4,R1                       TO MOVE
         SR    R3,R1              ADJUST LENGTH
         B     MCOPY              LOOP BACK
MCOPY010 DS    0H
         LTR   R3,R3              CHECK FOR ANYTHING TO MOVE
         BZ    MCOPY020           ALL DONE
         BCTR  R3,0               SUBTRACT ONE FOR EXECUTE
         EX    R3,MVC             COPY LAST OF DATA
MCOPY020 DS    0H
         LR    R15,R8             ADDRESS OF RELOCATED LOADER
         BR    R15                BRANCH TO IT

The copy routine is pretty straight forward.  First we check to see if we have at least 256 bytes left to copy.  If not we branch to MCOPY010 to handle a short move.   We then copy 256 bytes of data, increment our source and target pointers, and then decrement the remaining length.

When we finally have less than 256 bytes to copy we must first check that there is at least one byte to move.  We then subtract one from the length and use an Executed Move Characters to copy the remainder of the data.

Finally we branch to the routine we just moved.

 M32K     DC    A(1024*32)         * CONSTANT 32K
 MASK     DC    A(X'00FFF000')     * BOUNDARY MASK
 MVC      MVC   0(1,R4),0(R2)      * EXECUTED INSTRUCTION

Finally we define our constants.

It is important to point out that we don’t do any relocation of pointers for the routine we copy to high memory.  It is important that when we write the code for our loader we avoid using any relocatable constants.  For example if we used something like:

PTR      DC    A(BUFFER)

we would generate a relocatable constant.  Once we copied the routine to high memory the address pointer would still refer to the original location in low memory.  Instead we need to calculate the pointer address at run time and instead use something like:

         LA    R2,BUFFER
         ST    R2,PTR  
PTR      DC    A(0)

This will give us the proper value in our pointer.

The Assembler output will help  us determine if we have used any relocatable addresses in our program.  Near the end of the assembly listing we find the Relocation Dictionary.  It provides us with a list of all the relocatable symbols in the program and the address where it is located.  If we find any relocatable symbols that are contained within our code to be relocated we can then go back to the source and correct the problem.

                                     RELOCATION DICTIONARY
  0001     0001      08     000005
  0001     0001      08     000D81
  0001     0001      08     000D89
  0001     0001      08     000D91
  0001     0001      08     000D99

[Next – Nucleus Load Module Loader]