PHASE.DOC by Mike Rubenstein PHASED code ----------- One of the limitations of this assembler is the lack of a .PHASE direc- tive. This directive causes the assembler to generate addresses for a different section of memory for labels than the actual place the code is to be loaded. This is important for the Kaypro since when the ROM is called, the lower 32K of memory is no longer available. Simply ORGing at a higher location later in the program and jumping there will cause the entire area of memory between 100H and the end point of the program to be saved resulting in a huge .COM file when loaded with LOAD.COM. There are many ways to phase code and still end up with a reasonable sized .COM file. Here I will present two of the most common methods. Label+OFFSET Method ------------------- In order for code to be assembled in one area to run in another our only concern is how the addresses are calculated by the assembler. Normally, an assembler sets a location counter when it sees an ORG pseudo-op. As it produces each byte of the it increments the location counter to cal- culate the next address. If it finds a label, it sets the label's ad- dress according to this location counter. The programmer has another method of setting the address of labels, with EQU. If every label in the program takes the form of Label+OFFSET where the offset is a con- stant, then the assembler will produce the code to run in high memory while creating a file that will load in low memory. The following short program which re-loads your monitor ROM from the ROM to RAM illustrates this. ;*********************************************************************** ; ; Rom Save Program ; Run and then enter SAVE 16 ROM.COM ; ROM.COM will contain object code of your monitor ROM ;*********************************************************************** ORG 100h ; YES EQU 0FFH NO EQU 0 ; OLD EQU YES YES if not a Kaypro 10 or 4-84 ; IF OLD SYSPRT EQU 1CH Old Kaypro 2's and 4's ELSE SYSPRT EQU 14H 10's, 4-84's, 2-84's ENDIF ; OFFSET EQU 8000h Offset for calculating high addresses ; LD DE,HISTRT The destination of the High memory code LD HL,LODEND+1 The source code is just beyond this ; loader LD BC,HIEND-HISTRT The number of bytes to move (end-start) LDIR Move it up there JP HISTRT Jump to it ; LODEND NOP To calculate end of loader/start of high ; memory code segment ; HISTRT EQU $+OFFSET Begin using offset ; IN A,(SYSPRT) Get present sysport data SET 7,A Bank select bit OUT (SYSPRT),A CALL MOVIT Move the code routine IN A,(SYSPRT) RES 7,A Back to ram bank OUT (SYSPRT),A CALL TPAMOV Now move to 100H for save JP 0 Back to CP/M ; MOVIT EQU $+OFFSET ; LD HL,0 Source is at 0 (in ROM ) LD DE,OFFSET+1000H Load above us LD BC,1000h Ppick up 4K (2732) LDIR RET ; TPAMOV EQU $+OFFSET ; LD HL,OFFSET+1000H Destination becomes source LD DE,100H Move to TPA start LD BC,1000H 4K bytes to move LDIR RET ; HIEND EQU $+OFFSET ; end of code to be relocated ; END Assemble this program (the source is on the disk as PHASE1.AZM, so you don't have to type it in.) Examine the listing file. Notice that the assembler generated high memory addresses though the program loads low. Using DDT.COM ------------- With this method you would split the above program into two parts, the loader and the code that is to be relocated. You can assemble the load- er and pick an arbitrary source address for the code to be relocated (say 200h). Then you can assemble the relocatable portion with an high ORG, like 8000H. Now you can join the two HEX files together with the program DDT.COM, reading in the high portion with an OFFSET. To get the offset, use DDT's Hex sum and difference command in the form of: -H, The second number will be the OFFSET. The program we wrote above would go together like this. *********************************************************************** ; LOADER.AZM Loads relocating code to its destination *********************************************************************** ; ORG 100H ; BYTCNT EQU 100H We can either supply a value here that ; we know will load enough code or assem- ; ble the high code first and let the as- ; sembler give us this value (examine ; print file) ; HISTRT EQU 8000H Where the relocation code goes HILOAD EQU 200H Where the other file goes ; LD DE,HISTRT The destination of the High memory code LD HL,HILOAD The source code is just past this loader LD BC,BYTCNT The number of bytes to move (end-start) LDIR Move it up there JP HISTRT Jump to it, memory code segment END *********************************************************************** ; PHASE2.AZM ; Relocate with DDT *********************************************************************** ; YES EQU 0FFH NO EQU 0 ; OLD EQU FALSE ; IF OLD SYSPRT EQU 1CH Old Kaypro 2's and fours ELSE SYSPRT EQU 14H 10's, 4-84's, 2-84's ENDIF ; BYTCNT EQU HIEND-HISTRT ; ORG 8000h ; HISTRT IN A,(SYSPRT) Get present sysport data SET 7,A Bank select bit OUT (SYSPRT),A CALL MOVIT Move the code routine IN A,(SYSPRT) RES 7,A Back to ram bank OUT (SYSPRT),A CALL TPAMOV Now move to 100H for save JP 0 Back to CP/M ; MOVIT LD HL,0 Source is at 0 (in ROM ) LD DE,9000H Load above us LD BC,1000h Pick up 4K (2732) LDIR RET ; TPAMOV LD HL,9000H Destination becomes source LD DE,100H Move to TPA start LD BC,1000H 4K bytes to move LDIR RET ; HIEND EQU $ ; END Now we can use DDT to join the two files: DDT LOADER.HEX -200,8000 -8200 8200 In this case both numbers are the same (we want second IPHASE2.HEX Prepare to load file R8200 Read in with offset ^C Exit to CPM SAVE 1 PHASE3.COM And the com file is created ORGing High (CP/M modifications) -------------------------------- DDT.COM can be used to load .HEX files anywhere in memory despite where the load point (ORG) was set. It does this by reading the file in with a negative offset with the 'R' command. Usually CP/M is modified by saving the SYSGEN image and then overlaying the image with the modified section and re-SYSGENing. Let's say you wrote a new BIOS for your Kaypro. The BIOS for the old Kaypros ORGed at FA00H. You assemble it with the assembler with the ORG at FA00H. The object file is KBIOS.HEX If you want to overlay the present bios with your new BIOS immediately to see if it works it is done as follows: Enter DDT by entering DDT IKBIOS.HEX This sets up DDT for a file read. R Actually reads the file in and overlays your old bios with the binary code. ^C Returns you to CP/M and if all is well with your new BIOS, you will warm boot Now you want a permanent copy of your new BIOS on your system tracks. Once done, you will be able to copy your new system onto any disk with SYSGEN. SYSGEN copies the system into memory but not at the same place the system runs. The BIOS image actually begins at 1F80H in the SYSGEN image. We must read the file in at 1F80H even though it ORGs at FA00H. We can do this with DDT also. First we must save the SYSGEN image to a file. SYSGEN KAYPRO SYSGEN V2.2 SOURCE DRIVE (OR RETURN TO SKIP)a Get the system from A: SOURCE ON A THEN RETURN Enter a carriage return DESTINATION DRIVE (OR RETURN TO REBOOT) Enter a carriage return save 40 cpm.com Save it to a file Now we use DDT to work on it DDT CPM.COM H1F80,FA00 We ask for the sum and difference of desired address - load address DDT prints this. The second number is the offset IKBIOS.HEX R ^C Now when we return to CP/M we run sysgen to save the new image to system tracks. SYSGEN KAYPPRO SYSGEN V2.2 SOURCE DRIVE (OR RETURN TO SKIP) Enter return, use the memory image DESTINATION DRIVE (OR RETURN TO REBOOT) We will put it on B DESTINATION ON B THEN RETURN Another return FUNCTION COMPLETE DESTINATION DRIVE (OR RETURN TO REBOOT) One more return Now when when we boot with the disk in drive B the new system will be loaded. --------------------------------- end ----------------------------------