{File name XLispMakeGraph.mc
Description:  DandeLion InterLisp Emulator LispFloatArray
Author: Charnley
Last modified: Charnley              20-Aug-84 15:55:49
Created:   8-Jun-84 10:04:55
}

RegDef[umaskrealLo, U, 045],
RegDef[umaskrealHi, U, 046];

{	MAKEGRAPH 337
	Args:
	S-12  Ptr to list of Kount values:  value in [0..255]
	S-10  Ptr to list of 256 patterns:  pattern[i] used to display value = i
	S-8  X:  x-displacement of first bit in target bitmap
	S-6  Addr of target map:  first word of target bitmap {left edge}
	S-4  Target map width:  words wide of target bitmap:  in [0..255]
	S-2  Pattern height:  number of bits high {repeated} of pattern: in [1..16]
	S-0  Pattern width:  number of bits wide of pattern: in [1..16]
	TOS  Kount
}

{	u regs
	uS2Hi, uS2Lo ptr to patterns
	uS1Hi, uS1Lo ptr to values
	uXdisp value of x-displacement
	uDHi, uDLo ptr to leftmost top dest address
	uWidth map width in words {width-1 if two dest words}
	uICount pattern height
	uNBits  pattern width in bits
	umaskrealLo  saves mask for source into dest low word
	umaskrealHi  saves mask for source into dest high word
	uShiftedPattLo  bits to be ored into first dest word
	uShiftedPattHi  bits to be ored into second dest word
}

{	r regs
	S1  real address of next value
	S2  real address of pattern, and temp
	D  real address of next dest
	Zorch  remap temp
	Zimph  remap temp
	Stemp  general temp
	Kount  outer loop count
}

{	link regs
L0
     LMGremapDret
	Set[L0.LMGDinit, 4],
	Set[L0.LMGD1, 2],
	Set[L0.LMGD2, 3],
	Set[L0.LMGD3, 5],
     LMGremapS1ret
	Set[L0.LMGS1init, 4],
	Set[L0.LMGS1S2, 6],
     LMGremapS2ret
	Set[L0.LMGS1S2, 6],
     AllignRet
	Set[L0.LMGS1S2, 6],
L1
	return link for reg saving
     LFASaveRegsRet
	Set[L1.LMGprep, 5],

	amount to left shift source
L2
	0  --  plot each value
	1  --  plot every other value

L3
	0  first inner loop, one dest word
	1  first inner loop, two dest words
	2  other inner loop, one dest word
	3  other inner loop, two dest words
}

{
	{init}
	  {generate: 1st target word mask, 2nd target word mask, Shift count for pattern}
	  {for OCount in [0..Kount - 1]}
	    {get next value}
	    {get pattern[value]}
	    {shift pattern}
	    {mask pattern}{not needed for 'or'  --  assumes pattern is zero filled}
	    {for ICount in [0..Pattern height - 1]}
	      {merge pattern into target word(s)}
	      {next ICount}
	    {next OCount}
}
LMG:	at[IBLT],
	Xbus ← ibNA, XDisp,	c1;
	L2 ← 0, BRANCH[iblt, iblt2],	c2;{put ib into L2}
iblt:
	GOTO[ibltstart],	c3;
iblt2:
	GOTO[ibltstart],	c3;

ibltstart:
	L1 ← L1.LMGprep,	c1;
	CALL[LFASaveRegsHere],	c2;{this does S ← S - 4}

	MAR ← S ← [rhS, S - 8],	c1, at[L1.LMGprep, 10, LFASaveRegsRet];
LMGS1ret:
	BRANCH[$, LMGS1, 1],	c2;
	Stemp{S1Lo} ← MD,	c3;{S-12}

	MAR ← [rhS, S - 1],	c1;
	uS1Lo ← Stemp, CANCELBR[$, 2],	c2;
	Stemp{S1Hi} ← MD,	c3;

	MAR ← S ← [rhS, S + 2],	c1;
LMGS2ret:
	uS1Hi ← Stemp, BRANCH[$, LMGS2, 1],	c2;
	Stemp {S2Lo}← MD,	c3;{S-10}

	MAR ← [rhS, S - 1],	c1;
	uS2Lo ← Stemp, CANCELBR[$, 2],	c2;
	Stemp{S2Hi} ← MD,	c3;

	MAR ← S ← [rhS, S + 2],	c1;
LMGS3ret:
	uS2Hi ← Stemp, BRANCH[$, LMGS3, 1],	c2;
	Stemp {Xdisp}← MD,	c3;{S-8}

	MAR ← S ← [rhS, S + 2],	c1;
LMGS4ret:
	uXdisp ← Stemp, BRANCH[$, LMGS4, 1],	c2;
	Stemp{DLo} ← MD,	c3;{S-6}

	MAR ← [rhS, S - 1],	c1;
	uDLo ← Stemp, CANCELBR[$, 2],	c2;
	Stemp{DHi} ← MD,	c3;

	MAR ← S ← [rhS, S + 2],	c1;
LMGS5ret:
	uDHi ← Stemp, BRANCH[$, LMGS5, 1],	c2;
	Stemp{Width} ← MD,	c3;{S-4}

	MAR ← S ← [rhS, S + 2],	c1;
LMGS6ret:
	uWidth ← Stemp, BRANCH[$, LMGS6, 1],	c2;
	Stemp{ICount} ← MD,	c3;{S-2}

	MAR ← S ← [rhS, S + 2],	c1;
LMGS7ret:
	uICount ← Stemp, BRANCH[$, LMGS7, 1],	c2;
	Stemp{NBits} ← MD,	c3;{S-0}

	uNBits ← Stemp, GOTO[LMGprep],	c1;

LMGS1:
	S ← S - 0FF - 1,	c3;
	MAR ← S ← [rhS, S + 0], GOTO[LMGS1ret],	c1;

LMGS2:
	S ← S + 0FF + 1,	c3;
	MAR ← S ← [rhS, S + 0], GOTO[LMGS2ret],	c1;

LMGS3:
	S ← S + 0FF + 1,	c3;
	MAR ← S ← [rhS, S + 0], GOTO[LMGS3ret],	c1;

LMGS4:
	S ← S + 0FF + 1,	c3;
	MAR ← S ← [rhS, S + 0], GOTO[LMGS4ret],	c1;

LMGS5:
	S ← S + 0FF + 1,	c3;
	MAR ← S ← [rhS, S + 0], GOTO[LMGS5ret],	c1;

LMGS6:
	S ← S + 0FF + 1,	c3;
	MAR ← S ← [rhS, S + 0], GOTO[LMGS6ret],	c1;

LMGS7:
	S ← S + 0FF + 1,	c3;
	MAR ← S ← [rhS, S + 0], GOTO[LMGS7ret],	c1;

LMGprep:
	S2 ← uXdisp,	c2;
	Zimph ← S2 and ~0F,	c3;

	Zimph ← Zimph LRot12,	c1;{Zimph set to dest word offset from Xdisp}
	Ybus ← S2, YDisp,	c2;
	Xbus ← 1, XDisp, DISP4[Mask],	c3;

	{build a mask of left zero's, with one's starting at first bit}
	{one cycle subroutine returns mask in Stemp} {c1}
	umaskrealLo ← Stemp,	c2, at[1, 10, MaskRet];
	Q ← uNBits,	c3;
	Ybus ← S2 + Q,  YDisp,	c1;
	Xbus ← 3, XDisp, DISP4[Mask],	c2;

	{build a mask of left one's, with zero's starting past last bit}
	{one cycle subroutine returns mask in Stemp} {c3}

	Ybus ← ~Stemp, ZeroBr,	c1, at[3, 10, MaskRet];{mask is wrong for position 0; test and fix}

	S1 ← 0 - S2, BRANCH[Tmask, Fmask],	c2;
Tmask:
	umaskrealHi ← ~Stemp, GOTO[LMGz],	c3;
Fmask:
	umaskrealHi ← Stemp, GOTO[LMGz],	c3;

LMGz:
	D ← uNBits,	c1;
	Ybus ← S1 - D, YDisp,	c2;{left shift amount = - NBits - Xdisp}
	Xbus ← 2, XDisp, DISP4[Mask], L1 ← 0,	c3;{place left cycle amount in L1}

	{one cycle subroutine returns garbage in Stemp}{c1}
	D ← D - 1,	c2, at[2, 10, MaskRet];
	Ybus ← D + S2, NibCarryBr,	c3;

	S2 ← uWidth, L3 ← 0, BRANCH[oneDW, twoDW],	c1;{place oneDW{0} / twoDW{1} into L3}

oneDW:
	Q ← umaskrealLo,	c2;
	Q ← Q and umaskrealHi,	c3;
	umaskrealLo ← Q,	c1;


	GOTO[anyDW],	c2;
twoDW:
	S2 ← S2 - 1, GOTO[anyDW],	c2;{sub one from width if two dest words}
anyDW:
	,	c3;

	uWidth ← S2,	c1;{now in words or words - 1}
	L0 ← L0.LMGDinit, Zorch ← uDLo,	c2;
	Q ← rhZorch ← uDHi, CALL[LMGremapDinit],	c3;
	{Zimph set up with word offset}

	rhZorch ← Q ← uS1Hi,	c2, at[L0.LMGDinit, 10, LMGremapDret];
	Zorch ← uS1Lo, CALL[LMGremapS1init],	c3;

	L0 ← L0.LMGS1S2,	c2, at[L0.LMGDinit, 10, LMGremapS1ret];
	Zimph ← MD, CALL[LMGremapS2],	c3;

LMGdoubleouter:
	MAR ← S1 ← [rhS1, S1 - 2], BRANCH[LMGout, LMGend],	c1;

LMGouterloop:
	{get next value}
	MAR ← S1 ← [rhS1, S1 - 1], BRANCH[LMGout, LMGend],	c1;
LMGout:
	BRANCH[$, LMGremapS1, 1],	c2, at[L0.LMGS1S2, 10, LMGremapS1ret];;
	Zimph ← MD, CALL[LMGremapS2],	c3;

	{use value as index into pattern table}
	S2 ← umaskrealLo, L1Disp,	c2, at[L0.LMGS1S2, 10, LMGremapS2ret];
	Stemp ← MD, DISP4[Allign],	c3;

LMGpause:
	uShiftedPattLo ← Stemp and S2,	c1, at[L0.LMGS1S2, 10, AllignRet];
	S2 ← umaskrealHi,	c2;
	uShiftedPattHi ← Stemp and S2,	c3;

	Q ← ~umaskrealLo,	c1;
	S2 ← uWidth, L3Disp,	c2;
	Stemp ← uICount, DISP2[Innerloop],	c3;

	MAR ← [rhD, D + 0], GOTO[SInner], L3 ← 2,	c1, at[0, 4, Innerloop];
	MAR ← D ← [rhD, D + S2{Width}], GOTO[SInner], L0 ← L0.LMGD1,	c1, at[2, 4, Innerloop];
SInner:
	Stemp{ICount} ← Stemp - 1, ZeroBr, BRANCH[$, LMGremapD1, 1],	c2;
remapD1ret:
	Q ← MD and Q, BRANCH[Smoreinner, Snomoreinner],	c3;

Smoreinner:
	MAR ← [rhD, D + 0],	c1;
	MDR ← Q or uShiftedPattLo, L3Disp,	c2;
	Q ← ~umaskrealLo, DISP2[Innerloop],	c3;

Snomoreinner:
	MAR ← [rhD, D + 0], L0 ← L0.LMGS1S2,	c1;
	MDR ← Q or uShiftedPattLo, L2Disp,	c2;
	Kount{OCount} ← Kount - 1, ZeroBr, BRANCH[LMGouterloop, LMGdoubleouter],	c3;

	MAR ← [rhD, D + 0], GOTO[DInner], L3 ← 3,	c1, at[1, 4, Innerloop];
	MAR ← D ← [rhD, D + S2{Width - 1}], GOTO[DInner], L0 ← L0.LMGD2,	c1, at[3, 4, Innerloop];
DInner:
	BRANCH[$, LMGremapD2, 1],	c2;
remapD2ret:
	Q ← MD and Q,	c3;

	MAR ← [rhD, D + 0],	c1;
	MDR ← Q or uShiftedPattLo,	c2;
	Q ← ~umaskrealHi,	c3;

	MAR ← D ← [rhD, D + 1], L0 ← L0.LMGD3,	c1;
	Stemp{ICount} ← Stemp - 1, ZeroBr, BRANCH[$, LMGremapD3, 1],	c2;
remapD3ret:
	Q ← MD and Q, BRANCH[Dmoreinner, Dnomoreinner],	c3;

Dmoreinner:
	MAR ← [rhD, D + 0],	c1;
	MDR ← Q or uShiftedPattHi, L3Disp,	c2;
	Q ← ~umaskrealLo, DISP2[Innerloop],	c3;

Dnomoreinner:
	MAR ← [rhD, D + 0], L0 ← L0.LMGS1S2	c1;
	MDR ← Q or uShiftedPattHi, L2Disp,	c2;
	Kount{OCount} ← Kount - 1, ZeroBr, BRANCH[LMGouterloop, LMGdoubleouter],	c3;

LMGend:
	Q ← 14'd, CANCELBR[$, 3],	c2;
	L1 ← L1.LFAexit,	c3;

	GOTO[LFACommonExit],	c1;

{	,	c3, at[L1.LFGexit, 10, RestoreRegsRet];
	{instruction dispatch}

	Bank ← EmuBank,	c1;
	PC ← PC + PC16, L2 ← L2.0, IBDisp,	c2;
	L2 ← L2.0, DISPNI[OpTable],	c3;
}

LMGremapD1:
	Zorch ← uDLo, CANCELBR[LMGremapD],	c3;

	Ybus ← Stemp, ZeroBr, GOTO[remapD1ret],	c2, at[L0.LMGD1, 10, LMGremapDret];

LMGremapD2:
	Zorch ← uDLo, GOTO[LMGremapD],	c3;

	GOTO[remapD2ret],	c2, at[L0.LMGD2, 10, LMGremapDret];

LMGremapD3:
	Zorch ← uDLo, CANCELBR[LMGremapD],	c3;

	Ybus ← Stemp, ZeroBr, GOTO[remapD3ret],	c2, at[L0.LMGD3, 10, LMGremapDret];

LMGremapD:
	MAR ← Zorch ← [Zorch, D + 0],	c1;{byte merge only}
	Zimph ← 0FF + 1,	c2;
	rhZorch ← uDHi,	c3;

LMGremapDinit:
	Zorch ← Zorch + Zimph, CarryBr,	c1;
	uDLo ← Zorch, BRANCH[LMGDnocar, LMGDcar],	c2;

LMGDcar:
	Zimph ← Zorch,	c3;

	Zorch ← rhZorch + 1, LOOPHOLE[byteTiming],	c1;
	rhZorch ← Zorch LRot0,	c2;
	Zorch ← Zimph,	c3;

	uDHi ← Zorch,	c1;
	,	c2;
	GOTO[LMGDmap],	c3;

LMGDnocar:
	,	c3;

LMGDmap:
	Map ← [rhZorch, Zorch],	c1;
	,	c2;
	rhD ← D ← MD, XwdDisp,	c3;

	Map ← [rhZorch, Zorch], DISP2[LMGmapD, 1],	c1;
	MDR ← D or 30, GOTO[LMGDok],	c2, at[1, 4, LMGmapD];
	Rx ← D, GOTO[LMGpagefault],	c2, at[3, 4, LMGmapD];

LMGDok:
	L0Disp,	c3;

	MAR ← D ← [rhD, Zorch + 0], DISP4[LMGremapDret],	c1;

LMGremapS1init:
	Zimph ← Kount - 1, L2Disp,	c1;
	Zorch ← Zorch + Zimph, CarryBr, BRANCH[LMGsingleS1, LMGdoubleS1],	c2;

LMGdoubleS1:
	Zorch ← Zorch - Zimph, CANCELBR[$],	c3;

	Zimph ← Zimph + Zimph,	c1;
	Zorch ← Zorch + Zimph, CarryBr,	c2;

LMGsingleS1:
	uS1Lo ← Zorch, BRANCH[LMGremapS1map, LMGS1initS1car],	c3;

LMGS1initS1car:
	Q ← Q + 1,	c1;
	rhZorch ← Q LRot0,	c2;
	GOTO[LMGremapS1map],	c3;

LMGremapS1:
	Zorch ← uS1Lo, GOTO[LMGremapS1sub],	c3;

LMGremapS1sub:
	MAR ← Zorch ← [Zorch, S1 + 0],	c1;{byte merge only}
	Zimph ← 0FF + 1,	c2;
	Q ← rhZorch ← uS1Hi,	c3;

	Zorch ← Zorch - Zimph, CarryBr,	c1;
	uS1Lo ← Zorch, BRANCH[LMGS1car, LMGS1nocar],	c2;

LMGS1car:
	Q ← Q - 1,	c3;
	rhZorch ← Q LRot0,	c1;
	,	c2;

LMGS1nocar:
	,	c3;

LMGremapS1map:
	Map ← [rhZorch, Zorch],	c1;
	uS1Hi ← Q,	c2;
	rhS1 ← S1 ← MD, XwdDisp,	c3;

	Map ← [rhZorch, Zorch], DISP2[LMGmapS1],	c1;
	MDR ← S1 or 10, GOTO[LMGS1ok],	c2, at[0, 4, LMGmapS1];
	MDR ← S1 or 10, GOTO[LMGS1ok],	c2, at[1, 4, LMGmapS1];
	MDR ← S1 or 10, GOTO[LMGS1ok],	c2, at[2, 4, LMGmapS1];
	Rx ← S1, GOTO[LMGpagefault],	c2, at[3, 4, LMGmapS1];

LMGS1ok:
	L0Disp,	c3;

	MAR ← S1 ← [rhS1, Zorch + 0], DISP4[LMGremapS1ret]	c1;

{----	S2 REMAP   ----}
LMGremapS2:
	Zorch ← uS2Lo,	c1;
	Zorch ← Zorch + Zimph, CarryBr,	c2;
	rhZorch ← uS2Hi, BRANCH[LMGS2nocar, LMGS2car],	c3;

LMGS2car:
	Q ← rhZorch,	c1;
	Q ← Q + 1,	c2;
	rhZorch ← Q LRot0,	c3;

LMGS2nocar:
	{map S2}
	Map ← [rhZorch, Zorch],	c1;
	,	c2;
	rhS2 ← S2 ← MD, XwdDisp,	c3;

	Map ← [rhZorch, Zorch], DISP2[LMGmapS2],	c1;
	MDR ← S2 or 10, GOTO[LMGS2ok],	c2, at[0, 4, LMGmapS2];
	MDR ← S2 or 10, GOTO[LMGS2ok],	c2, at[1, 4, LMGmapS2];
	MDR ← S2 or 10, GOTO[LMGS2ok],	c2, at[2, 4, LMGmapS2];
	Rx ← S2, GOTO[LMGpagefault],	c2, at[3, 4, LMGmapS2];

LMGS2ok:
	L0Disp,	c3;

	MAR ← S2 ← [rhS2, Zorch + 0], RET[LMGremapS2ret]	c1;

LMGpagefault:
	TOS ← uTOS,	c3;

LMGfault:
	,	c1;
	GOTO[LFApagefault],	c2;

{	Left Allign by dispatched amount, return thru L0}
	Stemp ← Stemp LRot0, GOTO[SHzero],	c*, at[00, 10, Allign];
	Stemp ← Stemp LRot0, GOTO[SHone],	c*, at[01, 10, Allign];
	Stemp ← Stemp LRot0, GOTO[SHtwo],	c*, at[02, 10, Allign];
	Stemp ← Stemp LRot4, GOTO[SHmin1],	c*, at[03, 10, Allign];
	Stemp ← Stemp LRot4, GOTO[SHzero],	c*, at[04, 10, Allign];
	Stemp ← Stemp LRot4, GOTO[SHone],	c*, at[05, 10, Allign];
	Stemp ← Stemp LRot4, GOTO[SHtwo],	c*, at[06, 10, Allign];
	Stemp ← Stemp LRot8, GOTO[SHmin1],	c*, at[07, 10, Allign];
	Stemp ← Stemp LRot8, GOTO[SHzero],	c*, at[08, 10, Allign];
	Stemp ← Stemp LRot8, GOTO[SHone],	c*, at[09, 10, Allign];
	Stemp ← Stemp LRot8, GOTO[SHtwo],	c*, at[0A, 10, Allign];
	Stemp ← Stemp LRot12, GOTO[SHmin1],	c*, at[0B, 10, Allign];
	Stemp ← Stemp LRot12, GOTO[SHzero],	c*, at[0C, 10, Allign];
	Stemp ← Stemp LRot12, GOTO[SHone],	c*, at[0D, 10, Allign];
	Stemp ← Stemp LRot12, GOTO[SHtwo],	c*, at[0E, 10, Allign];
	Stemp ← Stemp LRot0, GOTO[SHmin1],	c*, at[0F, 10, Allign];

SHzero:
	Stemp ← Stemp, L0Disp, GOTO[SHF0],	c*;

SHone:
	Stemp ← LRot1 Stemp, L0Disp, GOTO[SHF0],	c*;

SHtwo:
	Stemp ← LRot1 Stemp, L0Disp, GOTO[SHF1],	c*;

SHmin1:
	Stemp ← RRot1 Stemp, L0Disp, GOTO[SHF0],	c*;

SHF0:
	Stemp ← Stemp, RET[AllignRet],	c*;

SHF1:
	Stemp ← LRot1 Stemp, RET[AllignRet],	c*;

	{Mask generation subroutine}
	Stemp ← 1, RET[MaskRet],	c*, at[0F, 10, Mask];
	Stemp ← 3, RET[MaskRet],	c*, at[0E, 10, Mask];
	Stemp ← 7, RET[MaskRet],	c*, at[0D, 10, Mask];
	Stemp ← 0F, RET[MaskRet],	c*, at[0C, 10, Mask];
	Stemp ← 1F, RET[MaskRet],	c*, at[0B, 10, Mask];
	Stemp ← 3F, RET[MaskRet],	c*, at[0A, 10, Mask];
	Stemp ← 7F, RET[MaskRet],	c*, at[09, 10, Mask];
	Stemp ← 0FF, RET[MaskRet],	c*, at[08, 10, Mask];
	Stemp ← LShift1 0FF, SE←1, RET[MaskRet],	c*, at[07, 10, Mask];
	Stemp ← RShift1 u7FF, RET[MaskRet],	c*, at[06, 10, Mask];
	Stemp ← u7FF, RET[MaskRet],	c*, at[05, 10, Mask];
	Stemp ← RShift1 u1FFF, RET[MaskRet],	c*, at[04, 10, Mask];
	Stemp ← u1FFF, RET[MaskRet],	c*, at[03, 10, Mask];
	Stemp ← uTT3FFF, RET[MaskRet],	c*, at[02, 10, Mask];
	Stemp ← RShift1 (Stemp xor ~Stemp), RET[MaskRet],	c*, at[01, 10, Mask];
	Stemp ← Stemp xor ~Stemp, RET[MaskRet],	c*, at[00, 10, Mask];

	{ E N D }