KLWINC==^D18 ;# chars at which hairy word move starts
; winning over BP loop
$STENT==1 ;offset from beg of loop for entry to
; STORE phase
$GENT==4 ;offset from beg of loop for entry to GET phase
.PSECT DATA
FSCPKL: 0 ;a LSHC A,<n> for SHIFT-IN goes here
LSH A,1
MOVEM A,(C) ;Address of dest stored in RH here
0 ;a LSHC A,<n> for SHIFT-OUT goes here
MOVE B,(C) ;Address of source stored in RH here
AOBJN C,FSCPKL
JRST @FENTRM(D)
LDB E,[POINT 3,A,5] ;Get low 3 bits of P field for source
SKIPGE E,FSCHTB(E) ;Get resulting # chars, skip if addr ok
MOVEI A,1(A) ;P= 01, must bump address.
MOVEI L,1(A) ;Anyway, get addr+1 into 12.
LDB D,[POINT 3,O,5] ;Repeat procedure for dest
SKIPGE D,FSCHT2(D) ;Using slightly different table
AOSA V,O ;And addr goes into 10
MOVEI V,(O) ;And isn't normally bumped.
MOVEI O,(C) ;Update the destination pointer in o
ADJBP O,O+TMPACS ;From initial value
;Now get index for shift values, and count for words
SUBI C,(E) ;Get # chars minus those in 1st src wd.
ADDI E,-6(D) ;Get E index - D*5+S, zero based.
IDIVI C,5 ;Find # words to loop through, rem in d
MOVE B,-1(L) ;And get 1st word of source.
JRST @FPATH(E) ;Must now pick a path...
;Blt possible! Jump to FSBLT0 if no shifting needed for setup.
FSBLT0: MOVEM B,(V) ;Store source word directly
JRST FSBLT4
FSBLT: LSH B,@SHASL(E) ;Shift source up against left
MOVE A,(V) ;Get 1st wd of dest.
LSH A,@SHADR(E) ;Right-adjust it
LSHC A,@SHFIX(E) ;And get everything into A.
LSH A,1 ;Need one more bit's worth.
MOVEM A,(V) ;Store 1st wd of dest...
;Now settle down to serious BLT'ing.
FSBLT4: MOVEI T,(C) ;Transfer word count
ADDI T,(V) ;Find addr of last dest word
MOVEI V,1(V) ;Now get 1st dest addr,
HRLI V,(L) ;And put 1st source addr in LH.
BLT V,(T) ;Zoom!!
JUMPE D,FSCPY9 ;If no remainder, super win - done!
ADDI L,(C) ;Hmm, must get last source word.
MOVE B,(L) ;Like so.
MOVE A,FBMSK(D) ;And a word mask for chars
AND B,A ;Clear unused bits from source,
ANDCAM A,1(T) ;And zap target bits in dest.
IORM B,1(T) ;And stick last chars in.
JRST FSCPY9 ;Ok, all done...
;Can't do BLT. Well, get A and B set up for magical shift loop.
SHSKP2: LSH B,@SHASL(E) ;Here, only need to adjust source,
JRST SHSKP5 ;Since dest will be totally clobbered.
FSSHFT: LSH B,@SHASL(E) ;Both src and dest must be integrated.
SHSKP1: MOVE A,(V) ;Only need adjust dest; src wd is full.
LSH A,@SHADR(E)
SHSKP5: LSHC A,@SHFIX(E) ;Stuff as many chars as possible into A
CAIE D,0 ;If any remainder,
MOVEI C,1(C) ;Add 1 more word.
MOVNI C,(C) ;Make AOBJN pointer.
MOVSI C,(C)
;Now make another index for termination wrapup purposes.
ADD D,FFINDX(E) ;New idx using # chs left in last wd.
;Now set things up for loop, and enter it.
FSCPY3: HRLI V,(<MOVEM A,(C)>)
MOVEM V,FSCPKL+2 ;Address for MOVEM
HRRM L,FSCPKL+4 ;Address for MOVE
MOVE L,FSHINT(E) ;Get LSH for shift-in
MOVEM L,FSCPKL
MOVE L,FSHOUT(E) ;And shift-out
MOVEM L,FSCPKL+3
JUMPGE D,FSCPKL+$STENT ;Depending on flag, enter loop at store
SOS V,FSCPKL+2
JRST FSCPKL+$GENT ;Or at get.
;---------------------------------------------------------------------------
;Come here when loop finished. The last word of the source string
;will be in B. It may have 1 to 5 chars left for moving, but will
;never have 0.
;Long wrapup.
FSCPTL: LSHC A,@FSCPKL ;Perform a shift-in
LSH A,1
MOVEM A,@10 ;Store full word.
MOVEI C,1(C) ;Increment address index
;And drop through to Medium wrapup.
;Medium wrapup.
FSCPTM: LSHC A,@FLOUT(D) ;Shift rest of source word into A
MOVE B,@10 ;Get dest word it will be stored into
LSH B,@FLADJ(D) ;Left-adjust chars to preserve.
;And drop thru to Short wrapup.
;Short wrapup.
FSCPTS: LSHC A,@FFLOUT(D) ;Do final, last, shift-out.
ANDCMI A,1
MOVEM A,@10 ;And store last dest word.
;Done!! Just restore regs and return.
FSCPY9: HRLI N,D+TMPACS ;Restore regs
HRRI N,D
BLT N,N
RET
;Indexed by low 3 bits of P field, returns # chars
;existing to right of loc BP points to. Hence value
;ranges from 5 to 1; if P = 01, SETZ indicates that
;bp address needs incrementing.
FSCHTB: 1 ;P=10
SETZ 5 ;P=01, increment addr
0
0 ;Randomness
5 ;P=44, full word
4 ;P=35, 4 chars to go
3 ;P=26
2 ;P=17
;This table is just like FSCHTB except values are pre-multiplied
;by 5 for easy addition into E.
;SHFIX table, contains # bits to left-shift A and B combined so
;as to move as many characters out of B as possible. Indexed
;by E. MIN(d,e) (d and e after fschtb)
SHFIX: ENT 1,1,1,1,1
ENT 1,2,2,2,2
ENT 1,2,3,3,3
ENT 1,2,3,4,4
ENT 1,2,3,4,5
;FSHINT table, containing appropriate LSHC instructions for shifting
;in the first chars of a fresh source word. Indexed by E.
;FSHOUT table, containing appropriate LSHC instructions for shifting
;out the last chars of an old source word, to make room for a
;new one. Indexed by E.
;FFINDX table, contains part of D index for fast add-in.
;Indexed by E. Similar to FSHOUT. Sign bit also indicates
;whether entry point is $STENT (pos) or $GENT (neg).
DEFINE ENTS (A,B,C,D,E) <
ENT5 A
ENT5 B
ENT5 C
ENT5 D
ENT5 E
>;DEFINE ENTS
DEFINE ENT5 (X,Y) <
X+<Y*5>
>;DEFINE ENT5
S==0B0
G==1B0
;FFLOUT table, for Short wrapup routine. Final Last shift-out of
;chars in B, so that the last dest word can be stored from A.
;Indexed by D. Adds 1 extra bit since MOVEM A, done right after it,
;and nothing to preserve in B.