LOAD 'Macros.dump' INCLUDE 'SS.equ' INCLUDE 'Driver.equ' INCLUDE 'Heap.aii.i' INCLUDE 'Eval.aii.i' ;----------------------------------------------- ; ; Imported addresses ; ;----------------------------------------------- IMPORT S_AddCellToChangedList IMPORT S_DeltaMove IMPORT S_FixFormula IMPORT S_FixFormula2 IMPORT S_FixFormula3 IMPORT S_FixFormulaFlag IMPORT S_GetCellTableEntry IMPORT S_InsertLeftPadCells IMPORT S_InsertRightPadCells IMPORT S_MergeDependLists IMPORT S_MoveDestBR IMPORT S_MoveDestTL IMPORT S_MoveNewCell IMPORT S_MoveOldCell IMPORT S_MoveSrcBR IMPORT S_MoveSrcTL IMPORT S_RearrangePadCells IMPORT S_RemoveCellFromChangedList IMPORT S_ResetCircularity IMPORT S_SetCellTableEntry IMPORT S_SetCircularBits IMPORT S_SplitDependList IMPORT S_TraverseDependFormulas ;----------------------------------------------- ; ; Forward addresses and entries ; ;----------------------------------------------- ENTRY S_ClearChangedBits ENTRY S_ClearChangedBits2 ;-------------------------------------------------------------------------- ; S_SwapCell ; ; For the purposes of the comments in this routine, the following ; terminology will be used. User cell's are those cells that the user ; thinks of as cells. (These include labels, values, and 2 types of formulas. ; The cell type of user cells are always positive, and of non-user cells are ; always negative.) Pad cells are those cell structures in the cell table, used ; to indicate space for overlapping labels. Real cells will be the union of ; User and Pad cells. (This name is used because real cell structures exist.) ; Fake cells are cell table entries that consist of dependency lists. ; (Dependency lists always have some of the high 2 bits of the cell table entry ; non-zero for detection.) Empty cells are blank cell table entries. (For the ; purposes of this routine, empty cells treated as Fake cells because the ; code works.) S_SwapCell PROC EXPORT ;Using S_CurrentData ;Using S_MoveData ;Using S_SwapCellFixData input SrcCell:l local SrcCellTableEntry:l,SrcFakeFlag:w local SrcFormat:l,SrcCellType:w local SrcFormulaIndex:l,SrcDependIndex:l local SrcSingDepList:l,SrcRngDepList:l local NewSrcEntry:l,NewSrcDepList:l local DestCell:l,DestCellTableEntry:l,DestFakeFlag:w local DestFormat:l,DestCellType:w local DestFormulaIndex:l,DestDependIndex:l local DestSingDepList:l,DestRngDepList:l local NewDestEntry:l,NewDestDepList:l local CellPtr:l,PreviousCell:l,NextCell:l,ClrChangedBits:w error ErrorFlag BEGIN ; Initialize flag variables stz ErrorFlag stz SrcFakeFlag stz DestFakeFlag stz ClrChangedBits ; Determine the other cell to swap with AddWord SrcCell,S_DeltaMove,DestCell AddWord SrcCell+2,S_DeltaMove+2,DestCell+2 ; ; ; Adjust the src cell ; ; ; in SrcCell:l out SrcCellTableEntry:l XCall S_GetCellTableEntry ora SrcCellTableEntry beq fakeSrc1 ; branch empty cell lda SrcCellTableEntry+2 and #S_CellTableFlags beq realSrc1 ; branch real cell ; The following works for both fake and empty src cells. fakeSrc1 inc SrcFakeFlag MoveWord #S_CellTypeEmpty,SrcCellType MoveWord #0,SrcFormat+2 MoveLong SrcCellTableEntry,SrcDependIndex brl adjustDestCell realSrc1 H_GetBlockPtr SrcCellTableEntry,CellPtr MoveLong [CellPtr]:#S_CellContent,SrcFormulaIndex MoveLong [CellPtr]:#S_CellDependOnMe,SrcDependIndex MoveLong [CellPtr]:#S_CellFormat,SrcFormat MoveLong [CellPtr]:#S_CellNext,NextCell MoveLong [CellPtr]:#S_CellPrevious,PreviousCell lda SrcFormat+2 and #$FFFF-S_CellCircular MoveWord a,[CellPtr]:#S_CellFormat+2 lda SrcFormat and #S_CellType sta SrcCellType bmi chkChangedSrc ; branch pad cell ; Clear any circularity, we'll reset them at the end ; userSrc1 lda SrcFormat+2 and #S_CellCircular beq chkChangedSrc Call S_ResetCircularity,in=(SrcCell:l) ; Remove SrcCell from changed list if it is already there. ; chkChangedSrc lda NextCell+2 ora NextCell beq adjustDestCell lda #0 MoveWord a,[CellPtr]:#S_CellNext MoveWord a,[CellPtr]:#S_CellNext+2 MoveWord a,[CellPtr]:#S_CellPrevious MoveWord a,[CellPtr]:#S_CellPrevious+2 in SrcCell:l,PreviousCell:l,NextCell:l XCall S_RemoveCellFromChangedList ; ; ; Adjust the dest cell ; ; ; adjustDestCell in DestCell:l out DestCellTableEntry:l XCall S_GetCellTableEntry ora DestCellTableEntry beq fakeDest ; branch empty cell lda DestCellTableEntry+2 and #S_CellTableFlags beq realDest1 ; branch real cell ; The following works for both fake and empty Dest cells. fakeDest inc DestFakeFlag MoveWord #S_CellTypeEmpty,DestCellType MoveWord #0,DestFormat+2 MoveLong DestCellTableEntry,DestDependIndex brl adjustDepends realDest1 H_GetBlockPtr DestCellTableEntry,CellPtr MoveLong [CellPtr]:#S_CellContent,DestFormulaIndex MoveLong [CellPtr]:#S_CellDependOnMe,DestDependIndex MoveLong [CellPtr]:#S_CellFormat,DestFormat MoveLong [CellPtr]:#S_CellNext,NextCell MoveLong [CellPtr]:#S_CellPrevious,PreviousCell lda DestFormat+2 and #$FFFF-S_CellCircular MoveWord a,[CellPtr]:#S_CellFormat+2 lda DestFormat and #S_CellType sta DestCellType bmi chkChangedDest ; branch pad cell ; Clear any circularity, we'll reset them at the end ; userDest lda DestFormat+2 and #S_CellCircular beq chkChangedDest Call S_ResetCircularity,in=(DestCell:l) ; Remove DestCell from changed list if it is already there. chkChangedDest lda NextCell+2 ora NextCell beq adjustDepends lda #0 MoveWord a,[CellPtr]:#S_CellNext MoveWord a,[CellPtr]:#S_CellNext+2 MoveWord a,[CellPtr]:#S_CellPrevious MoveWord a,[CellPtr]:#S_CellPrevious+2 in DestCell:l,PreviousCell:l,NextCell:l XCall S_RemoveCellFromChangedList ; Adjust src cell's DependOnMe references adjustDepends lda SrcDependIndex ora SrcDependIndex+2 beq adjustDestDep ; Set up the globals used in the FixFormula routines stz S_FixFormulaFlag MoveLong SrcCell,S_MoveOldCell MoveLong DestCell,S_MoveNewCell ; The first changed bit allows for formulas with references to ; both cells involved, and the Fix routines will still work. ; The second changed bit allows for circular references to itself. lda DestDependIndex ora DestDependIndex+2 beq doFixFormFlag1 MoveWord #S_RecentlyChangedBit,S_FixFormulaFlag inc ClrChangedBits doFixFormFlag1 lda SrcFormat+2 and #S_CellCircular beq doTraverse1 lda #S_RecentlyChangedBit2 tsb S_FixFormulaFlag inc ClrChangedBits doTraverse1 in SrcCell:l,SrcCellTableEntry:l in #S_FixFormula:l,#S_FixFormula2:l XCall S_TraverseDependFormulas ; Adjust dest cell's DependOnMe references adjustDestDep lda DestDependIndex ora DestDependIndex+2 beq adjustFormulas stz S_FixFormulaFlag MoveLong DestCell,S_MoveOldCell MoveLong SrcCell,S_MoveNewCell lda DestFormat+2 and #S_CellCircular beq doTraverse2 MoveWord #S_RecentlyChangedBit2,S_FixFormulaFlag inc ClrChangedBits doTraverse2 in DestCell:l,DestCellTableEntry:l in #S_FixFormula:l,#S_FixFormula2:l XCall S_TraverseDependFormulas ; Adjust src cell's formula ; adjustFormulas lda SrcCellType bmi adjustDestFormula ; branch non-user cell and #S_CellTypeTextForm beq adjustDestFormula ; branch non-formula cell MoveLong SrcCell,S_MoveOldCell MoveLong DestCell,S_MoveNewCell in SrcCell:l,DestCell:l,SrcFormulaIndex:l XCall S_FixFormula3 ; Adjust dest cell's formula ; adjustDestFormula lda DestCellType bmi chkClrChangedBits ; branch non-user cell and #S_CellTypeTextForm beq chkClrChangedBits ; branch non-formula cell MoveLong DestCell,S_MoveOldCell MoveLong SrcCell,S_MoveNewCell in DestCell:l,SrcCell:l,DestFormulaIndex:l XCall S_FixFormula3 chkClrChangedBits lda SrcFakeFlag beq chkClrChgBits2 ; branch real cell in SrcCell:l out :l XCall S_GetCellTableEntry pla sta SrcCellTableEntry sta SrcDependIndex pla sta SrcCellTableEntry+2 sta SrcDependIndex+2 ora SrcCellTableEntry beq chkClrDest ; branch empty cell chkClrChgBits2 lda ClrChangedBits beq chkClrDest in SrcCell:l,SrcCellTableEntry:l in #S_ClearChangedBits:l,#S_ClearChangedBits2:l XCall S_TraverseDependFormulas lda SrcCellType bmi chkClrDest ; branch non-user cell and #S_CellTypeTextForm beq chkClrDest ; branch non-formula cell Call S_ClearChangedBits,in=(SrcCell:l,SrcFormulaIndex:l) chkClrDest lda DestFakeFlag beq chkClrDest2 ; branch real cell in DestCell:l out :l XCall S_GetCellTableEntry pla sta DestCellTableEntry sta DestDependIndex pla sta DestCellTableEntry+2 sta DestDependIndex+2 ora DestCellTableEntry beq doSwap ; branch empty cell chkClrDest2 lda ClrChangedBits beq doSwap in DestCell:l,DestCellTableEntry:l in #S_ClearChangedBits:l,#S_ClearChangedBits2:l XCall S_TraverseDependFormulas lda DestCellType bmi doSwap ; branch non-user cell and #S_CellTypeTextForm beq doSwap ; branch non-formula cell Call S_ClearChangedBits,in=(DestCell:l,DestFormulaIndex:l) ; Break up both depend lists into their single cell and range parts. ; The old single part will be attached to New location's range part ; and vise - versa. doSwap lda SrcFakeFlag bne splitSrcDeps ; branch fake or empty cell H_GetBlockPtr SrcCellTableEntry,CellPtr MoveLong [CellPtr]:#S_CellDependOnMe,SrcDependIndex ; Split up the depend list. ; splitSrcDeps in SrcDependIndex:l out SrcSingDepList:l,SrcRngDepList:l XCall S_SplitDependList ; Now break up the dest depend lists into its single cell and range parts. lda DestFakeFlag bne splitDestDeps ; branch fake or empty cell H_GetBlockPtr DestCellTableEntry,CellPtr MoveLong [CellPtr]:#S_CellDependOnMe,DestDependIndex splitDestDeps in DestDependIndex:l out DestSingDepList:l,DestRngDepList:l XCall S_SplitDependList ; Merge the Src's SingDepList with the Dest's RngDepList list in SrcSingDepList:l,DestRngDepList:l out NewDestDepList:l XCall S_MergeDependLists ; Merge the Dest's SingDepList with the Src's RngDepList list in DestSingDepList:l,SrcRngDepList:l out NewSrcDepList:l XCall S_MergeDependLists ; The following 3 labels represent the 3 ways to set up ; the NewSrcEntry used in this swap. ; 1) Nothing left in the Src cell. Set the depend list here. ; The New src is fake. ; 2) Pad Cell left in the Src position. Put the depend ; in the pad cell. ; 3) The Dest was user and is moving to the Src postion. Set the ; depend in the user cell. lda DestCellType bpl userSrc5 ; branch all <-> user lda SrcFakeFlag bne fakeSrc5 ; branch empty,fake <-> empty,fake,pad lda SrcCellType bmi padSrc5 ; branch pad <-> empty,fake,pad lda DestFakeFlag bne fakeSrc5 ; branch user <-> empty,fake ; A User Src is moving to a Pad Dest. The pad must be disposed of. ; A fake Src is left behind. ; Call S_RemoveCell,in=(DestCell:l) H_DisposeBlock DestCellTableEntry ; The following 9 cases get to the following code. ; empty,fake,user <-> empty,fake,pad fakeSrc5 MoveLong NewSrcDepList,NewSrcEntry lda SrcCellType jpl userDest6 ; branch user <-> empty,fake,pad lda DestFakeFlag jne fakeDest6 ; branch empty,fake <-> empty,fake brl padDest6 ; branch empty,fake <-> pad ;------------------------------------- ; The following 3 cases get to the following code. ; pad <-> empty,fake,pad padSrc5 H_GetBlockPtr SrcCellTableEntry,CellPtr MoveLong NewSrcDepList,[CellPtr]:#S_CellDependOnMe MoveLong SrcCellTableEntry,NewSrcEntry lda DestFakeFlag bne fakeDest6 ; branch pad <-> empty,fake bra padDest6 ; branch pad <-> pad ;------------------------------------- ; The following 4 cases get to the following code. ; all <-> user userSrc5 H_GetBlockPtr DestCellTableEntry,CellPtr MoveLong SrcCell,[CellPtr]:#S_CellID MoveLong NewSrcDepList,[CellPtr]:#S_CellDependOnMe MoveLong DestCellTableEntry,NewSrcEntry lda SrcFakeFlag bne fakeDest6 ; branch empty,fake <-> user lda SrcCellType bpl userDest6 ; branch user <-> user ; A User Dest is moving to a Pad Src. The pad must be disposed of. ; A fake Dest is left behind. ; Call S_RemoveCell,in=(SrcCell:l) H_DisposeBlock SrcCellTableEntry ; The following 3 labels represent the 3 ways to set up ; the NewDestEntry used in this swap. ; 1) Nothing left in the Dest cell. Set the depend list here. ; The New Dest is fake. ; 2) Pad Cell left in the Dest position. Put the depend ; in the pad cell. ; 3) The Src was real and is moving to the Dest postion. Set the ; depend in the real cell. ; The following 9 cases get to the following code. ; empty,fake,pad <-> empty,fake,user fakeDest6 MoveLong NewDestDepList,NewDestEntry bra resetIndices ;------------------------------------- ; The following 3 cases get to the following code. ; empty,fake,pad <-> pad padDest6 H_GetBlockPtr DestCellTableEntry,CellPtr MoveLong NewDestDepList,[CellPtr]:#S_CellDependOnMe MoveLong DestCellTableEntry,NewDestEntry bra resetIndices ;------------------------------------- ; The following 4 cases get to the following code. ; user <-> all userDest6 H_GetBlockPtr SrcCellTableEntry,CellPtr MoveLong DestCell,[CellPtr]:#S_CellID MoveLong NewDestDepList,[CellPtr]:#S_CellDependOnMe MoveLong SrcCellTableEntry,NewDestEntry ;------------------------------------- ; The following 16 cases get to the following code. ; all <-> all resetIndices Call S_SetCellTableEntry,in=(SrcCell:l,NewSrcEntry:l) Call S_SetCellTableEntry,in=(DestCell:l,NewDestEntry:l) ; If cells are labels, fix pad cells: if cells are formulas, fix ; circularity lda SrcCellType bpl chkSrcCirc lda DestCellType bpl chkDestCirc brl chkSrcChanged chkSrcCirc and #S_CellTypeTextForm beq chkDestCircCheck Call S_SetCircularBits,in=(DestCell:l) chkDestCircCheck lda DestCellType bmi fixSrcPadCells chkDestCirc and #S_CellTypeTextForm beq fixSrcPadCells Call S_SetCircularBits,in=(SrcCell:l) ; Remove old pad cells ; fixSrcPadCells in DestCell:l out :l,:l XCall S_RearrangePadCells,err=ErrorFlag pla plx cpx S_MoveDestBR+2 blt chkLeft1 stx S_MoveDestBR+2 chkLeft1 pla plx cpx S_MoveDestTL+2 bge fixDestPadCells stx S_MoveDestTL+2 fixDestPadCells lda ErrorFlag jne chkSrcChanged in SrcCell:l out :l,:l XCall S_RearrangePadCells,err=ErrorFlag pla plx cpx S_MoveSrcBR+2 blt chkLeft2 stx S_MoveSrcBR+2 chkLeft2 pla plx cpx S_MoveSrcTL+2 bge chkSrcLabel stx S_MoveSrcTL+2 ; Insert New pad cells ; chkSrcLabel lda ErrorFlag bne chkSrcChanged lda SrcCellType bne chkDestLabel ; 0 = label Call S_InsertRightPadCells,in=(DestCell:l),out=(ax:l) cpx S_MoveDestBR+2 blt chkLeft3 stx S_MoveDestBR+2 chkLeft3 Call S_InsertLeftPadCells,in=(DestCell:l),out=(ax:l) cpx S_MoveDestTL+2 bge chkDestLabel stx S_MoveDestTL+2 chkDestLabel lda DestCellType bne chkSrcChanged ; 0 = label Call S_InsertRightPadCells,in=(SrcCell:l),out=(ax:l) cpx S_MoveSrcBR+2 blt chkLeft4 stx S_MoveSrcBR+2 chkLeft4 Call S_InsertLeftPadCells,in=(SrcCell:l),out=(ax:l) cpx S_MoveSrcTL+2 bge chkSrcChanged stx S_MoveSrcTL+2 chkSrcChanged lda DestCellTableEntry ora DestCellTableEntry+2 beq chkDestChanged Call S_AddCellToChangedList,in=(SrcCell:l) chkDestChanged lda SrcCellTableEntry ora SrcCellTableEntry+2 beq Exit Call S_AddCellToChangedList,in=(DestCell:l) Exit RETURN ENDP ;--------------------------------------------------------------------------- ; ; These routines clear the S_CellChangedBit of the cell reference's ; refbytes. S_ClearChangedBits PROC EXPORT ;Using S_CurrentData input Cell:l,FormulaIndex:l local FormulaPtr:l local Start:w,Stop:w BEGIN H_GetBlockPtr FormulaIndex,FormulaPtr MoveWord [FormulaPtr]:#E_FormulaCells,Stop MoveWord #E_FormulaData,Start bra chkEnd dependLoop MoveWord [FormulaPtr]:Start,a and #$FFFF-S_RecentlyChangedBit-S_RecentlyChangedBit2 sta [FormulaPtr],y AddWord Start,#5,Start chkEnd cmp Stop blt dependLoop RETURN #0 ENDP ;---------------------------------------------------------------------------- ; ; S_ClearChangedBits2 PROC EXPORT input Cell:l,FormulaIndex:l output Moved:w BEGIN stz Moved Call S_ClearChangedBits,in=(Cell:l,FormulaIndex:l) RETURN Moved ENDP END