:TITLE[BITBLT];*Last edited: 5 February 1981 by Fiala

%BBTable format

WORD
NAME
0
Functionbit 0 Long; 14:17 function; for AltoXMMode
bit 12=alt bank src, 13=alt bank dest
1
unused
2
DBCADest BCABase Core Address of dest bit map
3
DBMRDest BMRBit Map Raster width in words (>=0)
4
DLXDest LXBlock’s Left X offset from 1st bit of scan-line (>= 0)
5
DTYDest TYBlock’s Top Y offset from 1st scan-line (>=0)
6
DWDest WWidth in bits of block (>=0)
7
DHDest HHeight in scan-lines of block (>=0)
10
SBCASrc BCA
11
SBMRSrc BMR(>=0??)
12
SLXSrc LX(>=0)
13
STYSrc TY(>=0)
14
Gray0These four words are the Gray Block
15
Gray1Gray0 is used on last item transmitted,
16
Gray2Gray1 on next-to-last, etc., Gray0 on
17
Gray34th from last, etc.
20
LongSrcLoThis pair instead of MDShi/SBCA if long
21
LongSrcHi
22
LongDestLoThis pair instead of MDShi/DBCA if long
23
LongDestHi

BitBlt functions:
[X=0 uses BBFB (Dest & Mask’), X=1 uses BBFBX (Dest unmasked)]
[MA=0 causes Src & Mask, MA=1 causes Src or Mask’]

CODE
MA XSALUFOPActionComputation

0
0 0R or TS(D & M’) or (S & M)
1
0 1R or TD or SD or (S & M)
2
0 1R # TD # SD # (S & M)
3
0 1R & T’D & S’D & (S & M)’
4
1 0R or T’S’(D & M’) or (S or M’)’
5
1 1R or T’D or S’D or (S or M’)’
6
1 1R # T’D # S’D # (S or M’)’
7
1 1R & TD & SD & (S or M’)
10
0 1R or T(D & S’) or (S & G)(D & (S & M)’) or (S & M & G)
11
0 1R or TD or (S & G)D or (S & M & G)
12
0 1R # TD # (S & G)D # (S & M & G)
13
0 1R & T’D & (S & G)’D & (S & M & G)’
14
0 0R or TG(D & M’) or (G & M)
15
0 1R or TD or GD or (G & M)
16
0 1R # TD # GD # (G & M)
17
0 1R & T’D & G’D & (G & M)’

bbFunction is in the following format:
00
mesa long pointer during early initialization;
L-to-R = 0 / R-to-L = 1 after early init.
01-03
unused
04-07
which-innerloop index
10-11
unused
12
For AltoXMMode alt bank src, else unused
13
For AltoXMMode alt bank dest, else unused
14-17
Bitblt function code
%

*BBFA dispatch values
Set[bbItem,3];
*item refill
Set[bbSDRef,4];
*source and destination refill
Set[bbSRef,5];
*source refill
Set[bbDRef,6];
*destination refill
Set[bbNoRef,7];
*no refill

Set[bbILtype0,00];
*functions 1-3 and 5-7
Set[bbILtype1,02];
*functions 0 and 4
Set[bbILtype2,04];
*function 10
Set[bbILtype3,06];
*functions 11-13
Set[bbILtype4,10];
*function 14
Set[bbILtype5,12];
*functions 15-17

:IF[AltoXMMode]; *****************************
OnPage[bbXMPage];
bbShortXM:
bbSrcQHi ← T;
T ← (RMZero) - (40C);*177740 addresses bank
PFetch1[MDS,bbGray];
Dispatch[bbFunction,12,2];*Alternate bank bits
T ← LdF[bbGray,16,2], Disp[.+1];
Return, DispTable[4];
bbDestQHi ← (bbDestQHi) + T, Return;
bbSrcQHi ← (bbSrcQHi) + T, Return;
bbSrcQHi ← (bbSrcQHi) + T, Goto[.-2];
:ENDIF; **************************************

OnPage[bbPage];

*Alto entry here with StkP pointing at AC1 (2*scan-lines completed),
*(Cycle&PCXF) and not (100000C) in T, and pointer to BitBlt table in AC2
*(a base reg.); the BitBlt table is known to start at an even address.
*Mesa entry with (Cycle&PCXF) or (100000C) in T, Stack holding 2*scan-lines
*completed and Stack0 in AC2 (a pointer to BitBlt table).
bbBitBlt:
PFetch2[AC2,bbItemWid,6], Task;*fetch dw and dh
bbGray1 ← (bbGray1) or not (0C);*-1=don’t touch pages; 0=do
AC0 ← T, Skip[BPCChk’];*Save PCF and Mesa/Alto flag in AC0
PCB ← (PCB) + (4C);*Advance PC on imminent refill
PFetch1[AC2,bbFunction,0];*Even
bbNegBitsLeft ← Zero;*0 L-to-R, variable R-to-L

*Setup bbSrcQLo/Hi and bbDestQLo/Hi double-precision; in short mode, sbca/dbca
*are fetched into bbSrcQLo/bbDestQLo and MDShi rsh 8 is copied into
*bbSrcQHi/bbDestQHi; long pointers are fetched directly into bbSrcQLo/Hi and
*bbDestQLo/Hi. Smalltalk simulates an XM Alto in which bbFunction[12:13]
*specify that the emulator alternate bank (bits 14-15 of 177740) should be
*added into bbSrcQHi/bbDestQHi respectively.
PFetch1[AC2,bbGray2,3];*fetch dbmr
*The way bbItemsLeft and stack count is determined by gray mode requirements.
*Alto gray mode uses gray n mod 4 with n scanlines left to do, and the
*vertical direction of transfer must be the same here for compatibility.
**Aligning the gray pattern with the absolute or relative address of the
**destination bit map is superior to this algorithm but Alto incompatible.
T ← (Stack) + (2C);
*bbItemsLeft ← (scanlines left to do - 1) * 2
bbItemsLeft ← (Lsh[bbItemsLeft,1]) - T;*Exit if no items
PFetch2[AC2,bbSlx,12], Goto[bbExit,ALU<0];*Fetch slx and sty
**Note incompatibility: on Alto, neg words/scanline reverses transfer
T ← bbItemWid, Skip[R>=0];
PCF ← AC0, DblGoto[bbMDone,bbNDone,R<0];*Exit if width<0
bbNegItemWid ← (Zero) - T, Skip[ALU#0];
PCF ← AC0, DblGoto[bbMDone,bbNDone,R<0];*Exit if width=0
PFetch2[AC2,bbDlx,4];*fetch dlx and dty
bbFunction ← (bbFunction) and not (177400C), Goto[bbShrt,R>=0];
T ← 22C, Task;
PFetch2[AC2,bbDestQLo];
T ← 20C;
PFetch2[AC2,bbSrcQLo], Goto[bbDir];
bbShrt:
PFetch1[AC2,bbDestQLo,2];*bbDestQLo ← dbca
T ← Rsh[MDShi,10];
:IF[AltoXMMode]; *****************************
bbDestQHi ← T, LoadPage[bbXMPage];
PFetch1[AC2,bbSrcQLo,10], Call[bbShortXM];*bbSrcQLo ← sbca
bbFunction ← (bbFunction) and not (60C);
:ELSE; ***************************************
bbDestQHi ← T;
PFetch1[AC2,bbSrcQLo,10], Task;*bbSrcQLo ← sbca
bbSrcQHi ← T;
:ENDIF; **************************************

%Determination of BitBlt directions (T=Top, B=Bottom, L=Left, R=Right):
T-to-B is slightly faster than B-to-T, so prefer T-to-B when possible, but
Alto compatibility on gray mode requires B-to-T on dty = sty.
L-to-R is much faster than R-to-L, which uses multiple item setups/scanline,
so avoid R-to-L when possible. The heuristic here assumes src and dest bit
maps are disjoint except when sbca .eq. dbca (short mode) and sbmr .eq. dbmr.
Direction of transfer is don’t care otherwise. Page-touching prior to
inner loops is necessary only when src and dest bit maps are not disjoint or
when the BitBlt function is not restartable (xor/xnor) on a page fault.
In other situations it is safe to restart BitBlt at the beginning of the
scanline after a fault.
T-to-B, L-to-R dty < sty
B-to-T, R-to-L (dty = sty) & (sbmr = dbmr) & (dlx - slx >= 100b) &
(item >= 100b wide) & (slx+scanlinewidth > dlx)
B-to-T, L-to-R (dty > sty) or (dty = sty when not doing R-to-L)
Timing from bbBitBlt to here: 47 short, 48 long (cycles).
%
bbDir:
Dispatch[bbFunction,14,4], Call[bbFnSetup];*Odd
SALUF ← T, T ← bbDty;
LU ← (bbSty) - T;
T ← bbGray2, FreezeResult, Goto[bbTtoB,ALU>=0];
bbDBMR ← (Zero) - T, Goto[.+3,MB];
T ← bbGray;
bbSBMR ← (Zero) - T;
T ← Rsh[bbItemsLeft,1], Goto[bbGenlInit];

*Sty .ge. Dty: will go T-to-B if .g., B-to-T if .eq. for Alto compatibility
bbTtoB:
bbDBMR ← T, Goto[bbMaybeBTRL,ALU=0];
T ← bbGray, Skip[MB];
bbSBMR ← T;
T ← Rsh[Stack,1], Goto[bbGenlInit];
*StY = Dty
bbMaybeBTRL:
bbDBMR ← (Zero) - T, Skip[MB’];
T ← Rsh[bbItemsLeft,1], Goto[bbGenlInit];
T ← bbGray;
bbSBMR ← (Zero) - T;
LU ← (bbDBMR) + T;
T ← bbSlx, Skip[ALU=0];
bbTBLR:
T ← Rsh[bbItemsLeft,1], Goto[bbGenlInit];*L-to-R dbmr .ne. sbmr
*bbGray1 ← 0 forces page touching because of possible S-D overlap.
T ← (bbDlx) - T;*T ← dlx - slx
LU ← (Lsh[AllOnes,6]) and T, Skip[ALU>=0];
bbGray1 ← Zero, Goto[bbTBLR];*L-to-R if DestX < SrcX
*DestX >= SrcX; bbNegSDNonOverlap ← - (DestX - SrcX)
LU ← LdF[bbItemWid,0,12], Skip[ALU#0];*Even
bbGray1 ← Zero, Goto[bbTBLR];*L-to-R if (DestX-SrcX) < 100b
LU ← (bbItemWid) - T, Skip[ALU#0];
bbGray1 ← Zero, Goto[bbTBLR];*L-to-R if item < 100b long
bbGray1 ← Zero, Skip[Carry];*or width < non-overlap
T ← Rsh[bbItemsLeft,1], Goto[bbGenlInit];
bbNegSDNonOverlap ← (Zero) - T;
bbFunction ← (bbFunction) or (100000C), Goto[bbTBLR]; *R-to-L

*General init: T has items completed if T-to-B, items remaining if B-to-T.
*Time: (71 T-to-B), (71 to 88 B-to-T, L-to-R), (93 to 95 R-to-L) + 1 if long
bbGenlInit:
bbDty ← (bbDty) + T, Skip[MB’];*Even
LU ← bbGray2, Goto[bbDestInit];
LU ← bbGray;
bbSrcWLo ← Zero, Skip[ALU#0];*sbmr=0 not impossible
T ← RHMask[bbSrcQHi], Goto[bbAddSF];
T ← bbSty ← (bbSty) + T, Call[bbYHi0];
*bbSrcQLo/QHi + (sty*sbmr) + (slx rsh 4); product may be > 16 bits
bbGray ← Rsh[bbGray,1], Goto[bbNoAddS,R Even];
*Multiply timing: 6*nzeroes right of the left-most one + 14*nones in sbmr.
bbSrcQLo ← (bbSrcQLo) + T, Goto[.+3,ALU#0];
T ← (bbYHi) + 1, UseCOutAsCIn;
T ← bbSrcQHi ← (bbSrcQHi) + T, Goto[bbAddSF];
T ← (bbYHi) + 1, UseCOutAsCIn;
bbSrcQHi ← (bbSrcQHi) + T;
bbNoAddS: T ← bbSty ← Lsh[bbSty,1], DblGoto[bbLshyHi1,bbLshyHi0,R<0];
bbAddSF:bbSrcQHi ← (Lsh[bbSrcQHi,10]) + T + 1;
*bbSrcQHi in base reg. format
T ← LdF[bbSlx,14,4], Call[bbNegIWSub];
*bbSlast ← (Slx & 17) + ItemWid - 1 = displacement to last bit of scan-line
*Add (slx rsh 4) and copy WLo into QLo; point bbSlx at bit in 1st quadword.
bbSlast ← (Zero) - T - 1, Call[bbSBWQ];
*Time to here: (1 if long) + {(71 to 75 if no source) else multiply time +
* [(100 to 101 T-to-B), (100 to 118 B-to-T, L-to-R), (122 to 125 R-to-L)]}
LU ← bbGray2;
bbDestInit:
T ← bbDestWLo ← Zero, Goto[bbAddDF,ALU=0];
T ← bbDty, Call[bbYHi0];
*bbDestQLo/QHi + (dty*dbmr) + (dlx rsh 4); product may be > 16 bits
bbGray2 ← Rsh[bbGray2,1], Goto[bbNoAddD,R Even];
bbDestQLo ← (bbDestQLo) + T, Goto[.+3,ALU#0];
T ← (bbYHi) + 1, UseCOutAsCIn;
bbAddDF: T ← bbDestQHi ← (bbDestQHi) + T, Goto[bbAddDF1];
*Even
T ← (bbYHi) + 1, UseCOutAsCIn;
bbDestQHi ← (bbDestQHi) + T;
bbNoAddD: T ← bbDty ← Lsh[bbDty,1], DblGoto[bbLshyHi1,bbLshyHi0,R<0];
bbAddDF1:
bbDestQHi ← (Lsh[bbDestQHi,10]) + T + 1;
PFetch2[AC2,bbGray2,16], Call[bbDBWQ];
T ← LdF[bbDlx,14,4], Call[bbNegIWSub];*offset to last scan-line bit
PFetch2[AC2,bbGray,14], Skip[MB];
T ← Rsh[bbSlast,4], DblGoto[bbTS,bbNTS,R Odd];
SB ← bbDlx, Goto[bbTchD];
%Time to bbTchD/S: (1 if long) + [(106 to 111 if no source) else
(137 to 139 T-to-B), (137 to 156 B-to-T, L-to-R), (159 to 163 R-to-L)]
To this add entry/exit overhead less time between bbItemRefill and bbTchD/S:
Alto--16 + 20; Alto Mesa--10 + 30; Pilot Mesa--10 + 20
(-15 T-to-B), (-19 B-to-T), (-12 no source).
Total time: [148 to 150 T-to-B, 148 to 166 B-to-T L-to-R, 168 to 171 R-to-L,
124 to 127 no source] + [0 Pilot, 8 Alto, or 10 Alto Mesa] + [1 if long].
To this add about 60 cycles/multiply (1 multiply if no source else 2).
%

bbyHi0:
Skip[ALU>=0];*Nop exit if dty/sty < 0
PCF ← AC0, DblGoto[bbMDone,bbNDone,R<0];
bbYHi ← 0C, Return;

bbLshyHi0:
bbYHi ← Lsh[bbYHi,1], Return;
bbLshyHi1:
bbYHi ← (Lsh[bbYHi,1]) + 1, Return;

bbNegIWSub:
T ← (MNBR ← bbNegItemWid) - T;
T ← (bbGray1) or T, Skip[R Odd];
T ← (Lsh[AllOnes,1]) and T;*Make bbLast be odd
bbDlast ← (Zero) - T - 1, Return;*Mask bbLast be 0

*T[08] ← MA’, T[09] ← MB, T[10:15] ← ALU op
*The MB branch condition is used to indicate "no source."
bbFnSetup:
PFetch1[AC2,bbGray,11], Disp[.+1];*fetch sbmr

bbFunction ← 1000C, DispTable[20];*0,R or T
bbOr:
T ← 204C, Return;*0,R or T
bbX:
T ← 263C, Goto[bbForceTch];*0,R xor T
bbAN:
T ← 227C, Return;*0,R & T’

bbFunction ← 1000C;*1,R or T’
T ← 074C, Return;*1,R or T’
T ← 054C, Goto[bbForceTch];*1,R xnor T
T ← 056C, Return;*1,R & T

bbFunction ← 2000C, Goto[bbOr];*0,R or T
bbFunction ← 3000C, Goto[bbOr];*0,R or T
bbFunction ← 3000C, Goto[bbX];*0,R xor T
bbFunction ← 3000C, Goto[bbAN];*0,R & T’

T ← 304C, Goto[bbTR4];*0,R or T
T ← 304C, Goto[bbTR5];*0,R or T
T ← 363C, Goto[bbTR5Tch];*0,R xor T
T ← 327C, Goto[bbTR5];*0,R & T’

bbTR5:
bbFunction ← 5000C, Return;*type 5; no source
bbTR4:
bbFunction ← 4000C, Return;*type 4; no source
bbTR5Tch:
bbFunction ← 5000C;*type 5; touch pages
bbForceTch:
bbGray1 ← Zero, Return;


%Approx. item refill times starting at bbItemRefill are below; the inner-loop
dependent constant given in the comments before the inner loops must be
added to these and the time is 1 (Alto) or 9 (Mesa) cycles greater if
interrupts are disabled:
L-to-R, src used:
58 (T-to-B) or 61 (B-to-T) cycles
[+ 12 + 11*(NDestPages+NSrcPages-2) if xor/xnor functions or sty=dty]
L-to-R, src unused:
41 [+ 5 + 11*(NDestPages-1) if xor function]
R-to-L:
11*(NDestPages+NSrcPages) + 93 cycles
R-to-L, continuing item:
62 cycles, 47 or 63 on last continuation

When both src and dest are used the no-refill case will occur at
most 6 times followed by a src-refill, dest-refill, or item-refill.
If src and dest are word-aligned, at most 3 no-refill loops will occur
followed by a src-dest-refill or item refill.

When only the dest is used, at most 3 no-refill loops occur followed
by a src-dest-refill or item refill.
%

bbSrcFetch:
PFetch4[bbSrcQLo,bbSrc], Return;

*Note: Doing PStore4 first allows both PFetch4’s to be launched before
*transport for either occurs. If the PFetch4 for the src were done first,
*the PFetch4 for the dest could not be launched before transport for both
*preceding references had finished.
bbSrcDestRfl:
PStore4[bbDestQLo,bbDest];
T ← bbSrcWLo ← (bbSrcWLo) + (4C);
PFetch4[bbSrcQLo,bbSrc], Skip;
bbDestRfl:
PStore4[bbDestQLo,bbDest];
T ← bbDestWLo ← (bbDestWLo) + (4C);
bbDestFetch:
PFetch4[bbDestQLo,bbDest], Return;

*The bbIA, bbIB, bbIE, and bbIF dispatch tables could be united by revising
*the SrcDestRefill subroutine to check MB; this would save 12b mi but slow
*inner loops by 2 to 3 cycles.

bbInnerLoops:
*functions 1-3 and 5-7; refill times: i=4+I, sd=32, s=20, d=26, n=4
bbIA1:
bbDlx ← (DB ← bbDlx) + T, Call[bbFixG], At[bbI,bbILtype0];
T ← BBFA[SB[bbSrc]] or T;
bbIA2:
DB[bbDest] ← BBFBX[DB[bbDest]] SALUFOP T, Disp[.+1];
bbItemRefill:
T ← bbDestWLo, Goto[bbItemRfl], DispTable[5,17,3];
bbSrcDestRefill:
T ← bbDestWLo, Goto[bbSrcDestRfl];
bbSrcRefill:
T ← bbSrcWLo ← (bbSrcWLo) + (4C), Goto[bbSrcFetch];
bbDestRefill:
T ← bbDestWLo, Goto[bbDestRfl];
T ← BBFA[SB[bbSrc]] or T, Goto[bbIA2];

*functions 0 and 4; refill times: i=4+I, sd=32, s=20, d=26, n=4
**Can improve by not fetching bbDest when MNBR < -77 on dest refill.
bbIB1:
bbDlx ← (DB ← bbDlx) + T, Call[bbFixG], At[bbI,bbILtype1];
T ← BBFA[SB[bbSrc]] or T;
bbIB2:
DB[bbDest] ← BBFB[DB[bbDest]] SALUFOP T, Disp[.+1];
T ← bbDestWLo, Goto[bbItemRefill], DispTable[5,17,3];
T ← bbDestWLo, Goto[bbSrcDestRfl];
T ← bbSrcWLo ← (bbSrcWLo) + (4C), Goto[bbSrcFetch];
T ← bbDestWLo, Goto[bbDestRfl];
T ← BBFA[SB[bbSrc]] or T, Goto[bbIB2];

*function 10; refill times: i=8+I, sd=36, s=22, d=30, n=8
bbIC1:
bbDlx ← (DB ← bbDlx) + T, Call[bbFixG], At[bbI,bbILtype2];
T ← BBFA[SB[bbSrc]] or T;
DB[bbDest] ← (DB[bbDest]) and not T, Disp[.+1];
T ← PCF[bbGray] and T, Goto[bbICi], DispTable[5,17,3];
T ← PCF[bbGray] and T, Goto[bbICsd];
T ← PCF[bbGray] and T, Goto[bbICs];
T ← PCF[bbGray] and T, Goto[bbICd];
T ← PCF[bbGray] and T, Goto[bbICr];

*functions 11-13; refill times: i=6+I, sd=34, s=20, d=28, n=6
bbID1:
bbDlx ← (DB ← bbDlx) + T, Call[bbFixG], At[bbI,bbILtype3];
T ← BBFA[SB[bbSrc]] or T;
T ← PCF[bbGray] and T, Disp[.+1];
bbICi:
DB[bbDest] ← BBFBX[DB[bbDest]] SALUFOP T, Goto[bbItemRefill], DispTable[5,17,3];
bbICsd:
DB[bbDest] ← BBFBX[DB[bbDest]] SALUFOP T, Goto[bbSrcDestRefill];
bbICs:
DB[bbDest] ← BBFBX[DB[bbDest]] SALUFOP T, Goto[bbSrcRefill];
bbICd:
DB[bbDest] ← BBFBX[DB[bbDest]] SALUFOP T, Goto[bbDestRefill];
bbICr:
DB[bbDest] ← BBFBX[DB[bbDest]] SALUFOP T, Return;

*function 14; refill times: i=4+I, sd=26, s=never, d=never, n=4
**Can improve by not refilling dest and BLKSing bbGray when MNBR<-77.
bbIE1:
bbDlx ← (DB ← bbDlx) + T, Call[bbFixG], At[bbI,bbILtype4];
T ← BBFA[PCF[bbGray]];
bbIE2:
DB[bbDest] ← BBFB[DB[bbDest]] SALUFOP T, Disp[.+1];
T ← bbDestWLo, Goto[bbItemRflNS], At[bbIE,bbItem];
T ← bbDestWLo, Goto[bbDestRfl], At[bbIE,bbSDRef];
T ← BBFA[PCF[bbGray]], Goto[bbIE2], At[bbIE,bbNoRef];

*functions 15-17; refill times: i=4+I, sd=26, s=never, d=never, n=4
bbIF1:
bbDlx ← (DB ← bbDlx) + T, Call[bbFixG], At[bbI,bbILtype5];
T ← BBFA[PCF[bbGray]];
bbIF2:
DB[bbDest] ← BBFBX[DB[bbDest]] SALUFOP T, Disp[.+1];
T ← bbDestWLo, Goto[bbItemRflNS], At[bbIF,bbItem];
T ← bbDestWLo, Goto[bbDestRfl], At[bbIF,bbSDRef];
T ← BBFA[PCF[bbGray]], Goto[bbIF2], At[bbIF,bbNoRef];

bbFixG:
PCF ← bbItemsLeft, BBFBX, Return;

bbItemRflNS:
PStore4[bbDestQLo,bbDest], Call[bbCntI];
LU ← NWW, DblGoto[bbIntOff,bbIntOn,R<0];

*Worst case time to return from bbIR1 is 42 (src used).
bbItemRfl:
PStore4[bbDestQLo,bbDest], Call[bbIR1];
*Test for interrupts and done:
*Item refill time: 12.
LU ← NWW, Skip[R>=0];
bbIntOff: bbItemsLeft ← (bbItemsLeft) - (2C), Skip;
bbIntOn:bbItemsLeft ← (bbItemsLeft) - (2C), Skip[ALU#0];
T ← bbDBMR, DblGoto[bbAdvD,bbExit1,ALU>=0];
LU ← PCF ← AC0, Skip[ALU>=0];
DblGoto[bbMDone,bbNDone,ALU<0];
LU ← xfWDC, DblGoto[bbMesaInt,bbNovaInt,ALU<0];

bbIR1:
T ← MNBR ← bbNegBitsLeft, Goto[bbRtoLCont,R<0];
bbCntI:
Stack ← (Stack) + (2C), Return;

*At bbMesaInt and bbNovaint, we have committed to taking an interrupt;
*control can only get back by restarting the opcode.

***The code at bbMesaInt and bbMDone is in AltoX.Mc

*Since the Alto only checks for interrupts during jumps, we simulate JMP .
**Could call intEnt here and handle the (rare) return, if WW, ACTIVE, and
**DMA (used by intEnt) did not clobber BitBlt registers other than
**bbSrc and bbDest.
bbNovaInt:
T ← PCB, LoadPage[nePage], Goto[bbNExit];
*
LoadPage[xoPage];
*
Call[intEnt];
*
T ← bbDBMR, Goto[bbAdvD];
bbNDone:
*Time to next opcode = 20 cycles
T ← (PCB) + 1, LoadPage[nePage];
bbNExit:
T ← (PCF.word) + T, GotoP[brJmpPz];

bbExit:
PCF ← AC0, DblGoto[bbMDone,bbNDone,R<0];
bbExit1: PCF ← AC0, DblGoto[bbMDone,bbNDone,R<0];

*Item refill time: 16 (no src), 18 (src used)
*bbDestW ← bbDestQ ← bbDestW + bbDBMR
bbAdvD:
T ← bbDestQLo ← (bbDestQLo) + T, Goto[bbAD1,ALU>=0];*Even
MNBR ← bbNegItemWid, Skip[Carry];
bbDestQHi ← (bbDestQHi) - (400C) - 1;
bbDestWLo ← Zero, Skip[MB’];
SB ← bbDlx, Goto[bbTchD];
*bbSrcW ← bbSrcQ ← bbSrcW + bbSBMR
T ← bbSBMR;
bbSrcQLo ← (bbSrcQLo) + T, Call[bbASn];
%Avoid page touching and simply refill bbSrc/bbDest except when either a
non-restartable function is being executed (xor, xnor) or dty=sty, in which
case there is possible src-dest overlap. When touching, begin with the last
page of the scan-line and finish with a PFetch4 of the 1st quadword.
Initial displacement is [(ItemWidth - 1 + (startbit & 17)) rsh 4] + non-page
bits of start word, where the first term is computed during initialization.
The choice to touch/not-touch is indicated in bbSLast/bbDLast which contain
0 when not touching or some odd value when touching.
%
bbTchS:
T ← Rsh[bbSlast,4], Skip[R Odd];
bbNTS:
PFetch4[bbSrcQLo,bbSrc], Goto[bbNTS1];
bbTS:
T ← (RHMask[bbSrcQLo]) + T;
T ← (Lsh[AllOnes,10]) and T, Call[.+2];
T ← (Lsh[AllOnes,10]) + T;
PFetch4[bbSrcQLo,bbSrc], Skip[ALU=0];*Even
Return;
bbSrcWLo ← Zero;
SB ← bbSlx, Goto[bbTchD];

bbAD1:
MNBR ← bbNegItemWid, Skip[Carry’];*Even
bbDestQHi ← (bbDestQHi) + (400C) + 1;
bbNS1:
bbDestWLo ← Zero, Goto[bbNoTchS,MB];
T ← bbSBMR;
T ← bbSrcQLo ← (bbSrcQLo) + T, Call[bbASp];
T ← Rsh[bbSlast,4], DblGoto[bbNTS,bbTS,R Even];
bbNoTchS:
SB ← bbDlx;*Odd
bbTchD:
T ← Rsh[bbDlast,4], Goto[bbNTD,R Even];*Odd
T ← (RHMask[bbDestQLo]) + T;
T ← (Lsh[AllOnes,10]) and T, Call[.+2];
T ← (Lsh[AllOnes,10]) + T;
bbNTD:
PFetch4[bbDestQLo,bbDest], Skip[ALU=0];*Even
Return;
*Item refill time to here: 33 + [5 + 11*(NDPages-1) if xor function] (no src)
*50 (T-to-B), 53 (B-to-T) +
*[12 + 11*(NDPgs+NSPgs-2) if xor/xnor functions or sty=dty & sbmr=dbmr]
Dispatch[bbFunction,4,4], Goto[bbItemSetup,R>=0];
*New R-to-L item
T ← bbNegItemWid;*Odd
T ← (MNBR ← bbNegSDNonOverlap) - T, Call[bbSlxFix];*T ← bits left
bbNegBitsLeft ← (bbNegBitsLeft) - T, Goto[bbRtoLNew];

bbRtoLCont:
*Here when continuing R-to-L item.
LU ← (bbNegSDNonOverlap) - T, Call[bbRtoLC1];*Odd
*Initially T will contain ItemWidth-SDNonOverlap; subsequent iterations
*T will contain -SDNonOverlap until the last iteration for the scan-line, when
*T will contain -BitsLeft. bbNegBitsLeft is 0 at onset of each scan-line.
bbRtoLNew:
bbDlx ← (LdF[bbDlx,14,4]) + T, Call[bbSBWQ];
PFetch4[bbSrcQLo,bbSrc,0], Call[bbDBWQ];
bbNTS1:
SB ← bbSlx;
T ← bbSrcWLo ← Zero, Call[bbDestFetch];
Dispatch[bbFunction,4,4];
bbItemSetup:
T ← Lsh[bbDBMR,4], Disp[bbInnerLoops];*Even

**Worst case time to return from bbSlxFix is 46 cycles.
bbRtoLC1:
bbDestWLo ← Zero, Skip[Carry’];
T ← MNBR ← bbNegSDNonOverlap;
bbNegBitsLeft ← (bbNegBitsLeft) - T, Goto[bbSlxFix];

%bbSBWQ and bbDBWQ are used both by initialization and in the R-to-L case.
bbASn/bbASp are called by item refill to advance QLo/QHi by a signed
word displacement, bbSBMR. The equivalent code in bbDBWQ is open-coded
for item refill.
%
bbSBWQ:
T ← Rsh[bbSlx,4], Skip[R>=0];
T ← (Lsh[AllOnes,14]) or T;
T ← bbSrcQLo ← (bbSrcQLo) + T, Goto[bbASp,ALU>=0];
bbASn:
T ← Lsh[bbSrcQLo,4], Skip[Carry];
bbSrcQHi ← (bbSrcQHi) - (400C) - 1;
bbSlx ← (LdF[bbSlx,14,4]) + T, Return;
bbASp:
T ← Lsh[bbSrcQLo,4], Skip[Carry’];
bbSrcQHi ← (bbSrcQHi) + (400C) + 1;
bbSlxFix:
bbSlx ← (LdF[bbSlx,14,4]) + T, Return;

bbDBWQ:
T ← Rsh[bbDlx,4], Skip[R>=0];
T ← (Lsh[AllOnes,14]) or T;
T ← bbDestQLo ← (bbDestQLo) + T, Goto[bbADp,ALU>=0];*Even
T ← Lsh[bbDestQLo,4], Skip[Carry];
bbDestQHi ← (bbDestQHi) - (400C) - 1;
bbDlx ← (LdF[bbDlx,14,4]) + T, Return;
bbADp:
T ← Lsh[bbDestQLo,4], Skip[Carry’];
bbDestQHi ← (bbDestQHi) + (400C) + 1;
bbDlxFix:
bbDlx ← (LdF[bbDlx,14,4]) + T, Return;

:END[BitBlt];