keep obj/out mcopy out.mac **************************************************************** * * Ouput Module * * This module handles writing the output file and locating the * proper load segment for code segments. * **************************************************************** copy directPage **************************************************************** * * OutCommon - global data for the segment module * **************************************************************** * OutCommon data ; ; Constants ; nameSize equ 10 size of a load segment name dictGrowSize equ 4096 grow size for the dictionary buffer dynGrowSize equ 1024 grow size for synamic segment buffer ; ; global variables ; expressSegment ds 2 express segment number keepRefnum ds 2 keep file reference number lastLoadNumber ds 4 last load number allocated loadList ds 4 head of load segment list loadNamePtr ds 4 pointer to the name of the load segment ; ; Dynamic segment information ; dynHandle ds 4 handle of the dynamic segment buffer dynSize ds 2 bytes left in the buffer dynBuffSize ds 4 total memory in the segment buffer dynStart ds 4 ptr to the start of the buffer dynSegment ds 2 dynamic segment number ; ; Current load segment information ; loadNext ds 4 pointer to the next load segment loadLast ds 4 pointer to the last load segment loadPtr ds 4 pointer to the storage location for this record loadNumber ds 2 number of this load segment loadType ds 2 load segment type loadORG ds 4 load segment origin loadAlign ds 4 load segment aligment loadBankSize ds 4 load segment bank size loadName ds nameSize name of the load segment loadSeg ds 4 handle of the segment buffer loadSegStart ds 4 start of the segment buffer loadPC ds 4 size of the load segment loadOp ds 4 op disp for the segment buffer loadOpSt ds 4 op at start of current lConst loadDict ds 4 handle of the dictionary buffer loadDictStart ds 4 start of the dictionary buffer loadDictSize ds 2 bytes left in the dictionary buffer loadDp ds 4 dp disp for the dictionary buffer loadPass2 ds 2 are we ready for pass 2? loadEnd anop end of the record loadSize equ loadEnd-loadNext size of a load module record (even!) end **************************************************************** * * AddEnd - add an end record to the dictionary * * Inputs: * loadNext... - load segment record * **************************************************************** * AddEnd private using OutCommon lda loadDictSize make sure there is room in the dictionary bne lb1 jsr ExpandDictBuffer lb1 short M save the end marker lda #0 sta [dp] long M inc4 dp update dp dec loadDictSize update loadDictSize rts end **************************************************************** * * AddSegment - add a segment to the expressload table * * Inputs: * r8 - pointer to the segment to add * r4,r8 - expressload list pointers * expOffset - segment offset pointer * expMap - segment map pointer * expHeader - segment header map * expressSegment - express segment number * **************************************************************** * AddSegment private using OutCommon jsr MoveSegment move the segment ot the new list sub4 expHeader,expOffset,r12 set the segment offset lda r12 sta [expOffset] ldy #6 zero the reserved words lda #0 lb1 sta [expOffset],Y dey dey bne lb1 add4 expOffset,#8 update the offset pointer ldy #loadNumber-loadNext get the old segment number lda [r4],Y dec A set it's mapped segment asl A tay lda expressSegment sta [expMap],Y ldy #loadNumber-loadNext set the new segment number sta [r4],Y inc expressSegment update segment number add4 fMark,#69+5 allow for the segment header & lconst move4 fMark,mark1 set the lconst mark ldy #loadPC-loadNext find the segment size lda [r4],Y sta len1 iny iny lda [r4],Y sta len1+2 add4 fMark,len1 allow for the segment body move4 fMark,mark2 set the reloc mark ldy #loadDp-loadNext find the reloc size lda [r4],Y sta len2 iny iny lda [r4],Y sta len2+2 ora len2 if len2 = 0 then bne lb1a stz mark2 mark2 = 0 stz mark2+2 lb1a add4 fMark,len2 allow for the dictionary inc4 fMark allow for the end mark ldy #loadBankSize-loadNext set the bank size lda [r4],Y sta bankSize iny iny lda [r4],Y sta bankSize+2 ldy #loadType-loadNext set the segment type lda [r4],Y sta kind ldy #loadOrg-loadNext set the origin lda [r4],Y sta org iny iny lda [r4],Y sta org+2 ldy #loadAlign-loadNext set the alignment factor lda [r4],Y sta align iny iny lda [r4],Y sta align+2 ldy #loadNumber-loadNext set the segment number lda [r4],Y sta segNum ldx #nameSize-2 set the segment name ldy #loadName-loadNext+nameSize-2 lb2 lda [r4],Y sta name,X dey dey dex dex bpl lb2 ldy #segEnd-mark1-1 move the header to the express segment short M lb3 lda mark1,Y sta [expHeader],Y dey bpl lb3 long M add4 expHeader,#69 update the segment header pointer rts mark1 ds 4 lConst file mark len1 ds 4 lConst length mark2 ds 4 reloc file mark len2 ds 4 reloc length dc i1'0' undefined dc i1'0' label length dc i1'4' number length dc i1'2' version bankSize ds 4 bank size kind ds 2 segment type dc i'0' undefined org ds 4 origin align ds 4 alignment dc i1'0' numsex dc i1'0' undefined segNum ds 2 segment number dc i4'0' segment entry dc i'lname-len1' disp to name dc i'segend-mark1' disp to body lname dc 10c' ' load name dc i1'10' segment name length name ds 10 segment name segend anop end **************************************************************** * * CheckHeader - check the header parameters * * Inputs: * segOrg - origin for this segment * segAlign - alignment for this segment * segType - type for this segment * segBanksize - banksize for this segment * loadType - load segment type * loadORG - load segment origin * loadAlign - load segment aligment * loadBankSize - load segment bank size * * Outputs: * loadType - load segment type * loadORG - load segment origin * loadAlign - load segment aligment * loadBankSize - load segment bank size * **************************************************************** * CheckHeader private using OutCommon using Common ; ; Set the load segment type ; lda loadPC if at the start of the segment then ora loadPC+2 bne st1 lda segType use segType and #$FEFF sta loadType bra st4 else st1 lda segType or in the or flags and #$1D00 ora loadType sta loadType lda segType mask out missing and flags and #$E200 ora #$1DFF and loadType sta loadType lda loadType get the type without flags and #$007F sta r0 lda segType and #$007F cmp r0 if they do not match then beq st4 cmp #1 if seg is data then bne st2 lda r0 if not load in [code,init,dp] then beq st4 cmp #$10 beq st4 cmp #$12 beq st4 err15 ph4 #0 flag segment conflict ph2 #15 jsr Error bra st4 st2 cmp #0 else if seg in [code,init,dp] then beq st3 cmp #$10 beq st3 cmp #$12 bne err15 st3 lda r0 if load = data then cmp #1 bne err15 lda loadType use seg type and #$FF00 sta loadType lda segType and #$007F ora loadType sta loadType ! else flag the error st4 anop endif lda bankOrg if bankOrg then beq st5 lda loadType bank org the program ora #$0100 sta loadType st5 anop endif ; ; Set the load segment origin (pass 1) ; lda pass branch if pass 2 cmp #2 beq or0 lda segOrg skip if org is 0 ora segOrg+2 jeq or4 lda loadPC if at the start of the segment then ora loadPC+2 ora loadOrg ora loadOrg+2 bne po1 move4 segOrg,loadOrg loadOrg = segOrg bra po3 else po1 sub4 segOrg,loadOrg,r0 update the pc lda r2 bmi po3 cmpl r0,pc blt po3 move4 r0,pc po3 anop endif bra or4 ; ; Set the load segment origin (pass 2) ; or0 lda segOrg skip if org is 0 ora segOrg+2 beq or4 lda loadPC if at the start of the segment then ora loadPC+2 ora loadOrg ora loadOrg+2 bne or1 move4 segOrg,loadOrg loadOrg = segOrg bra or3 else or1 sub4 segOrg,loadOrg,r0 update the pc sub4 r0,pc lda r2 bpl or2 if disp is negative then ph4 #0 Error(NULL,3) ph2 #3 jsr Error bra or3 else or2 lda r0 define DS bytes to fill space ora r2 beq or3 jsr DefineDS or3 anop endif jsr CheckAlignOrg check for conflicts between align,org or4 anop ; ; Set the load segment alignment (pass 1) ; lda pass branch if pass 2 cmp #2 beq sa0 lda segAlign skip if alignment is 0 ora segAlign+2 jeq sa4 lda loadPC if at the start of the segment then ora loadPC+2 ora loadAlign ora loadAlign+2 bne la1 move4 segAlign,loadAlign loadAlign = segAlign bra la3 else la1 cmpl loadAlign,segAlign if loadAlign < segAlign then bge la2 move4 segAlign,loadAlign loadAlign = segAlign la2 move4 segAlign,r0 PrepareAlign(segAlign) jsr PrepareAlign la3 anop endif bra sa4 ; ; Set the load segment alignment (pass 2) ; sa0 lda segAlign skip if alignment is 0 ora segAlign+2 beq sa4 ph4 segAlign make sure the align is a power of 2 jsr CheckAlign lda loadPC if at the start of the segment then ora loadPC+2 ora loadAlign ora loadAlign+2 bne sa1 move4 segAlign,loadAlign loadAlign = segAlign bra sa3 else sa1 cmpl loadAlign,segAlign if loadAlign < segAlign then bge sa2 move4 segAlign,loadAlign loadAlign = segAlign sa2 move4 segAlign,r0 DefineAlign(segAlign) jsr DefineAlign sa3 anop endif jsr CheckAlignOrg check for conflicts between align,org sa4 anop ; ; Set the load segment bank size ; lda pass branch if pass 2 cmp #2 beq rt1 lda loadBankSize if loadBanksize = 0 ora loadBanksize+2 beq bs1 cmpl segBanksize,loadBanksize or ((segBanksize < loadBanksize) bge bs2 and (segBanksize <> 0)) then lda segBanksize ora segBanksize+2 beq bs2 bs1 move4 segBankSize,loadBankSize loadBankSize = segBankSize bs2 anop rt1 rts ; ; CheckAlignOrg - make sure the align and org do not conflict ; CheckAlignOrg anop lda loadAlign if loadAlign <> 0 then ora loadAlign+2 beq ca2 sub4 loadAlign,#1,r0 if loadOrg & (loadAlign-1) then lda r0 and loadOrg bne ca1 lda r2 and loadOrg+2 beq ca2 ca1 ph4 #0 Error(NULL,21) ph2 #21 jsr Error ca2 rts end **************************************************************** * * CompactCInterseg - compact a cInterseg record * * Inputs: * r0 - ptr to the cInterseg record * r4 - ptr to the end of the dictionary * dp - ptr to the next free byte in the dictionary * **************************************************************** * CompactCInterseg private using Common using OutCommon ; ; See if the record can be compacted ; lda [r0] length must be 2 or 3 xba and #$00FF cmp #2 beq ck1 cmp #3 jne nc1 ck1 sta length cmp #3 if length = 3 then bne ck2 ldy #2 shift count must be 0 lda [r0],Y and #$00FF jne nc1 stz shift lda #2 set the record type sta recordType ldy #5 set the segment number lda [r0],Y and #$00FF sta segment bra ck3 else {if length = 2 then} ck2 ldy #5 segment number must be <= 12 lda [r0],Y and #$00FF sta segment cmp #13 jge nc1 ldx express if express then beq ck2a cmp #12 don't use 12, either jeq nc1 ck2a clc set the record type for shift 0 lda segment adc #13 sta recordType ldy #2 shift must be 0 or -16 lda [r0],Y and #$00FF sta shift beq ck3 cmp #$00F0 jne nc1 add2 recordType,#12 set the record type for shift -16 ck3 anop ; ; Create a Super record ; lda #13 create the record header cmp loadDictSize make sure there is room in the blt sp1 dictionary jsr ExpandDictBuffer sp1 add4 dp,#1,recordLengthPtr save a pointer to the length field sub4 recordLengthPtr,loadDictStart short M set the op code lda #$F7 sta [dp] ldy #5 set the super record type lda recordType sta [dp],Y long M add4 dp,#6 skip the super record header sub2 loadDictSize,#6 ldy #4 set the segment offset page lda [r0],Y and #$00FF sta page beq pg3 if page <> 0 then sta r12 while (r12 := page) > $7F do pg1 lda r12 cmp #$80 blt pg2 short M write a skip page for $7F pages lda #$FF sta [dp] long M inc4 dp dec loadDictSize sub2 r12,#$7F r12 -= $7F bra pg1 endwhile pg2 lda r12 if r12 <> 0 then beq pg3 short M write a skip page for r12 pages ora #$80 sta [dp] long M inc4 dp dec loadDictSize pg3 anop move4 dp,r12 initialize the page counter short M lda #$FF sta [r12] long M inc4 dp skip the page counter dec loadDictSize move4 r0,r8 for each dictionary record do sp2 cmpl r8,r4 jeq sp14 lda [r8] if it is a Reloc then and #$00FF cmp #$E2 bne sp3 add4 r8,#11 skip the record bra sp2 loop sp3 cmp #$75 if it is a skipped cReloc or beq sp4 cReloc then cmp #$F5 bne sp5 sp4 add4 r8,#7 skip the record bra sp2 loop sp5 cmp #$76 if it is a skipped cInterseg then bne sp6 add4 r8,#8 skip the record bra sp2 loop sp6 cmp #$E3 if it is an Interseg then bne sp7 add4 r8,#15 skip the record bra sp2 loop sp7 ldy #2 if the cInterseg is a different type short M then lda [r8],Y cmp shift bne sp7a dey lda [r8],Y cmp length bne sp7a cmp #3 beq sp8 ldy #5 lda [r8],Y cmp segment beq sp8 sp7a long M skip the record add4 r8,#8 brl sp2 loop sp8 long M make sure there is room in the lda #5 dictionary cmp loadDictSize blt sp9 sub4 r12,loadDictStart jsr ExpandDictBuffer add4 r12,loadDictStart sp9 short M if r8^.page <> page then sec ldy #4 lda [r8],Y sbc page beq sp13 dec A if r8^.page - page > 1 then beq sp12 sp10 cmp #$80 record a page skip blt sp11 tax lda #$FF sta [dp] long M inc4 dp dec loadDictSize short M txa sec sbc #$7F bra sp10 sp11 cmp #0 beq sp12 ora #$80 sta [dp] long M inc4 dp dec loadDictSize short M sp12 ldy #4 record the new page lda [r8],Y sta page lda #$FF set up a record count sta [dp] long M move4 dp,r12 inc4 dp dec loadDictSize short M sp13 lda [r12] increment the record count inc A sta [r12] ldy #3 set the offset lda [r8],Y sta [dp] long M inc4 dp dec loadDictSize short M mark the record lda [r8] and #$7F sta [r8] long M add4 r8,#8 skip the record brl sp2 loop sp14 anop set the super record length add4 recordLengthPtr,loadDictStart,r12 sub4 dp,r12,recordLengthPtr sub4 recordLengthPtr,#4 ldy #2 lda recordLengthPtr sta [r12] lda recordLengthPtr+2 sta [r12],Y rts ; ; Cannot compact - put the unchanged record in the dictionary ; nc1 lda #8 make sure there is room in the cmp loadDictSize dictionary blt nc2 jsr ExpandDictBuffer nc2 ldy #6 move the record nc3 lda [r0],Y sta [dp],Y dey dey bpl nc3 add4 dp,#8 skip the record sub2 loadDictSize,#8 add4 r0,#8 rts ; ; Local data ; recordLengthPtr ds 4 pointer to the super record length field page ds 2 current cReloc page number length ds 2 length of the cReloc fields shift ds 2 shift count segment ds 2 segment number recordType ds 2 type of the Super record end **************************************************************** * * CompactCReloc - compact a cReloc record * * Inputs: * r0 - ptr to the cReloc record * r4 - ptr to the end of the dictionary * dp - ptr to the next free byte in the dictionary * **************************************************************** * CompactCReloc private using OutCommon ; ; See if the record can be compacted ; lda [r0] length must be 2 or 3 xba and #$00FF cmp #2 beq ck1 cmp #3 jne nc1 ck1 sta length ldy #2 shift count must be 0 lda [r0],Y and #$00FF jne nc1 ; ; Create a Super record ; lda #13 create the record header cmp loadDictSize make sure there is room in the blt sp1 dictionary jsr ExpandDictBuffer sp1 add4 dp,#1,recordLengthPtr save a pointer to the length field sub4 recordLengthPtr,loadDictStart short M set the op code lda #$F7 sta [dp] ldy #5 set the super record type lda length and #$01 sta [dp],Y long M add4 dp,#6 skip the super record header sub2 loadDictSize,#6 ldy #4 set the segment offset page lda [r0],Y and #$00FF sta page beq pg3 if page <> 0 then sta r12 while (r12 := page) > $7F do pg1 lda r12 cmp #$80 blt pg2 short M write a skip page for $7F pages lda #$FF sta [dp] long M inc4 dp dec loadDictSize sub2 r12,#$7F r12 -= $7F bra pg1 endwhile pg2 lda r12 if r12 <> 0 then beq pg3 short M write a skip page for r12 pages ora #$80 sta [dp] long M inc4 dp dec loadDictSize pg3 anop move4 dp,r12 initialize the page counter short M lda #$FF sta [r12] long M inc4 dp skip the page counter dec loadDictSize move4 r0,r8 for each dictionary record do sp2 cmpl r8,r4 jeq sp14 lda [r8] if it is a Reloc then and #$00FF cmp #$E2 bne sp3 add4 r8,#11 skip the record bra sp2 loop sp3 cmp #$75 if it is a skipped cReloc then bne sp4 add4 r8,#7 skip the record bra sp2 loop sp4 cmp #$F6 if it is a cInterseg or skipped beq sp5 cInterseg then cmp #$76 bne sp6 sp5 add4 r8,#8 skip the record bra sp2 loop sp6 cmp #$E3 if it is an Interseg then bne sp7 add4 r8,#15 skip the record bra sp2 loop sp7 ldy #1 if the cReloc is a different type then lda [r8],Y cmp length (checks length and shift=0) beq sp8 add4 r8,#7 skip the record bra sp2 loop sp8 lda #5 make sure there is room in the cmp loadDictSize dictionary blt sp9 sub4 r12,loadDictStart jsr ExpandDictBuffer add4 r12,loadDictStart sp9 short M if r8^.page <> page then sec ldy #4 lda [r8],Y sbc page beq sp13 dec A if r8^.page - page > 1 then beq sp12 sp10 cmp #$80 record a page skip blt sp11 tax lda #$FF sta [dp] long M inc4 dp dec loadDictSize short M txa sec sbc #$7F bra sp10 sp11 cmp #0 beq sp12 ora #$80 sta [dp] long M inc4 dp dec loadDictSize short M sp12 ldy #4 record the new page lda [r8],Y sta page lda #$FF set up a record count sta [dp] long M move4 dp,r12 inc4 dp dec loadDictSize short M sp13 lda [r12] increment the record count inc A sta [r12] ldy #3 set the offset lda [r8],Y sta [dp] long M inc4 dp dec loadDictSize short M mark the record lda [r8] and #$7F sta [r8] long M add4 r8,#7 skip the record brl sp2 loop sp14 anop set the super record length add4 recordLengthPtr,loadDictStart,r12 sub4 dp,r12,recordLengthPtr sub4 recordLengthPtr,#4 ldy #2 lda recordLengthPtr sta [r12] lda recordLengthPtr+2 sta [r12],Y rts ; ; Cannot compact - put the unchanged record in the dictionary ; nc1 lda #8 make sure there is room in the cmp loadDictSize dictionary blt nc2 jsr ExpandDictBuffer nc2 ldy #6 move the record nc3 lda [r0],Y sta [dp],Y dey dey bpl nc3 add4 dp,#7 skip the record sub2 loadDictSize,#7 add4 r0,#7 rts ; ; Local data ; recordLengthPtr ds 4 pointer to the super record length field page ds 2 current cReloc page number length ds 2 length of the cReloc fields end **************************************************************** * * CompactSegment - compact a single segment * * Inputs: * LoadNext... - segment record * **************************************************************** * CompactSegment private using OutCommon using Common lda loadDict if there is no dictionary then ora loadDict+2 bne lb1 rts return lb1 move4 loadDict,dictHandle save the dictionary handle move4 loadDictStart,r0 get a pointer to the dictionary move4 dp,r4 get a pointer to the dictionary end stz loadDictStart zero the current load dictionary stz loadDictStart+2 stz loadDict stz loadDict+2 stz loadDp stz loadDp+2 stz dp stz dp+2 stz loadDictSize stz loadDictSize+2 lb2 cmpl r0,r4 for each dictionary entry do jeq lb12 lda [r0] if r0^ = cReloc then and #$00FF cmp #$00F5 bne lb3 jsr CompactCReloc compact the record bra lb2 loop lb3 cmp #$75 if r0^ = skipped cReloc then bne lb4 add4 r0,#7 skip the record bra lb2 loop lb4 cmp #$E2 if r0^ = Reloc then bne lb7 lda #12 make sure there is room in the cmp loadDictSize dictionary blt lb5 jsr ExpandDictBuffer lb5 ldy #10 move the record lb6 lda [r0],Y sta [dp],Y dey dey bpl lb6 add4 dp,#11 skip the record sub2 loadDictSize,#11 add4 r0,#11 bra lb2 loop lb7 cmp #$F6 if r0^ = cInterseg then bne lb8 jsr CompactCInterseg compact the record bra lb2 loop lb8 cmp #$76 if r0^ = skipped cInterseg then bne lb9 add4 r0,#8 skip the record brl lb2 loop ! (condition must be true) if r0^ = Interseg then lb9 lda #16 make sure there is room in the cmp loadDictSize dictionary blt lb10 jsr ExpandDictBuffer lb10 ldy #14 move the record lb11 lda [r0],Y sta [dp],Y dey dey bpl lb11 add4 dp,#15 skip the record sub2 loadDictSize,#15 add4 r0,#15 brl lb2 loop lb12 ph4 dictHandle free the old dictionary buffer _DisposeHandle rts dictHandle ds 4 old dictionary handle end **************************************************************** * * CreateDynamicSegment - create the dynamic segment (if any) * * Inputs: * dynSegment - dynmaic segment number; 0 if none * dynStart - start of the dynamic segment * dy - next byte in the buffer * **************************************************************** * CreateDynamicSegment private using OutCommon lda dynSegment quit if there is no segment bne lb0 rts lb0 lda dynSize write the trailing 4 bytes cmp #4 bge lb1 jsr ExpandDynamicBuffer lb1 ldy #2 lda #0 sta [dy] sta [dy],Y add4 dy,#4 sub4 dy,dynStart,r0 set the size of the lConst sub4 r0,#5 move4 dynStart,r4 lda #$F2 sta [r4] ldy #1 lda r0 sta [r4],Y iny iny lda r2 sta [r4],Y move #0,loadNext,#loadSize clear all entries lda dynSegment set the segment number sta loadNumber lda #2 set the segment type sta loadType lla loadBankSize,$10000 set the load segment bank size move jumpName,loadName,#nameSize set the segment name move4 dynHandle,loadSeg set the segment buffer handle move4 dynStart,loadSegStart set the load segment start sub4 dy,dynStart,loadPc set the segment size sub4 loadPc,#5 move4 loadPc,pc move4 dy,op set the segment pointer sub4 dy,dynStart,loadOp set the segment displacement inc loadPass2 ready for pass 2 stz dp no dictionary pointer stz dp+2 jsr SaveSegment rts jumpName dc c'~JumpTable' end **************************************************************** * * CreateFile - make sure an output file exists * * Inputs: * kname - keep file name * **************************************************************** * CreateFile private using OutCommon move4 kname,giPathname see if a file exists OSGet_File_Info giRec bcs lb1 lda giFiletype yes -> make sure it is an OBJ file cmp #$B3 blt err7 cmp #$BF+1 bge err7 rts lb1 move4 kname,crPathname no file exists, so create one OSCreate crRec bcs err12 rts err12 lda #12 file write error jmp TermError err7 lda #7 Could not overwrite existing file jmp TermError ; ; Local data ; giRec dc i'3' GetFileInfo record giPathname ds 4 ds 2 giFiletype ds 2 crRec dc i'4' crPathname ds 4 dc i'$C3' dc i'EXE' dc i4'$0100' end **************************************************************** * * DecimalVariable - convert an OS string to a decimal value * * Inputs: * r0 - pointer to the shell variable value * * Outputs: * C - set if all characters are digits, else clear * X-A - value (if C set); least sig. 32 bits only * **************************************************************** * DecimalVariable private lda [r0] get a loop counter sta r12 stz r8 set the initial value stz r10 add4 r0,#2,r4 get a character pointer lb1 lda [r4] if the character is not a digit then and #$00FF return false cmp #'0' blt lb3 cmp #'9'+1 bge lb3 mul4 r8,#10 r8 = r8*10 + value(r4^) lda [r4] and #$000F clc adc r8 sta r8 bcc lb2 inc r10 lb2 inc4 r4 loop dec r12 bne lb1 lda r8 return value ldx r10 sec rts lb3 clc return false rts end **************************************************************** * * DoCompact - compact the dictionaries * **************************************************************** * DoCompact private using OutCommon using Common jsr SaveSegment save the current segment lda #1 set the segment number sta segment lb1 move4 loadList,r0 find the proper segment lb2 ldy #loadNumber-loadNext lda [r0],Y cmp segment bne lb3 jsr GetSegment get the segment jsr CompactSegment compact the segment jsr SaveSegment save the segment inc segment next segment bra lb1 start the search over lb3 ldy #2 next segment pointer lda [r0],Y tax lda [r0] sta r0 stx r2 ora r2 bne lb2 move4 loadList,r0 done - get a segment back jsr GetSegment rts return segment ds 2 segment number end **************************************************************** * * DynamicCheck - if any segment is dynamic, set up a jump table * * Inputs: * loadList - list of current load segments * loadNext... - active load segment * lastLoadNumber - last load number allocated * * Outputs: (if there is a dynamic segment) * dynHandle - handle of the synamic segment * dynStart - start of the dynamic segment * dynSize - size of the dynamic segment * dy - pointer to the next spot in the dynamic segment * dynSegment - dynamic segment number * **************************************************************** * DynamicCheck start using OutCommon ; ; See if any segment is dynamic ; lda loadType check the current segment bmi pr1 move4 loadList,r0 check the segments in the segment list cs1 lda r0 ora r2 beq cs2 ldy #loadType-loadNext lda [r0],Y bmi pr1 ldy #2 lda [r0],Y tax lda [r0] sta r0 stx r2 bra cs1 cs2 rts ; ; Prepare for dynamic segment output ; pr1 stz dy zero the pointer stz dy+2 stz dynSize zero the size stz dynBuffSize no memory in the buffer stz dynBuffSize+2 stz dynHandle no handle, yet stz dynHandle+2 stz dynStart initialize the field stz dynStart+2 jsr ExpandDynamicBuffer get an initial buffer add4 dy,#5 create space for the lConst opcode ldy #6 insert the 8 leading zeros lda #0 pr2 sta [dy],Y dey dey bpl pr2 sub2 dynSize,#13 add4 dy,#8 lda lastLoadNumber get a segment number inc A sta lastLoadNumber sta dynSegment rts end **************************************************************** * * ExpandDictBuffer - expand the dictionary buffer * * Inputs: * loadDict - handle of the dictionary buffer, nil for none * loadDictSize - size of the dictionary buffer * * Outputs: * loadDict - handle of the dictionary buffer * loadDictStart - start of the dictionary buffer * loadDictSize - size of the dictionary buffer * dp - start of the dictionary buffer * * Notes: * Other than dp, direct page is not disturbed. * **************************************************************** * ExpandDictBuffer start using Common using OutCommon lda loadDict if there is no buffer then ora loadDict+2 bne lb1 la loadDictSize,dictGrowSize set the dictionary size pha get a new buffer pha ph4 #dictGrowSize ph2 userID ph2 #$8000 ph4 #0 _NewHandle jcs oom pl4 loadDict stz loadDP loadDP = 0 stz loadDP+2 brl lb2 else lb1 sub4 dp,loadDictStart,loadDP get the displacement ph4 loadDict unlock the handle _HUnlock pha get the current handle size pha ph4 loadDict _GetHandleSize clc set the new size lda 1,S adc #dictGrowSize sta 1,S lda 3,S adc #^dictGrowSize sta 3,S ph4 loadDict expand the buffer _SetHandleSize bcs oom ph4 loadDict lock the handle _HLock add2 loadDictSize,#dictGrowSize update the free space lb2 anop endif move4 loadDict,dp dereference the handle ldy #2 lda [dp] sta loadDictStart lda [dp],Y sta loadDictStart+2 add4 loadDictStart,loadDP,dp set dp rts oom lda #5 jmp TermError end **************************************************************** * * ExpandDynamicBuffer - expand the dynamic segment buffer * * Inputs: * dynHandle - handle of the buffer, nil for none * dynBuffSize - size of the buffer * synSize - bytes left in the current buffer * dy - pointer to the current buffer * dynStart - start of the buffer * * Outputs: * dynHandle - handle of the buffer, nil for none * dynBuffSize - size of the buffer * synSize - bytes left in the current buffer * dy - pointer to the current buffer * dynStart - start of the buffer * **************************************************************** * ExpandDynamicBuffer private using Common using OutCommon lda dynHandle if there is no buffer then ora dynHandle+2 bne lb1 pha get a new buffer pha ph4 #dynGrowSize ph2 userID ph2 #$8000 ph4 #0 _NewHandle jcs oom pl4 dynHandle lla dynBuffSize,dynGrowSize set the size bra lb2 else lb1 ph4 loadDict unlock the handle _HUnlock add4 dynBuffSize,#dynGrowSize get the new size ph4 dynBuffSize set the new size ph4 dynHandle expand the buffer _SetHandleSize bcs oom ph4 dynHandle lock the handle _HLock lb2 anop endif add2 dynSize,#dynGrowSize update the free space sub4 dy,dynStart convert dy to a displacement move4 dynHandle,r0 dereference the handle ldy #2 lda [r0] sta dynStart lda [r0],Y sta dynStart+2 add4 dy,dynStart set dy rts oom lda #5 jmp TermError end **************************************************************** * * ExpressLoad - Handle express loading * * Inputs: * express - is the program express loaded? * **************************************************************** * ExpressLoad private using OutCommon using Common ; ; Sort the segments by number ; lda #1 set the initial segment number sta expressSegment stz r0 nothing in the output list stz r2 sn1 move4 loadList,r8 for each segment number sn2 lda r8 for each segment ora r10 beq sn4 ldy #loadNumber-loadNext if this is the right segment then lda [r8],Y cmp expressSegment bne sn3 jsr MoveSegment move the segment to the new list bra sn4 sn3 ldy #2 next segment lda [r8],Y tax lda [r8] sta r8 stx r10 bra sn2 sn4 inc expressSegment next segment number lda loadList ora loadList+2 bne sn1 move4 r0,loadList replace the list ; ; Build the expressload segment ; pha get memory for the lConst record pha mul4 lastLoadNumber,#79,r0 add4 r0,#7 ph4 r0 ph2 userID ph2 #$8000 ph4 #0 _NewHandle bcc ex1 lda #5 jmp TermError ex1 pl4 r0 recover the handle ldy #2 recover the start pointer lda [r0] sta expStart lda [r0],Y sta expStart+2 add4 expStart,#6,expOffset set the initial offset pointer mul4 lastLoadNumber,#8,r0 set the initial map pointer add4 r0,expOffset,expMap mul4 lastLoadNumber,#2,r0 set the initial header pointer add4 r0,expMap,expHeader lda #2 start with segment 2 sta expressSegment mul4 lastLoadNumber,#79,fMark set the initial file mark add4 fMark,#67+5+4+2+1 ; ; Add all static segments to the expressload segment ; stz r0 nothing in the output list stz r2 st1 move4 loadList,r8 for each segment do st2 lda r8 ora r10 beq dy1 ldy #loadType-loadNext if it is a static segment then lda [r8],Y bmi st3 jsr AddSegment add the segment to the express list bra st1 loop st3 ldy #2 next segment lda [r8],Y tax lda [r8] sta r8 stx r10 bra st2 ; ; Add all remaining segments to the expressload segment ; dy1 lda loadList for each segment do ora loadList+2 beq dn1 move4 loadList,r8 add the segment to the express list jsr AddSegment bra dy1 ; ; Adjust the dynamic segment number ; dn1 anop lda dynSegment get the old segment number beq fe1 skip if there isn't one dec A set its mapped segment asl A tay lda [expMap],Y sta dynSegment set the new segment number ; ; Finish off the express record ; fe1 move4 r0,loadList replace the load list pointer lda #0 put and end mark after the record short M sta [expHeader] long M ldy #2 zero the reserved space for the link sta [expStart] sta [expStart],Y ldy #4 set the number of segments lda lastLoadNumber dec A sta [expStart],Y ; ; Write the expressload segment ; ! set the size of the segment sub4 expHeader,expStart,length add4 length,#headerEnd-header+1,byteCnt move4 length,length2 set the length of the lCost record lda keepRefnum write the header sta wrRefnum sta wsRefnum OSWrite wrRec bcs lb1 move4 expStart,wsBuff write the body add4 length,#1,wsLen OSWrite wsRec bcs lb1 rts lb1 lda #12 jmp TermError ; ; Local data ; wsRec dc i'4' write the body wsRefnum ds 2 wsBuff ds 4 wsLen ds 4 ds 4 wrRec dc i'4' write the segment header wrRefnum ds 2 da 'header' dc i4'headerEnd-header' ds 4 header anop segment header model byteCnt ds 4 length of the segment, in bytes dc i4'0' reserved space at the end of the segment length ds 4 length of the segment dc i1'0' undefined dc i1'0' label length dc i1'4' number length dc i1'2' OMF version dc i4'$10000' bank size dc i'$8001' segment kind dc i'0' undefined dc i4'0' origin dc i4'0' alignment factor dc i1'0' numSex; set to LSB first dc i1'0' undefined dc i'1' segment number dc i4'0' entry point dc i'ldName-header' disp to the segment name dc i'data-header' disp to the segment image ldName dc 10c' ' load segment name; unused in load segs dc i1'12' length of the segment name dc c'~ExpressLoad' segment name data dc i1'$F2' lConst header length2 ds 4 headerEnd anop end **************************************************************** * * FindLoadSegment - find the proper load segment for a file * * Inputs: * loadNamePtr - pointer to the load segment name * segOrg - origin for this segment * segAlign - alignment for this segment * segType - type for this segment * segBanksize - banksize for this segment * * Outputs: * loadNumber - load segment number * * Additional outputs if pass = 2: * op - pointer to the next output segment byte * dp - pointer to the next dictionary segment byte * dictSize - remaining bytes in the dictionary segment * dictStart - pointer to the first byte in the dictionary * **************************************************************** * FindLoadSegment start using Common using OutCommon lda loadNumber if there is an existing segment then bmi lb3 move4 loadNamePtr,r0 if we need this segment then ldy #nameSize-2 lb1 lda [r0],Y cmp loadName,Y bne lb2 dey dey bpl lb1 move4 pc,loadPC save the program counter jsr Pass2Prep make sure we are "pass 2 ready" jsr CheckHeader check header parameters rts return lb2 jsr SaveSegment save the current segment info lb3 move4 loadList,r0 find the correct segment move4 loadNamePtr,r8 lb4 lda r0 ora r2 beq lb6 add4 r0,#loadName-loadNext,r4 ldy #nameSize-2 lb5 lda [r4],Y cmp [r8],Y bne lb5a dey dey bpl lb5 jsr GetSegment recover the segment jsr CheckHeader check header parameters rts lb5a ldy #2 next segment lda [r0],Y tax lda [r0] sta r0 stx r2 bra lb4 lb6 jsr NewSegment create a new segment jsr CheckHeader rts end **************************************************************** * * FinishLconst - finish the current lconst record * * Inputs: * op - current ptr in buffer * opst - op at the start of this record * * Outputs: * opst - set to op * **************************************************************** * FinishLConst start sub4 op,opSt,r0 sub4 r0,#5 lda #$F2 sta [opSt] ldy #1 lda r0 sta [opSt],Y lda r2 iny iny sta [opSt],Y move4 op,opSt rts end **************************************************************** * * GetSegment - get a segment from storage * * Inputs: * r0 - pointer to the segment to get * pass - current pass number * * Outputs: * loadNext... - filled in * pc - set to last value * op,opst,dp,dpSize - set as appropriate * **************************************************************** * GetSegment private using Common using OutCommon ldy #loadSize-2 recover the segment lb0 lda [r0],Y sta loadNext,Y dey dey bpl lb0 lda loadSeg if there is a segment buffer then ora loadSeg+2 beq lb1 ph4 loadSeg lock the buffer _HLock move4 loadSeg,r0 dereference the segment ldy #2 lda [r0] sta loadSegStart lda [r0],Y sta loadSegStart+2 add4 loadOp,loadSegStart,op set the segment pointer add4 loadOpSt,loadSegStart,opst set the lConst pointer bra lb3 else if pass = 2 then lb1 lda pass cmp #2 bne lb3 move4 loadPC,pc save the program counter jsr Pass2Prep prepare for pass2 lb3 anop endif move4 loadPC,pc reset the program counter lda loadDict if there is a dictionary then ora loadDict+2 beq lb4 ph4 loadDict lock the buffer _HLock move4 loadDict,r0 dereference the segment ldy #2 lda [r0] sta loadDictStart lda [r0],Y sta loadDictStart+2 add4 loadDp,loadDictStart,dp set the segment pointer lb4 lda loadLast break the back link ora loadLast+2 beq lb5 move4 loadLast,r0 ldy #2 lda loadNext sta [r0] lda loadNext+2 sta [r0],Y bra lb6 lb5 move4 loadNext,loadList lb6 lda loadNext break the forward link ora loadNext+2 beq lb7 move4 loadNext,r0 ldy #loadLast-loadNext lda loadLast sta [r0],Y iny iny lda loadLast+2 sta [r0],Y lb7 rts end **************************************************************** * * HexVariable - convert an OS string to a value * * Inputs: * r0 - pointer to the shell variable value * * Outputs: * C - set if all characters are hex digits, else clear * X-A - value (if C set); least sig. 32 bits only * **************************************************************** * HexVariable private lda [r0] get a loop counter sta r12 stz r8 set the initial value stz r10 add4 r0,#2,r4 get a character pointer lda [r4] the first char must be '$' and #$00FF cmp #'$' bne lb3 inc4 r4 dec r12 beq lb2a lb1 lda [r4] if the character is not a digit then and #$00FF return false cmp #'0' blt lb3 cmp #'9'+1 blt lb1a and #$005F cmp #'F'+1 bge lb3 cmp #'A' blt lb3 lb1a pha r8 = r8*16 + value(r4^) mul4 r8,#16 pla and #$007F cmp #'9'+1 blt lb1b sbc #7 lb1b and #$000F clc adc r8 sta r8 bcc lb2 inc r10 lb2 inc4 r4 loop dec r12 bne lb1 lb2a lda r8 return value ldx r10 sec rts lb3 clc return false rts end **************************************************************** * * InitOut - initialize the output buffer variables * **************************************************************** * InitOut start using Common using OutCommon lda #-1 no load segment is active sta loadNumber stz lastLoadNumber no load segments created stz loadList no load segments in the list stz loadList+2 stz dynSegment no dynamic segment rts end **************************************************************** * * IsDynamic - is the segment dynamic? * * Inputs: * A - segment to check * * Outputs: * C - set if the segment is dynamic, else clear * **************************************************************** * IsDynamic start using OutCommon cmp loadNumber if A = current segment then bne lb2 lda loadType return dynamic(loadType) lb0 bpl lb1 sec rts lb1 clc rts lb2 sta r4 save the segment number move4 loadList,r0 for each segment in the list do lb3 lda r0 ora r2 beq lb1 ldy #loadNumber-loadNext if this is the correct segment then lda [r0],Y cmp r4 bne lb4 ldy #loadType-loadNext return dynamic(r0^.loadType) lda [r0],Y bra lb0 lb4 ldy #2 next segment lda [r0],Y tax lda [r0] sta r0 stx r2 bra lb3 end **************************************************************** * * JumpTable - create/reuse a jump table entry * * Inputs: * expValue - disp into the dynamic segment * expSegment - dynamic segment number * shiftFlag - shift flag for the expression * * Outputs: * expValue - disp into the segment buffer * expSegment - dynamic segment number * **************************************************************** * JumpTable start using OutCommon using ExpCommon userID equ 0 disp to the user ID field file equ 2 disp to the file number seg equ 4 disp to the segment number offset equ 6 disp to the offset (expr value) jsl equ 10 disp to the jsl to the loader length equ 14 length of a record header equ 8+5 bytes in the buffer header add4 dynStart,#header,r0 check for an existing entry lb1 cmpl r0,dy bge lb3 ldy #seg lda [r0],Y cmp expSegment bne lb2 ldy #offset lda [r0],Y cmp expValue bne lb2 iny iny lda [r0],Y cmp expValue+2 beq lb5 lb2 add4 r0,#length bra lb1 lb3 lda dynSize no existing entry; create a new one cmp #length bge lb4 jsr ExpandDynamicBuffer lb4 move4 dy,r0 add4 dy,#length lda #0 sta [r0] ldy #file lda #1 sta [r0],Y ldy #seg lda expSegment sta [r0],Y ldy #offset lda expValue sta [r0],Y iny iny lda expValue+2 sta [r0],Y ldy #jsl lda #$0022 sta [r0],Y iny iny lda #0 sta [r0],Y lb5 sub4 r0,dynStart,expValue set the new expValue add4 expValue,#jsl-5 lda dynSegment set the new segment value sta expSegment lda shiftFlag check for an illegal shift beq lb6 ph4 #0 ph2 #20 jsr Error lb6 rts end **************************************************************** * * KeepFile - write the segments to the file * * Inputs: * loadList - head of the load list * kname - pointer to the output name * **************************************************************** * KeepFile start using Common using OutCommon lda #1 set the segment number sta segment jsr CreateFile create/check the file move4 kname,opPathname open the file OSOpen opRec bcc lb0 err12 lda #12 jmp TermError lb0 lda opRefnum save the keep refnum sta keepRefnum sta clRefnum sta mkRefnum OSSet_EOF mkRec erase the old file contents bcs err12 lda compact if compact then beq lb0a jsr DoCompact compact the dictionaries lb0a jsr SaveSegment save the current segment jsr CreateDynamicSegment create the dynamic segment lda express if express then beq lb1 jsr ExpressLoad write the expressload segment (if any) inc segment first segment to process is 2 lb1 move4 loadList,r0 find the proper segment lb2 ldy #loadNumber-loadNext lda [r0],Y cmp segment beq lb3 ldy #2 lda [r0],Y tax lda [r0] sta r0 stx r2 ora r2 bne lb2 OSClose clRec none left -- close the file move4 loadList,r0 get a segment back jsr GetSegment jsr SetFileType rts lb3 jsr GetSegment get and lock the segment jsr AddEnd add an end record to the dictionary jsr FinishLConst finish the current lconst record lda express if express then beq lb4 jsr Remap remap the segment numbers bra lb5 else lb4 jsr OptimizeDS optimize the DS, LConst records lb5 jsr WriteHeader write the header jsr WriteBody write the segment image jsr WriteDictionary write the dictionary jsr SaveSegment save the segment inc segment next segment bra lb1 ; ; Local data ; clRec dc i'1' close record clRefnum ds 2 opRec dc i'2' open record opRefnum ds 2 opPathname ds 4 mkRec dc i'3' set mark record mkRefnum ds 2 dc i'0' dc i4'0' segment ds 2 segment number end **************************************************************** * * MoveSegment - move a segment record * * Inputs: * r0 - pointer to the head of the new list * r4 - pointer to the last record in the new list (if r0 <> nil) * r8 - pointer to the record to move * loadList - pointer to the first record in the old list * * Outputs: * input pointers are modified * **************************************************************** * MoveSegment private using OutCommon ; ; Break the back link ; ldy #loadLast-loadNext if r8^.last = nil then lda [r8],Y iny iny ora [r8],Y bne lb1 ldy #2 loadList := r8^.next lda [r8] sta loadList lda [r8],Y sta loadList+2 bra lb2 else lb1 ldy #loadLast-loadNext r12 := r8^.last lda [r8],Y sta r12 iny iny lda [r8],Y sta r14 ldy #2 r12^.next := r8^.next lda [r8] sta [r12] lda [r8],Y sta [r12],Y lb2 anop endif ; ; Break the forward link ; ldy #2 if r8^.next <> nil then lda [r8] ora [r8],Y beq lb3 lda [r8] r12 := r8^.next sta r12 lda [r8],Y sta r14 ldy #loadLast-loadNext r12^.last := r8^.last lda [r8],Y sta [r12],Y iny iny lda [r8],Y sta [r12],Y lb3 anop endif ; ; Add the record to the new list ; ldy #2 r8^.next := nil lda #0 sta [r8] sta [r8],Y lda r0 if r0 = nil then ora r2 bne lb4 ldy #loadLast-loadNext r8^.last := nil lda #0 sta [r8],Y iny iny sta [r8],Y move4 r8,r0 r0 := r8 bra lb5 else lb4 ldy #2 r4^.next := r8 lda r8 sta [r4] lda r10 sta [r4],Y ldy #loadLast-loadNext r8^.last := r4 lda r4 sta [r8],Y iny iny lda r6 sta [r8],Y lb5 anop endif move4 r8,r4 r4 := r8 rts end **************************************************************** * * NamedVariable - see if the variable is a file type * * Inputs: * r0 - pointer to the shell variable value * * Outputs: * C - set if we have a match, else clear * X-A - variable value (if C is set) * **************************************************************** * NamedVariable private lda [r0] if length <> 3 then cmp #3 bne lb3 return false lda #nameEnd-name-3 index into the name array sta r4 lda #$BD initial file number sta r6 lb1 ldx r4 check for match ldy #2 short M lb1a lda [r0],Y cmp name,X beq lb1b and #$5F cmp name,X bne lb2 lb1b inx iny cpy #5 bne lb1a long M lda r6 return the file type ldx #0 sec rts lb2 long M no match - loop dec r6 sec lda r4 sbc #3 sta r4 bpl lb1 lb3 clc return false rts ; ; Local data ; name dc c'S16' file type mnemonics dc c'RTL' dc c'EXE' dc c'PIF' dc c'TIF' dc c'NDA' dc c'CDA' dc c'TOL' dc c'DVR' dc c'LDF' dc c'FST' nameEnd anop end **************************************************************** * * NewSegment - create a new segment record * * Inputs: * loadNamePtr - pointer to the load name * lastLoadNumber - load number for the last segment created * * Outputs: * loadNumber - number of this load segment * loadName - name of the load segment * pc - 0 * * - all other load record variables are set to 0 * **************************************************************** * NewSegment private using Common using OutCommon move #0,loadNext,#loadSize move4 loadNamePtr,r0 ldy #nameSize-2 lb1 lda [r0],Y sta loadName,Y dey dey bpl lb1 inc lastLoadNumber lda lastLoadNumber sta loadNumber stz pc stz pc+2 rts end **************************************************************** * * OptimizeDS - optimize DS and LConst records * * This subroutine removes LConst records that have a length * of zero, and combines adjacent DS records. * * Inputs: * op - ptr to the end of the load segment body * opst - copy of op * loadSegStart - start of the load segment body * * Outputs: * op - ptr to the end of the load segment body * opst - copy of op * **************************************************************** * OptimizeDS private using Common using OutCommon LConst equ $F2 long contanst op-code DS equ $F0 DS op-code lda loadSegStart r0 = to address ldx loadSegStart+2 r4 = from address sta r0 stx r2 sta r4 stx r6 stz r8 r8 = false {r0, r4 are the same} lb2 cmpl r4,op while r4 <> op do jge lb12 lda [r4] if r4^ = LConst then and #$00FF cmp #LConst bne lb3 ldy #1 if length = 0 then lda [r4],Y ldy #3 ora [r4],Y bne lb4 add4 r4,#5 skip the record lda #1 r8 := true sta r8 bra lb2 lb3 add4 r4,#5,r10 else {if r4^ = DS then} lb3a cmpl r10,op if (r10 = r4+5) < op then bge lb4 lda [r10] if r10^ = LConst then and #$00FF cmp #LConst bne lb3b ldy #1 if r10^.length = 0 then lda [r10],Y ldy #3 ora [r10],Y bne lb4 add4 r10,#5 skip the lconst lda #1 r8 := true sta r8 bra lb3a try again lb3b ldy #1 else if r10^ = DS then clc r10^.length += r4^.length lda [r10],Y adc [r4],Y sta [r10],Y ldy #3 lda [r10],Y adc [r4],Y sta [r10],Y move4 r10,r4 r4 := r10 lda #1 r8 := true sta r8 bra lb3 try again lb4 lda r8 {move the record to the new spot} beq lb10 if the record needs to be moved then lda [r4] if r4^ = LConst then and #$00FF cmp #Lconst bne lb9 ldy #1 lda [r4],Y sta r10 ldy #3 lda [r4],Y sta r12 add4 r10,#5 ldx r12 beq lb6 ldy #0 lb5 lda [r4],Y sta [r0],Y iny iny bne lb5 inc r2 inc r6 dex bne lb5 lb6 lda r10 beq lb10 ldy #0 lsr A tax bcc lb7 short M lda [r4] sta [r0] long M iny lb7 txa beq lb10 lb8 lda [r4],Y sta [r0],Y iny iny dex bne lb8 bra lb10 else {if r4^ = DS then} lb9 lda [r4] sta [r0] ldy #2 lda [r4],Y sta [r0],Y iny lda [r4],Y sta [r0],Y lb10 lda [r0] {next record} and #$00FF cmp #LConst bne lb11 clc ldy #1 lda [r0],Y adc r4 tax ldy #3 lda [r0],Y adc r6 sta r6 stx r4 clc ldy #1 lda [r0],Y adc r0 tax ldy #3 lda [r0],Y adc r2 sta r2 stx r0 lb11 add4 r0,#5 add4 r4,#5 brl lb2 endwhile lb12 lda r0 op = opst = r0 ldx r2 sta op stx op+2 sta opst stx opst+2 rts end **************************************************************** * * Pass2Prep - prepare a buffer for the first call to pass2 * * Inputs: * loadPass2 - has the buffer been prepared for pass 2? * **************************************************************** * Pass2Prep private using Common using OutCommon lda pass if this is not pass 2 cmp #2 bne lb1 lda loadPass2 or the buffer has already been prepared beq lb2 lb1 rts return lb2 add4 length,loadPC update the length of the program lda loadBanksize check for a bank overflow ora loadBanksize+2 beq lb2a cmpl loadPC,loadBanksize blt lb2a beq lb2a ph4 #0 ph2 #18 jsr Error lb2a pha get memory for the output buffer pha clc lda loadPC adc #5 tax lda loadPC+2 adc #0 pha phx ph2 userID ph2 #$8000 ph4 #0 _NewHandle bcc lb3 lda #5 jmp TermError lb3 pl4 loadSeg move4 loadSeg,r0 dereference the segment ldy #2 lda [r0] sta loadSegStart sta op sta opst lda [r0],Y sta loadSegStart+2 sta op+2 sta opst+2 add4 op,#5 skip the space for the lConst header stz loadPC loadPC = 0 stz loadPC+2 stz loadOrg loadOrg = 0 stz loadOrg+2 stz loadAlign loadAlign = 0 stz loadAlign+2 stz pc pc = 0 stz pc+2 inc loadPass2 loadPass2 = true rts end **************************************************************** * * PrintSegmentInfo - print the segment statistics * * Inputs: * loadList - head of the load list * **************************************************************** * PrintSegmentInfo start using Common using OutCommon puts #'Segment Information:',cr=t write segment header putcr puts #' Number Name Type Length Org',cr=t putcr jsr SaveSegment save the current segment lda #1 set the segment number sta segment lda kflag beq lb1 lda express beq lb1 inc segment lb1 move4 loadList,r0 find the proper segment lb2 ldy #loadNumber-loadNext lda [r0],Y cmp segment beq lb3 ldy #2 lda [r0],Y tax lda [r0] sta r0 stx r2 ora r2 bne lb2 move4 loadList,r0 done - get a segment back jsr GetSegment rts lb3 put2 segment,#6 print the segment number putc #' ',#6 inc segment ldy #loadName-loadNext print the segment name short I,M ldx #0 lb3a lda [r0],Y beq lb3b sta name+1,X iny inx cpx #10 bne lb3a lb3b stx name sec lda #13 sbc name sta fw long I,M puts name-1 putc #'$',fw print the type pea 0 ldy #loadType-loadNext lda [r0],Y pha ph2 #2 ph2 #0 jsr PrintHex puts #' $' print the length ldy #loadPC-loadNext+2 lda [r0],Y pha dey dey lda [r0],Y pha ph2 #8 ph2 #0 jsr PrintHex puts #' ' ldy #loadORG-loadNext+2 print the org lda [r0],Y sta r6 dey dey lda [r0],Y sta r4 ora r6 beq lb4 putc #'$' ph4 r4 ph2 #8 ph2 #0 jsr PrintHex putcr brl lb1 lb4 puts #'Relocatable',cr=t brl lb1 segment ds 2 segment number name dc i1'10',10c' ' segment name fw dc i'0' field width for spaces after name end **************************************************************** * * Remap - remap the segment numbers in interseg references * * Inputs: * loadDictStart - start of the dictionary * * Notes: * This remapping is needed when express loading a segment * changes the segment numbers. * **************************************************************** * Remap private using OutCommon move4 loadDictStart,r0 lb1 lda [r0] get an op code and #$00FF jeq lb5 quit if it is the end cmp #$E2 skip reloc bne lb2 add4 r0,#11 bra lb1 lb2 cmp #$E3 remap interseg bne lb3 ldy #9 lda [r0],Y dec A asl A tay lda [expMap],Y ldy #9 sta [r0],Y add4 r0,#15 bra lb1 lb3 cmp #$F5 skip cReloc bne lb4 add4 r0,#7 bra lb1 lb4 cmp #$F7 remap Super jne lb4a ldy #5 if r0^.type = 2 {interseg1} then lda [r0],Y and #$00FF cmp #2 jne sp7 add4 r0,#6,r4 r4 = disp to 1st subrecord sec r8 = page offset lda loadSegStart sbc #$0100-7 sta r8 lda loadSegStart+2 sbc #0 sta r10 ldy #1 r12 = # bytes to process lda [r0],Y dec A sta r12 sp1 lda [r4] repeat and #$00FF if r4^ & $80 <> 0 then bit #$0080 beq sp4 and #$007F add in the page displacement bne sp2 lda #$0080 sp2 xba clc adc r8 sta r8 bcc sp3 inc r10 sp3 inc4 r4 ++r4 dec r12 --r12 bra sp6 next entry sp4 sta r14 else r14 = #bytes + 1 inc4 r4 skip the count byte dec r12 lda r8 new page clc adc #$100 sta r8 bcc sp5 inc r10 sp5 short I,M repeat lda [r4] remap one segment tay tax lda [r8],Y dec A asl A tay lda [expMap],Y txy sta [r8],Y long I,M inc4 r4 ++r4 dec r12 --r12 dec r14 --r14 bpl sp5 until r14 < 0 sp6 lda r12 until r12 = 0 bne sp1 bra sp9 sp7 cmp #14 else if r0^.type in [14..25] then blt sp9 cmp #26 bge sp8 short I,M remap the segment number sec sbc #14 asl A tay lda [expMap],Y clc adc #13 ldy #5 sta [r0],Y long I,M bra sp9 else if r0^.type in [26..37] then sp8 short I,M remap the segment number sec sbc #26 asl A tay lda [expMap],Y clc adc #25 ldy #5 sta [r0],Y long I,M sp9 anop endif ldy #1 skip the record clc lda [r0],Y adc r0 tax iny iny lda [r0],Y adc r2 sta r2 stx r0 add4 r0,#5 brl lb1 lb4a short I,M remap cInterseg ldy #5 lda [r0],Y dec A asl A tay lda [expMap],Y ldy #5 sta [r0],Y long I,M add4 r0,#8 brl lb1 lb5 rts end **************************************************************** * * RemapJumpTable - remap the segment numbers in the jump table * * Inputs: * loadSegStart - start of the jump table buffer * * Notes: * This remapping is needed when express loading a segment * changes the segment numbers. * **************************************************************** * RemapJumpTable private using OutCommon add4 loadSegStart,#8+5,r0 lb1 ldy #2 quit if file = 0 lda [r0],Y beq lb2 ldy #4 remap a segment lda [r0],Y dec A asl A tay lda [expMap],Y ldy #4 sta [r0],Y add4 r0,#14 bra lb1 lb2 rts end **************************************************************** * * SaveSegment - save the current load segment record * **************************************************************** * SaveSegment private using OutCommon move4 loadList,loadNext insert the record in the linked list stz loadLast stz loadLast+2 move4 pc,loadPC save the current pc lda loadSeg if there is a segment buffer then ora loadSeg+2 beq lb1 sub4 op,loadSegStart,loadOp save the op displacement sub4 opst,loadSegStart,loadOpSt save the opst displacement ph4 loadSeg unlock the segment buffer _HUnlock lb1 lda loadDict if there is a dictionary buffer then ora loadDict+2 beq lb2 sub4 dp,loadDictStart,loadDP save the dp displacement ph4 loadDict unlock the dictionary buffer _HUnlock lb2 lda loadPtr if there is no spot reserved then ora loadPtr+2 bne lb3 ph2 #loadSize get some space jsr GetSymbolMemory sta loadPtr stx loadPtr+2 lb3 move4 loadPtr,r0 save the record ldy #loadSize-2 lb4 lda loadNext,Y sta [r0],Y dey dey bpl lb4 lda loadList if loadList <> nil then ora loadList+2 beq lb5 move4 loadList,r0 loadList^.loadLast = loadPtr ldy #loadLast-loadNext lda loadPtr sta [r0],Y iny iny lda loadPtr+2 sta [r0],Y lb5 move4 loadPtr,loadList point the head to this segment rts end **************************************************************** * * SetFileType - set the file type and aux type * * Inputs: * kname - keep name pointer * **************************************************************** * SetFileType private ; ; Get the current file info ; move4 kname,giPathName OSGet_File_Info giRec ; ; Set the file type ; ph4 #FileType read the file type variable jsr ReadVariable sta r0 stx r2 lda [r0] if the variable exists then beq lb2 jsr NamedVariable handle a named variable bcs lb1 jsr DecimalVariable handle a decimal variable bcs lb1 jsr HexVariable handle a hex variable bcs lb1 err13 ph4 #0 flag a bad file name error ph2 #13 jsr Error bra lb2 lb1 txy check for a file type out of range bne err13 cmp #$B3 blt err13 cmp #$BF+1 bge err13 sta giFileType set the file type bra lb3 else lb2 lda #EXE use the default file type sta giFileType lb3 anop endif ph4 r0 Free(r0) jsr Free ; ; Set the aux type ; ph4 #AuxType read the file type variable jsr ReadVariable sta r0 stx r2 lda [r0] if the variable exists then beq ax2 jsr DecimalVariable handle a decimal variable bcs ax1 jsr HexVariable handle a hex variable bcs ax1 ph4 #0 flag a bad file name error ph2 #19 jsr Error bra ax2 ax1 stx giAuxType+2 save the aux type sta giAuxType bra ax3 else ax2 lla giAuxType,$100 use the default aux type ax3 anop endif ph4 r0 Free(r0) jsr Free ; ; Update the file info ; OSSet_File_Info giRec bcs fi1 rts fi1 lda #12 jmp TermError ; ; Local data ; giRec dc i'4' get/set file info record giPathname ds 4 ds 2 giFileType ds 2 giAuxType ds 4 FileType dos KeepType filetype shell variable name AuxType dos AuxType auxtype shell variable name end **************************************************************** * * WriteBody - write the body of a load segment * * Inputs: * loadNext... - load segment record * keepRefnum - keep file reference number * **************************************************************** * WriteBody private using Common using OutCommon lda express if express then beq lb0 lda loadNumber if loadNumber = dynSegment then cmp dynSegment bne lb0 jsr RemapJumpTable remap the dynamic jump table lb0 move4 loadSegStart,wrBuff set the buffer address sub4 op,loadSegStart,wrLength set the length lda keepRefnum set the refnum sta wrRefnum OSWrite wrRec write the segment bcs lb1 rts lb1 lda #12 jmp TermError ; ; Local data ; wrRec dc i'4' write the segment wrRefnum ds 2 wrBuff ds 4 wrLength ds 4 ds 4 end **************************************************************** * * WriteDictionary - write the dictionary for a load segment * * Inputs: * loadNext... - load segment record * keepRefnum - keep file reference number * **************************************************************** * WriteDictionary private using Common using OutCommon sub4 dp,loadDictStart,wrLength set the length move4 loadDictStart,wrBuff set the buffer address lda keepRefnum set the refnum sta wrRefnum OSWrite wrRec write the segment bcs lb1 rts lb1 lda #12 jmp TermError ; ; Local data ; wrRec dc i'4' write the segment wrRefnum ds 2 wrBuff ds 4 wrLength ds 4 ds 4 end **************************************************************** * * WriteHeader - write the segment header for a load segment * * Inputs: * loadNext... - load segment record * keepRefnum - keep file reference number * * Notes: * This subroutine also writes the lConst opcode and * length field for the code image that will be written * by WriteBody. * **************************************************************** * WriteHeader private using OutCommon ! set the size of the segment sub4 opst,loadSegStart,byteCnt add4 byteCnt,#headerEnd-header sub4 dp,loadDictStart,r0 add4 byteCnt,r0 move4 loadPC,length set the length of the segment move4 loadBankSize,bankSize set the bankSize of the segment lda loadType set the kind of the segment sta kind move4 loadORG,org set the org of the segment move4 loadAlign,align set the alignment factor of the segment lda loadNumber set the segment number sta segNum move loadName,segName,#nameSize set the segment name lda keepRefnum write the header sta wrRefnum OSWrite wrRec bcs lb1 rts lb1 lda #12 jmp TermError ; ; Local data ; wrRec dc i'4' write the segment wrRefnum ds 2 da 'header' dc i4'headerEnd-header' ds 4 header anop segment header model byteCnt ds 4 length of the segment, in bytes dc i4'0' reserved space at the end of the segment length ds 4 length of the segment dc i1'0' undefined dc i1'0' label length dc i1'4' number length dc i1'2' OMF version bankSize ds 4 bank size kind ds 2 segment kind dc i'0' undefined org ds 4 origin align ds 4 alignment factor dc i1'0' numSex; set to LSB first dc i1'0' undefined segnum ds 2 segment number ds 4 entry point dc i'ldName-header' disp to the segment name dc i'headerEnd-header' disp to the segment image dc i4'0' temp ORG ldName dc 10c' ' load segment name; unused in load segs dc i1'10' length of the segment name segName ds 10 segment name headerEnd anop end