;; ShowCharMc.Mu -- Spruce inner loop

; Instruction positioning
!1,2, useTest, GetChar1;
!1,2, gc1, FullReturn;
!1,2, GetOld, GetNew;
!1,2, RangeError, notTooLow;
!1,2, notTooHigh, RangeError2;
!1,2, chk1, OffPage;
!1,2, chk11, Double;
!1,2, chk2, RangeError3;
!1,2, OffPage2, chk3;
!1,2, noCarry, Carry;
!1,2, noCarryB, CarryB;
!1,2, RecordUses, noRecord;
!1,2, old, new;
!1,2, OnCopy, enter1;
!1,2, BufFull, GetChar;

ShowChars:
	L←PC;
	savedPC←L;
	L←177026, TASK;
	PC←L; *4+entry*

;; let c=not immediate? WindowReadByte(DL), immediate>0? DL>>Bytes↑i, DL>>STR.char↑i
GetChar1:	L←ct-1, :gc2; [*3max* here]
GetChar:	L←ct-1;
gc2:	ct←L, SH<0;
	L←byteIdx+1, BUSODD, :gc1;	[gc1, FullReturn*5*]
; Fetch new word or use old one
gc1:	byteIdx←L, :GetOld;		[GetOld, GetNew]
GetOld:	T←377;
	L←T←data.T, :PlaceChar;
GetNew:	temp←L RSH 1;
	T←base;
	MAR←temp+T;
	NOP; available
	;available
	;available
	L←MD;
	data←L, TASK;
	temp←L LCY 8; *13*
	T←377;
	L←T←temp.T, :PlaceChar;

;; if c < bc % c > ec then {resultis 1} ; too high or too low
PlaceChar:	c←L;
	L←bcM1-T;
	L←ec-T, SH<0;

;; let icc=c+ICCOffset
	L←ICCOffset+T, SH<0, :RangeError; [RangeError*12*, notTooLow]

;; let p=WidthPointer+c*(size CharWidth/16)
notTooLow:  icc←L, L←T, :notTooHigh ;      [notTooHigh, RangeError1*13*]
notTooHigh: L←LASTL+T;	; next sequences makes c lsh 3 -- here, L=c lsh 1
	temp←L LSH 1;	; temp=c lsh 2
	L←T←temp;
	L←LASTL+T;	; L=c lsh 3
	T←WidthPointer;
	L←LASTL+T, TASK;
	p←L; *18*

;; let b=CurB!0+p>>CharWidth.OB
	T←5;		; read 5, then 4
	MAR←p+T;
	T←CurB0;
	;available
	;available
	L←MD+T;
	T←MD;
	b←L;

;; ShowChars, contd.

;; let s=CurS!0+p>>CharWidth.OS (sort of)
;; let band=s rshift 4 (sort of)
; actually, lineBand = {s, above} RROT 4
	L←CurS0+T;
	T←LASTL;
	temp←L MRSH 1;
	L←T←temp;
	temp←L MRSH 1;
	L←T←temp;
	temp←L MRSH 1;
	L←T←temp, TASK;
	lineBand←L MRSH 1;	*17*

;; let ds, db =p>>CharWidth.DS, p>>CharWidth.DB
	T←6;
	MAR←p+T;
;; test b < 4096 & ...
	T←b;
	L←7777-T;
	L←MD, SH<0;
	AC2←L, :chk1;	[chk1, OffPage*6* ]
chk1:	L←MD, BUS=0, TASK;
	AC1←L, :chk11; *8*	[chk11, Double ]
;; test db>0 & band ls nVisibleBands or resultis 2
chk11:	L←AC1-1;
	T←7777, SH<0;
	L←lineBand AND T, :chk2; [chk2, RangeError3*3*]
chk2:	band←L;
	T←nVisibleBands;
	L←LASTL-T;

;; 	BandFree!0=100000b+icc	//First entry
	MAR←BandFree, SH<0;
	T←100000, :OffPage2; [OffPage2*8*,chk3] band>nVisibleBands
chk3:	L←icc+T, TASK;
	MD←LASTL; *10*
;;	BandFree!1=(s lshift 12)+b
	T←170000;
	MAR←BandFree+1;
	T←lineBand.T;
	L←b+T, TASK;
	MD←LASTL; *5*

;; DoubleAdd(CurS, lv p>>CharWidth.WS)
Double:	MAR←T←p+1;
	L←2+T;
	p←L;
	T←CurS1;
	L←MD+T;
	CurS1←L, ALUCY;
	T←CurS0, :noCarry;	[noCarry, Carry]
Carry:	T←0+T+1;
noCarry:	L←MD+T;

;; DoubleAdd(CurB, lv p>>CharWidth.WB)
	MAR←p;
	CurS0←L;
	T←CurB1;
	; available
	L←MD+T;
	CurB1←L, ALUCY;
	T←CurB0, :noCarryB;	[noCarryB, CarryB]
CarryB:	T←0+T+1;
noCarryB:	L←MD+T, TASK;
	CurB0←L; *18*

;; ShowChars, contd.
;;	if db eq 0 then goto GetChar...
	SINK←AC1, BUS=0;
;; 	if ICCUses!icc ge 0 then . . .
	T←icc, :useTest;	[useTest, GetChar1]
useTest:	MAR←L←ICCUses+T;
	uses←L;
	L←2;
	entryLen←L; enter a 2-long value
	L←MD;
	SH<0, TASK;
	temp←L, :RecordUses; [RecordUses, noRecord]; *9*

RecordUses: L←77, SWMODE;
	AC0←L, :MUL;		db*ds+3*16+15
Mret:	L←AC1;
	T←AC0;
	AC1← L MRSH 1, L←T;	(. . .) /16
	AC0← L RSH 1;
	L←AC1;
	T←AC0;
	AC1← L MRSH 1, L←T;
	AC0← L RSH 1;
	L←AC1;
	T←AC0;
	AC1← L MRSH 1, L←T;
	AC0← L RSH 1;
	L←AC1;
	T←AC0, TASK;
	AC1← L MRSH 1; *17*
	T←EvenMask;		(. . .)&(177776) // even number
	SINK←temp, BUS=0;
	T←AC1.T, :old;	[old, new]
new:	L←fspn+T;
	fspn←L, :sto;
old:	L←fspo+T;
	fspo←L;
sto:	MAR←uses;
	T←2;
	L←temp-T, TASK;
	MD←LASTL, :noRecord; *10*

;; 	BandEnter(band, size BEChar/16) -- JMPRAM 30 enters here --
;;	onlyOnCopy, band, BandTable, CopyTable , BandFree, BandAvail, entryLen set up
BandEnter:
	L←0;
	ct←L; force return right away
	L←PC, TASK;
	savedPC←L; *2*
noRecord: SINK←onlyOnCopy, BUS=0;
	T←band, :OnCopy ;[OnCopy, enter1]
; Count contributions to jump for this band
OnCopy: MAR←L←CopyTable+T;
	temp←L;
	T←entryLen;
	;available
	L←MD+T;
	MAR←temp;
	TASK;
	;available
	MD←LASTL; *11*
	T←band;
enter1:	MAR←BandTable+T;
	T←entryLen+1;
	;
	MD←BandFree;
	SINK←MD;
	L←MD;
	MAR←BandFree-1;
	temp←L;
	L←BandFree+T;
	MD←temp;
	BandFree←L;
	L←BandAvail+T;
	BandAvail←L, SH<0, TASK;
	:BufFull;  [BufFull*0*,GetChar] *16max*

!1, 1, CodeReturn; Kill pending branches
FullReturn: L←0, TASK, :CodeReturn; [CodeReturn, CodeReturn] $MUDone $0
RangeError: L←MUCharRange, TASK, :CodeReturn; . . .
RangeError2: L←MUCharRange, TASK, :CodeReturn; . . .
RangeError3: L←MUCharRange, TASK, :CodeReturn;
OffPage:	L←MUOffPage, TASK, :CodeReturn;
OffPage2:	L←MUOffPage, TASK, :CodeReturn;
BufFull:	L←MUBufFull, TASK, :CodeReturn;

CodeReturn: AC0←L; *15max*
	L←savedPC, TASK;
	PC←L, :NOVEM; *9*

; FlushChars

!1,2, flDoit, flDone;
!1,2, flNotCh, flCh;
!1,2, flW2, flW4;
!1,2, flOLp, flCant;
!1,2, flGoOn, FlushLoop;

FlushChars:
	T←177777;
	L←leftCt XOR T, TASK;
	leftCt←L; ** convert from -(# left+1) to #left
FlushLoop:
	MAR←p-1, SINK←p, BUS=0;
	L←p, :flDoit; [flDoit, flDone]
flDoit:	pData←L;
	MD←0; clear pointer entry
	SINK←MD; switch back to original address (could use if orig. was even!)
	L←MD;
	MAR←p;
	p←L; ready for next time!
	;available
	;available
	L←MD, TASK;
	typeWd←L; *12*
	L←typeWd;
	T←37, SH<0;
	T←LASTL.T, :flNotCh; [flNotCh, flCh]
flNotCh: L←BERectangleH-T;
	NOP, SH=0;
flCh:	L←T←3, :flW2; [flW2, flW4]
flW2:	L←T←ONE;
flW4:	numData←L;
	L←leftCt-T-1;
	SH<0, TASK;
	leftCt←L, :flOLp; *11max* [flOLp, flCant]
flOLp:	MAR←L←outAddr+1;
	outAddr←L;
	L←numData-1, BUS=0;
	MD←typeWd, :flGoOn; [flGoOn,FlushLoop]
flGoOn:
	MAR←pData+1;
	numData←L;
	L←pData+1;
	pData←L;
	L←MD, TASK;
	typeWd←L, :flOLp; *10*

!1,1,FlushReturn;
; This can almost certainly be bummed -- reverse change to leftCt (ugh!)
flCant:	T←numData;
	L←leftCt+T+1;
	leftCt←L;
	L←MUCant, TASK, :FlushReturn;
flDone:	L←0, TASK, :FlushReturn; MUDone

; odd-aligned to kill branches
FlushReturn:
	AC0←L; **
	T←177777;
	L←leftCt XOR T, TASK;
	leftCt←L, :NOVEM; ** convert #left to -(#left+1)


;; DCS, September 29, 1978  8:50 AM, derived from ShowCharacter in SpruceShow
;; October 2, 1978  7:20 PM, working away -- getting faster!
;; October 3, 1978  11:12 AM, define regs (used all!), last minor mods before assembly test
;; October 3, 1978  2:43 PM, repairs after deskcheck
;; October 4, 1978  10:10 AM, bugs in setup code (4, 1 a typo)
;; October 4, 1978  5:18 PM, bug in onCopy dispatch (wrong order -- a typo), and fspn/o calc (off by 2x)
;; October 5, 1978  8:30 AM, correct OrbitSizeChar computation
;; October 5, 1978  9:45 AM, ShowChars updates BandFree, BandAvail, each time out;
;;				fetches same each time in
;; October 5, 1978  11:11 AM, double store must happen one cycle earlier! Good!
;; October 18, 1978  12:17 PM, remove all setup code -- use RLoad, Store instructions instead
;; October 20, 1978  11:57 AM, move defs to SpruceDefs
;; October 22, 1978  12:00 AM, add FlushChars
;; October 23, 1978  7:01 AM, complement leftCt in and out (easier than in ML code)
;; October 24, 1978  8:51 AM, update CopyTable!band if onlyOnCopy -- remove branching hair from flush
;; October 24, 1978  9:17 AM, add linkage allowing enter microcode to be used as BandEnter
;;