This is a modification of the RELOC1 routine, which showed how to implement relocatable "short" CALLs, within the range of relative jumps. Here the CALLs are "long", ie. the subroutine can he anywhere within the 61k addressing range. As before, the sequence 'EX (SP),HL and JP (HL)' returns with the address of the byte following the RST 6, but the target address for the 'JP (HL)' is obtained by adding the distances between the current location and the start of the subroutine. This distance is in the register OK and is computed at the time of assembly. Once we have the target address, the register DK is loaded with the distance between the byte we are jumping to and the byte we want to return to, so that the subroutine can place the correct return address or. the stack, by adding the displacement to the register HL before exchanging the top of the stack and the contents of HL. Note that this displacement is negative, but appears as a large number. Adding this number has the same effect as subtracting its complement.  
The subroutine is again the binary-to-hex conversion, but is cailed only twice to deal with the low byte of the entered number. This is sufficient to demonstrate that the HL register is not changed by the manipulations, until the final long jump is implemented. Incidentally, the conversion algorithm is an inspired piece of programming attributed to a certain Bill Byerley of INTEL, the designers of the 8080 processor. There is no example of relocatable buffer addressing, but it could be implemented in a way similar to the final jump. It must be remembered that the initial contents of HL is saved on the stack by the sequence at RST 6; unless it is used as a return from a subroutine, the top of stack must be cleared to prevent an eventual return to a meaningless address, leading to a crash. For a program which addresses buffers more often than subroutines, it would be more efficient to initialise RST 6 to 'POP HL and JP (HL)' or 'POP IY and JP (IY)' , which would not leave anything on the stack. But relocatable buffers cou'd be implemented by dimensioning an integer array, passing the address of its first element to the routine, then using indexed addressing to store and retrieve values. There are. many ways to overcome the relocatibility problem, but for long complex routines it may be simpler to use a relocator at the time of loading or initialisation. A number of examples have appeared in the magazines, using both EASIC and machine language. I prefer the method of storing the routine in an integer array (as used in these examples) and adjusting any absolute addresses just before cach CALL from BASIC. There is one possible problem: the array may lie under the ROM if the BASIC program is short, so that the selection of the lower ROM would lead to a crash. I found that out the hard way when I tried to copy the lower ROM to RAM, but normally there is no occasion to want to select the lower ROM. The operating system handles the ROM selection and restoration as required, without getting lost. (The solution to the problem was to store the routine in a string, just below the upper ROM.) TAU |