; O R B I T   Microcode
;
; Must be fetched from a root microcode file that defines the low-RAM locations, etc.
; See [Ivy]<Spruce>SpruceMc.MU
;
; Location 720b points to a control table (even address) with
; the following entries:
;0	Directive -- tells which function to execute
;1	Argument 1 -- first argument to the function
;2	Argument 2 -- second argument
;
; ...entries below here used only for directive 12 and 13 ...
;3	nBandsM1 -- number of bands (-1) to generate
;		A band is 16. scan-lines
;4	FA -- first read address for output (left half-word)
;5	LoTable -- pointer to left-over table
;		Must be even; must be initialized with @LoTable=0
;6	FontTable -- pointer to table of font characters:
;		(ICC is a mnemonic for 'internal character code')
;		FontTable!(ICC+100000b) => Fdes (must be even)
;			Fdes!0=-Height (in bits)
;			Fdes!1=Width-1
;			Fdes!2,3,... bit map for character
;7	NewRp -- pointer to list of "new characters" :
;		NewRp!1 is first word and must be even
;		Each entry on NewRp is one of:
;		(a) A character (2 words).  First word is ICC+100000b
;			Second word is xInBand (bit 4), Y (bit 12.)
;			XY address is of lower left corner of box.
;		(b) A "rule" (4 words).  First word is 1.
;			Second word is xInBand (bit 4), Y (bit 12.) -- same
;			interpretation as for a character.
;			Third word is -Height (in bits). Fourth word is
;			Width-1.
;		(c) A band terminator (2 words, both =0) used to mean
;			that no more information is required for this band.
;
; ...these entries are filled in by the microcode with values ...
;8.	Result -- if a function returns a result, it is placed here
;9.	Status -- records latest Orbit status
;		Some "firmware status" bits are added to the normal Orbit status
;		word:
;			100000b	-- Orbit is "in a character segment" (IACS)
;			40000b -- Timeout in Slot band switch wait (Directive=14b)
;			20000B -- ROS status WORD unstable (Directive=16b)
;			10000B -- Microcode got behind and send video went away
;			4000B  -- Illegal "band code" in band file entry
;
; Idling.  When a function is finished execution, the microcode sets
; location 720b to zero, and will then idle in one of two ways:
;	(a) Normal.  The Orbit task is blocked entirely; there is no activity.
;		A StartIO(4) is required to resume processing.
;	(b) Refreshing.  The microcode goes "to sleep," but will awake to
;		refresh the Orbit memory (the buffer being written into)
;		periodically.  If, upon awakening, a non-zero value is detected
;		in location 720b, it goes off to execute the specified function.
;		Awakening may be hastened by executing StartIO(4)
; (a) is default; turn on 100000b bit in Directive to get (b)
;
;
; F U N C T I O N S
;
; Directive=0: OrbitControl ← argument 1
; Directive=1: result ← OrbitData
; Directive=2: OrbitHeight ← argument 1,
;		result ← (if RefreshingNeeded then -1 else 0)
; Directive=3: OrbitXY ← argument 1
; Directive=4: OrbitDBCWidth ← argument 1
; Directive=5: OrbitFont ← argument 1
; Directive=6: result ← OrbitDeltaWC
; Directive=7: OrbitInk ← argument 1
; Directive=10b: result ← OrbitDBCWidth
; Directive=11b: OrbitROSCommand ← argument 1
; Directive=12b: Read data words (OrbitData)
;		argument 1 = count of words to read
;		argument 2 = address to put first word
; Directive=13b: Shovel a character to Orbit
;		OrbitHeight ← argument 1
;		OrbitXY ← argument 2
;		OrbitDBCWidth ← nBandsM1
;		for i=0 to abs(LoTable)-1 do OrbitFont←FA!i
;			(use "tasking" loop if LoTable>0, else non-tasking)
;		result ← OrbitDBCWidth
;		NewRp ← OrbitDeltaWC
; Directive=14b: Process an entire page and send to Slot
;		argument 1 = pointer (even) to ROS command table.
;			ROS command table entries are 2 words each:
;				whenflag bit   -- 0 means do it at BandM1
;				                  1 means do it now
;				command bit 3	-- which command to do
;				BandM1 bit 12. -- do it when nBandsM1 matches this field
;				rosArgument bit 16. -- this is the argument
;			Commands:
;				0 -- Send rosArgument as a ROS command
;				1 -- spare
;				2 -- spare
;				3 -- Wait (used if 2 ROS commands needed in same band)
;		argument 2 = Timeout count, in number of refresh cycles
;		result ← updated NewRp (remember it's 1 below next char)
; Directive=15b: Process a single band and return
;		result ← updated NewRp (remember it's 1 below next char)
; Directive=16b: Read a single word of ROS status (argument 1
;		contains, in the left half, the first address of ROS memory
;		to look in).
;		result ← status word
;
;Orbit microcode
;
;Orbit -- task 1 (just below the emulator)
; PackMu SpruceMc.Mb SpruceMc.Br 177774 (less bits for any other tasks)
;
; Comment conventions:
;	**	Put on any instruction after which a TASK switch might happen
;	!a,b	Branching between locations a and b may occur
;	[a,b]	Same
;	//		Put on instructions inserted to make sure Alto clock does not
;			stop during execution of an Orbit function.
;
;
;Orbit definitions
;
$ORBITDWC	$L0, 070014, 100;	F1=14 Alto←Delta Word Count
$ORBITDBCWID	$L26010, 70015, 120100;	F1=15 Alto←Delta BC, Width (-1)
;					F2=10, Delta Bc, Width←Alto, Cinit
$ORBITDBCWIDx	$L16015, 0, 160000;	F1=15 (version that does not define BUS)
$ORBITXY	$L26011, 0, 120000;	F2=11, X,Y ← Alto
$ORBITHEIGHT	$L26012, 0, 120000;	F2=12, Height ← Alto !!!BRANCHES!!!
$ORBITFONT	$L26013, 0, 120000;	F2=13, Font data ← Alto
$ORBITINK	$L26014, 0, 120000;	F2=14, Ink data ← Alto
$ORBITCONTROL	$L26015, 0, 120000;	F2=15, Control, FA ← Alto
$ORBITROSCMD	$L26016, 0, 120000;	F2=16, Ros command ← Alto
$ORBITDATA	$L0, 70016, 100;	F1=16, Alto ← Output data
$ORBITSTATUS	$L0, 70017, 100;	F1=17, Alto ← Status !!!BRANCHES!!!
$ORBITSTATUSx	$L16017, 0, 160000;	F1=17 (version that does not define BUS)

$BUSUNDEF	$L0, 14002, 100;		Leaves BS=2 so bus is =-1
;

; Orbit Control bits:
$GOAWAY		$10;
$WHICH		$4;
$CLRFRESH	$2;
$CLRBEHIND	$20;
$SLOTTAKE	$300;		Includes "enable" bit
$STABLEROS	$40;
$600		$600;
$400		$400;
$4000		$4000;
$6000		$6000;
$10000		$10000;
$170000		$170000;

;; 27 December, 1977 -- reassign R71-R76 to R46-R53 -- avoids all Tricon conflicts

$DIRECTIVE	$R53;	was R76
$ARG1		$R52;
$ARG2		$R51;
$NBANDSM1	$R50;
$FA		$R47;
$LOTABLE	$R46; was R71
$FONTTABLE	$R70;
$NEWRP		$R67;
;; March 6, 1978 no longer used, removed due to TriCon name conflict $STATUS $R66;
$PROGRESULT	$R66; ; 8 March, 1978
$RET0		$R64;
$RET1		$R63;
$LORP		$R62;
$LOWP		$R61;
$ORBBL		$R60;
$XY		$R57;
$BEGFADR	$R56;
 $ICC		$R56;
$C720		$R55;
$Shit		$R54;

$LASTL		$R40;		Last value of L in RAM

$TEMP		$R17;			March 6, 1978 Was R14, switched to avoid TriCon conflict
$FONTADR	$R15;
$HEIGHT		$R16;
;
; ORBIT -- here to load state from the control block, and to
; dispatch on the directive.

; Global dispatch definitions:
!1,2,LOLOOP,NCHAR;		Return from TFRCHR
!1,2,BANDRET0,BANDRET1;		Return from DOBAND
!3,4,REFRET0,REFRET1,REFRET2,REFRET3;	Return from REFRESH
!17,20,DIR0,DIR1,DIR2,DIR3,DIR4,DIR5,DIR6,DIR7,DIR10,DIR11,DIR12,DIR13,DIR14,DIR15,DIR16,DIR17;

!1,2,ORBITX,ORREFA;

ORBIT:	T←16;
	L←736-T, TASK;
	C720←L;			**** Wait here on a block...
	MAR←C720;
	NOP;available
	L←MD, TASK;
	ORBBL←L;		** ORBBL points to our control block

; Pick up the directive, argument 1
ORBITX: MAR←ORBBL;
	L←ORBBL+1;
	ORBBL←L;
	L←MD;
	T←MD;
	DIRECTIVE←L, L←T, TASK;
	ARG1←L;		**

; Pick up argument 2, nBandsM1
	MAR←L←ORBBL+1;
	L←LASTL+1;
	ORBBL←L;
	L←MD;
	T←MD;
	ARG2←L, L←T, TASK;
	NBANDSM1←L;	**

; Pick up FA, LoTable
	MAR←L←ORBBL+1;
	L←LASTL+1;
	ORBBL←L;
	L←MD;
	T←MD;
	FA←L, L←T, TASK;
	LOTABLE←L;	**

; Pick up FontTable, NewRp
	MAR←L←ORBBL+1;
	L←LASTL+1;
	ORBBL←L;
	L←MD;
	T←MD;
	FONTTABLE←L, L←T, TASK;
	NEWRP←L;	**

; Dispatch to appropriate function
	T←17;
	L←DIRECTIVE AND T;
	SINK←LASTL, BUS, TASK;
	:DIR0;	**

; ORBITDONE/STORE -- here when done with a function. Zero location
; 720b, and idle.  Idle is normally BLOCK; but will sit in a loop
; refreshing if high order bit of directive is on.
;	ORBITSTORE -- returns what is in L as result
;	ORBITDONEX -- XOR's what is in L with status

!1,2,ORQUIET,ORREF;
!4,5,IACS,,,,NOIACS;

ORBITSTORE: PROGRESULT←L;
ORBITDONE:	L←0, TASK;
ORBITDONEX: ICC←L;	**
	L←ORBITSTATUS;
	T←100000, :IACS;
IACS:	L←LASTL XOR T;
NOIACS: T←ICC;
	MAR←ORBBL+1;
	L←LASTL XOR T;
	MD←PROGRESULT, TASK;
	MD←LASTL;	**

; Record done, store diagnostic Shit, quit or enter refresh loop
	MAR←C720;
	L←DIRECTIVE;
	MD←0;
	MD←Shit;
	SH<0, TASK;
	:ORQUIET;  **  [ORQUIET, ORREF]

; ORQUIET -- let Orbit be quiet between invocations.  Turn off
; the RUN flop with BLOCK, and wait for StartIO to get it going
; again.  Note that the block actually "takes" at the next TASK,
; just after ORBIT.

ORQUIET: BLOCK, :ORBIT;

; ORREF -- Orbit's idle loop will refresh if needed.  Whenever it wakes
; up and discovers a non-zero command block, it will resume execution.
; Issuing a StartIO at any time will simply hasten the wakeup.

ORREF:	ORBITCONTROL←GOAWAY;
	NOP, TASK;
REFRET3: NOP;	**	Wait for a good long time (2ms)
	MAR←C720;
	NOP;
	L←MD, BUS=0, TASK;
	ORBBL←L, :ORBITX;	** !ORBITX,ORREFA

ORREFA:	L←3, TASK, :REFRESH;	Return to REFRET3 on new wakeup
;
; Directive 0: Control ← argument 1
DIR0:	ORBITCONTROL←ARG1;
	NOP,	TASK;
	NOP, :ORBITDONE; **	-- Let us go away if GOAWAY was set in last instr

; Directive 1: argument ← Orbit data
DIR1:	L←ORBITDATA, :ORBITSTORE;

; Directive 2: Set Height, return -1 if refresh needed
!4,5,NONEEDREF,,,,NEEDREF;

DIR2:	ORBITHEIGHT←ARG1;
	L←0, :NONEEDREF;
NONEEDREF: :ORBITSTORE;
NEEDREF: L←ALLONES, :ORBITSTORE;

; Directive 3: Set XY ← argument 1
DIR3:	ORBITXY←ARG1, :ORBITDONE;

; Directive 4: Set delta BC, Width ← argument 1
DIR4:	ORBITDBCWID←ARG1, :ORBITDONE;

; Directive 5: Ship font data ← argument 1
DIR5:	ORBITFONT←ARG1, TASK;
	NOP, :ORBITDONE; **  In case FIFO full....

; Directive 6: Read delta WC
DIR6:	L←ORBITDWC, :ORBITSTORE;

; Directive 7: Set ink data ← argument 1
DIR7:	ORBITINK←ARG1, :ORBITDONE;

; Directive 10b: Read delta BC, Width
DIR10:	L←ORBITDBCWID, :ORBITSTORE;

; Directive 11b: ROS command ← argument 1
DIR11:	ORBITROSCMD←ARG1, :ORBITDONE;

; Directive 12b: Read orbitdata words.  First argument is count
; Second argument is address


DIR12:	L←ARG2-1, TASK;
	TEMP←L;	** Temp=beginning core address-1
	T←TEMP;
	L←ARG1+T, TASK;
	ARG1←L;	**		ARG=last address

; 6 instructions in the loop to allow Orbit memory adequate time.
; Orbit really needs only 4 instructions
; per ORBITDATA function.

!1,2,F12CONT,F12DON;
F12CONT: MAR←L←TEMP+1, T←TEMP;
	TEMP←L;
	L←ARG1-T;
	MD←ORBITDATA;
	SH=0, TASK;
	:F12CONT; ** [F12CONT,F12DON]

F12DON:	NOP, :ORBITDONE; **

; Directive 13b: Load Height, XY, then DBCWID, shovel
; a number of words at the interface, then read delta WC
;	Argument 1: Height
;	Argument 2: XY
;	NBANDSM1: Width
;	FA: pointer to data vector
;	LOTABLE: count (may be positive or negative -- see below)

!4,1,KILLHEIGHT13;
!1,2,CONTLOP,DONLOP;
!1,2,CONTLOPT,DONLOPT;
!1,2,LOPTA, LOPNA;

DIR13:	ORBITHEIGHT←ARG1;
	ORBITXY←ARG2, :KILLHEIGHT13;
KILLHEIGHT13:	ORBITDBCWID←NBANDSM1;
	L←T←LOTABLE;
	L←FA-1, SH<0;
	FA←L, L←T, :LOPTA;		!LOPTA,LOPNA
	
; Two versions of this loop. First one does not task, so logic
; analyzer can be used on small loops.
; Second one tasks so can be used on large characters.
; Count<0 selects non-tasking loop.

CONTLOP: FA←L;
	L←LOTABLE+1;
	NOP;		///////////////////////;
	ORBITFONT←MD;
LOPNA: LOTABLE←L, SH=0;
	MAR←L←FA+1, :CONTLOP;		**DONT DO A TASK**

CONTLOPT: MAR←L←FA+1;
	FA←L;
	L←LOTABLE-1;
	NOP;		///////////////////////
	ORBITFONT←MD;
LOPTA:	LOTABLE←L, SH=0, TASK;
	NOP, :CONTLOPT;		**DO A TASK**


!1,2,WAITLOP,WAITDONE;
DONLOPT: L←100, :WAITLOP0;
DONLOP: L←100;
WAITLOP0: TEMP←L, :WAITLOP;	**
WAITLOP: L←TEMP-1, BUS=0, TASK, :WAITLOP0;

; The following is a non-standard way of storing a result
; (it comes back in the word of the control table occupied by
; NewRp)
WAITDONE: MAR←ORBBL;
	NOP, TASK;
	MD←ORBITDWC;	**
	L←ORBITDBCWID, :ORBITSTORE;

; Directive 15b: Do one band

DIR15:	L←0+1, TASK, :DOBAND;
BANDRET1: :ORBITDONE;

; Directive 16b: Read one word of ROS Status

!1,2,WDSTLP,WDSTDN;
!1,2,MSH1,MSH2;
!1,2,MSHGOOD,MSHBAD;
!4,1,MSHKILL;
!4,1,MSHKILL1;
!4,1,MSHKILL2;

DIR16:	L←ORBITSTATUS;
	FA←L, :MSHKILL1;		Remember StableROS bit
MSHKILL1: L←3, TASK, :MSH3;

WDSTLP:	L←3, :MSH0;
MSH1:	L←TEMP, TASK;
	TEMP ← L LSH 1;	**
	L←ICC-1, BUS=0;
MSH0:	ICC←L, :MSH1;
MSH2:	T←400;
	L←ORBITCONTROL←ARG1+T;	L←ARG1+T, ORBITCONTROL←ARG1
	ARG1←L;
	T←17;
	T←ORBITSTATUS.T;		Branches
	L←TEMP + T, TASK, :MSHKILL;
MSHKILL: TEMP←L;	**
	L←XY-1, BUS=0, TASK;
MSH3:	XY←L, :WDSTLP;	**

WDSTDN:	T←FA;
	T←ORBITSTATUS.T;
	L←STABLEROS AND T, :MSHKILL2;
MSHKILL2:	L←TEMP, SH=0;
	PROGRESULT←L, :MSHGOOD;
MSHGOOD:	:ORBITDONE;
MSHBAD:	T←20000, :ORBITDONEX;
;
; Directive = 17b: Spare
;
DIR17:	:ORBITDONE;
;
; Slot Printing loop (directive=14b)
; Register values on entering:
;	FA -- first read address in band
;	NBANDSM1 -- NumberOfBands-1
;	ARG1 -- pointer to ROS command table of pairs (x, cmd)
;		where x=(i,op,b)  i=bit0, op=bits1-3, b=bits4-15 and
;			i=0 if op is to be done when NBANDSM1=b
;			  1 if op is to be done immediately
;			op=0 if cmd is to be sent to ROS, 1 if status is to be read
;				and 3 to wait
;			 b=band number (first one to be executed is NBANDSM1,
;		and so on decreasing to 0).
;	ARG2 -- timeout count down
;	+ see subrs
; Uses: RET0
; Calls: REFRESH, DOBAND

!4,1,NXROS;		Make sure NXROS will kill ORBITSTATUS branch
!1,2,SVBND,DIR14DN;
!1,2,IMMEDIATE,CHECKBAND;
!1,2,NOROS,GIVEROS;
!1,2,NOTIMEOUT,TIMEOUT;
!4,5,NXBAND,,,,REFRSH2;

DIR14:	ORBITCONTROL←SLOTTAKE;
	T←WHICH;		Set FA properly.
	L←FA+T, TASK;
	ORBITCONTROL←LASTL; **
	L←NBANDSM1+1;
	PROGRESULT←L;	Would never otherwise be set to this value

; Ship out ROS commands in the command table.

NXROS:	MAR←ARG1;		Look for ROS command
	T←NBANDSM1;
	T←40000 OR T;
	T←30000 OR T;
	L←MD-T;      L will be negative only if MD is positive
	T←7777;
	L←LASTL AND T, SH<0;
	:IMMEDIATE, SH=0, TASK;        !IMMEDIATE,CHECKBAND
CHECKBAND: :NOROS;	** !NOROS,GIVEROS
IMMEDIATE:  :GIVEROS;        **

NOROS:	L←0, TASK, :DOBAND;	Go do most of the work.

; Return from band processing

BANDRET0: ORBITCONTROL←GOAWAY;
	L←ARG2, TASK;
	ICC←L;	**		Wait a long time here (2 ms)

; Quit early if BEHIND and SendVideo is gone, store Orbit status every band

!1,2, SGOAWAY, PGABORT;
!4,1, BRSTATKILL;
!5,2, BRHOLDKILL, BRHOLDSTORE;

REFRET2: ORBITCONTROL←0	;	Read SendVideo
	T←2;				Store status
	MAR←ORBBL+T;
	L←ORBITSTATUS;		Branches!
	MD←LASTL, :BRSTATKILL; !BRSTATKILL, BRSTATKILL
BRSTATKILL: T←30;		10-7-77 DCS !!!
	L←LASTL AND T;
	T←20;
	L←LASTL-T;			10-3-77 DCS
	SH=0, TASK;			Quit if behind and SendVideo gone
	:SGOAWAY;			! SGOAWAY, PGABORT  **
PGABORT: L←10000, TASK, :ORBITDONEX; Quit

; Save band number whenever word 8, bit 3 of status is on (Dover Count-H)

SGOAWAY: ORBITCONTROL←20000;Read word 8, first nybble [0-3] of status
	NOP			;//////Must wait two cycles before getting results
	L←0+1;			;For ANDing with ORBITSTATUS on next cycle
	ORBITSTATUSx, SINK←LASTL, BUS; Branches! (Next[7] due to hardware, Next[9] if count-H)
	L←NBANDSM1, :BRHOLDKILL; !BRHOLDKILL, BRHOLDSTORE; which band if count-H on
BRHOLDSTORE: PROGRESULT←L;
BRHOLDKILL: ORBITHEIGHT←0; Branches!! check to see if refresh needed
	:NXBAND;		!NXBAND,REFRSH2

REFRSH2: L←ICC-1, BUS=0;
	ICC←L, :NOTIMEOUT;	!NOTIMEOUT,TIMEOUT
NOTIMEOUT: L←2, TASK, :REFRESH;	Return to REFRET2 on new wakeup

; Time to begin generating a new band.

NXBAND: L←NBANDSM1-1, BUS=0, TASK;
	NBANDSM1←L, :SVBND;	**
SVBND:	T←4;
	MAR←ORBBL-T;		Update the command block to show progress
	TASK;
	MD←NBANDSM1, :NXROS;	**

TIMEOUT: L←40000, TASK, :ORBITDONEX;
DIR14DN: :ORBITDONE;
;
; Dispatch on ROS command table entry (high 4 bits)

%360,360,0,ROS0,ROS1,ROS2,ROS3;

GIVEROS: MAR←ARG1;
	T←2;
	L←ARG1+T;
	ARG1←L;
	T←30000;
	L←MD AND T;
	TEMP← L LCY 8;
	L←MD, TASK;
	RET0←L;	**
	SINK←TEMP, BUS, TASK;
	:ROS0;

; Op code 0: send a 16-bit ROS command
ROS0:	ORBITROSCMD←RET0, :NXROS;

; Op code 1: read status
ROS1:	ORBITCONTROL←RET0;
	MAR←ARG1-1;
	NOP;
	MD←ORBITSTATUS;	Warning--may or 4 into NEXT
	:NXROS;

; Op code 2: spare
ROS2:	:NXROS;

; Op code 3: wait in a loop -- argument tells how long.
ROS3:	NOP;
!1,2,ROS3A,ROS3B;
ROS3A:	L←RET0-1, BUS=0, TASK;
	RET0←L, :ROS3A;	**
ROS3B:	:NXROS;
;
;DOBAND -- enter here to process a band.
;	L = index of return (BANDRET0,BANDRET1)
;	NEWRP => next new character -1
;	LOTABLE => left-over table (@LOTABLE=0 at the very first)
;	FONTTABLE => ICC table (-#100000)
; Uses RET1,LORP,LOWP,FONTADR,HEIGHT,XY,ICC
; Calls REFRESH, TFRCHR

DOBAND:	RET1←L;	**
	L←LOTABLE-1;
	LORP←L, TASK;
	LOWP←L;	**

; Process left-overs
!4,5,NOREFRSH0,,,,REFRSH0;
!1,2,LOLOOPA,NOLOV;

LOLOOP:	MAR←L←LORP+1;
	L←LASTL+1;
	LORP←L;
	NOP;		///////////////////////
	L←ORBITHEIGHT←MD;	ORBITHEIGHT branches!!
	HEIGHT←L, SH=0, :NOREFRSH0;
NOREFRSH0: L←ORBITXY←MD, TASK, :LOLOOPA;

LOLOOPA: XY←L;	**
	MAR←L←LORP+1;
	L←LASTL+1;
	LORP←L;
	NOP;		///////////////////////
	ORBITDBCWID←MD;
	L←MD;
	FONTADR←L, L←0, TASK, :TFRCHR;	L=0 => return to LOLOOP

; Come to REFRSH0 to refresh when in the left-over
; loop.  Backs up the LORP pointer and returns to LOLOOP.
!1,1,REFRSH0A;	Kill SH=0 coming from above
REFRSH0: T←2, :REFRSH0A;
REFRSH0A: L←LORP-T, TASK;		Back up the read pointer
	LORP←L;	**
	L←0, TASK, :REFRESH;
REFRET0: :LOLOOP;

; Come to NCHAR when finished with left-over table (terminating
; 0 encountered).

; Process "new characters" from the main list.

!4,5,NOREFRSH1,,,,REFRSH1;
!1,2,NOTCHAR,REGCHAR;
!1,2,DOBR, NOBR;
; Band command dispatch, for all but characters
!37,40, ENDBAND, REGRULE, TRP2, TRP3, BRANCH, TRP5, TRP6, TRP7;

NOBR:		NOP, :NCHAR; **		Branch command did not perform a "branch"
NOLOV:	NOP;	**
NCHAR:	MAR←L←NEWRP+1;
	L←LASTL+1;
	NEWRP←L;
	L←T←MD;				T←cmd, L←cmd for test
	L←MD, SH<0;				L←XY
	XY←L, :NOTCHAR;			to REGCHAR if char

REGCHAR: MAR←FONTTABLE+T;
	ORBITXY ← XY;
	NOP;
	L←MD+1, TASK;
	FONTADR←L;	**
	MAR←FONTADR-1;
	L←FONTADR+1;
	NOP;		///////////////////////
GETHW:	FONTADR←L;
	ORBITHEIGHT←L←MD;	Branches on NEXT[7] !!
	HEIGHT←L, L←0+1, :NOREFRSH1;

NOREFRSH1: ORBITDBCWID←MD, TASK, :TFRCHR;	L=1 => return to NCHAR

!4,1,KILLHEIGHT0;

REFRSH1: L←MD, TASK;
	ICC←L;		** Save DBCWID
	L←0+1, :REFRESH;
REFRET1: ORBITHEIGHT←HEIGHT;	Branches!!
	ORBITXY←XY, :KILLHEIGHT0;
KILLHEIGHT0: ORBITDBCWID←ICC;
	L←0+1, TASK, :TFRCHR;

; If not a character, dispatch

; T = cmd, XY = cmd word 2
NOTCHAR: L←7 AND T;
	SINK ← LASTL, L←T, BUS, TASK;	Dispatch on cmd[11-15]
	ICC ← L, :ENDBAND;	** ICC ← cmd ! ENDBAND, REGRULE, , , BRANCH,...

; We have an "end band" signal in the new character list.

ENDBAND: MAR←LOWP+1;		Terminate the left over list
	SINK←RET1, BUS, TASK;
	MD←0, :BANDRET0;

; Do a rule.
REGRULE: MAR←L←NEWRP+1;
	L←LASTL+1;
	NEWRP←L;
	ORBITXY ← XY;
	L←0, :GETHW;

; If <function table>!10 ne cmd, "branch" to <current band loc> + cmd word 2

BRANCH: T←3;
	MAR←ORBBL+T;				function table!10
	T←ICC;					command word
	L←MD-T;
	T←XY, SH=0;					T←"branch" increment
	L←NEWRP+T, TASK, :DOBR;		"branch" if not equal ! DOBR, NOBR

DOBR: NEWRP ← L, :NOLOV; **			implement the "branch"

; Catch illegal band entries, or microprocessor problems

TRP2: L←NEWRP, :BANDTRAP;
TRP3: L←NEWRP, :BANDTRAP;
TRP5: L←NEWRP, :BANDTRAP;
TRP6: L←NEWRP, :BANDTRAP;
TRP7: L←NEWRP, :BANDTRAP;

; 721 ← band entry address
; Return with firmware status #4000

BANDTRAP: Shit←L;
	L←4000, :ORBITDONEX;
;
; TFRCHR -- Transfer a character part to the Orbit.
;
; Register values on entering (*** means already passed to Orbit):
;	L -- "return" address (0=>LOLOOP; 1=>NCHAR)
;	XY -- xy position in Orbit format (ORBITXY)  ***
;	HEIGHT -- height in Orbit format (ORBITHEIGHT) ***
;	FONTADR -- pointer to first data word of the font character
;		If FONTADR=0, it will be a "rule" instead
;	(bc,width) -- has already been given to Orbit (ORBITDBCWID←) ***
;	LOWP -- write pointer into left overs
; Uses RET0, BEGFADR
;
!7,10,FONTODD,FONTEVEN,,,FONTDONE,,,;
!1,2,FONTLA,FONTRULE;
!1,2,FONTLO,FONTDN;
!4,5,FONTRULEC,,,,FONTRULED;

TFRCHR:	RET0←L;	**	Save return address
	MAR←T←FONTADR, BUS=0;
	L←ONE AND T, :FONTLA;	Check to see if first address odd or even
FONTLA:	L←FONTADR+1, SH=0;
	BEGFADR←L, :FONTODD;

FONTLP:	MAR←L←FONTADR+1;
	NOP;		///////////////////////
	L←LASTL+1;
FONTEVEN: ORBITSTATUSx, FONTADR←L;	Branches!! check to see if done
	ORBITFONT←MD, TASK, :FONTODD;
FONTODD: ORBITFONT←MD, :FONTLP;	**

; Come here to put out a "rule" -- just give Orbit all -1's
; as font bits.
FONTRULE: ORBITSTATUSx;	Check to see if finished
	ORBITFONT←BUSUNDEF, TASK, :FONTRULEC;
FONTRULEC: ORBITFONT←BUSUNDEF, :FONTRULE;	**

; Now undo the effect on bumping the Font Address

FONTRULED: NOP;**
	T←ORBITDWC;
	L←ONE-T, TASK;
	BEGFADR←L, :FONTDNX;	**

FONTDONE: NOP;	**
FONTDNX: T←7777, ORBITDBCWIDx;	Read remaining width
	L←7777-T;
	T←ORBITDWC-1;
	L←BEGFADR+T, SH=0, TASK;
	FONTADR←L, :FONTLO;	**

; Left over to record. Format:
;		word 0: height
;		word 1: y (x=0)
;		word 2: dbc,width
;		word 3: font address

FONTLO: T←7777;
	L←XY AND T, TASK;
	BEGFADR←L;	**

	MAR←L←LOWP+1;
	L←LASTL+1;
	MD←HEIGHT;
	MD←BEGFADR, TASK;
	LOWP←L;	**

	MAR←L←LOWP+1;
	L←LASTL+1;
	MD←ORBITDBCWID;
	MD←FONTADR, TASK;
	LOWP←L;	**

FONTDN:	SINK←RET0, BUS, TASK;
	:LOLOOP;	**
;
; REFRESH -- the place that all refreshing is done (for now)
; Requires about 35*3+7 = 112 microcycles
; Register values on entering:
;	L -- return index
; Uses RET0, TEMP(R) -- but doesn't change it

; Note that a good deal of Orbit state is destroyed.
; Calculation of number of times through loop:
;	let n=number to store in L at beginning. (n+1)*2=64.+6.
;	6 is to leave enough in the FIFO.

!4,5,REFLPA,,,,REFLPD;
!4,1,REFLP;		Kill height branch

REFRESH: RET0←L;	**
	ORBITXY←0;
	ORBITHEIGHT←6000;	Branches!! 1024. bits = 64. words
	ORBITDBCWID←0, :REFLP;
REFLP:	L←TEMP, ORBITSTATUSx;	Branches!! check to see if done.
	ORBITFONT←0, TEMP←L, TASK, :REFLPA; TEMP←L just to hold BUS=0
REFLPA:	ORBITFONT←0, :REFLP;	**

; Note about the exit code.  If GOAWAY is set, the REFRESH subroutine
; does not return until a new wakeup is generated (either by
; another refresh request or by someone clearing GOAWAY: StartIO
; or buffer-switch).

REFLPD:	ORBITCONTROL←CLRFRESH;	**
	SINK←RET0, BUS, TASK;
	:REFRET0;	**		Usually hangs up here if no wakeup

; Excerpts from version created in 4-78 for Alto II XMs, assuming memory data available
;; only in instructions 5 and 6 of a memory cycle
;GIVEROS: MAR←ARG1;
;	T←2;
;	L←ARG1+T;
;	ARG1←L;
;	T←MD;
;	L←MD;
;	RET0←L;
;	L←30000 AND T, TASK;
;	TEMP←L LCY 8; **
;	SINK←TEMP, BUS, TASK;
;	:ROS0; [ ROS0, ROS1, ROS2, ROS3 ]

;	L←ORBITHEIGHT←MD;	ORBITHEIGHT branches!!
;	T←ORBITXY←MD, :NOREFRSH0; [ NOREFRSH0, REFRSH0 ]
;NOREFRSH0:
;	HEIGHT←L, L←T, SH=0, TASK; ~~ WOW!
;	XY←L, :LOLOOPA; ** [ LOLOOPA, NOLOV ]
;LOLOOPA:
;	MAR←L←LORP+1;
;	L←LASTL+1;
;	LORP←L;
;	NOP;		///////////////////////
;	ORBITDBCWID←MD;
;	L←MD;
;	FONTADR←L, L←0, TASK, :TFRCHR;	L=0 => return to LOLOOP
;; Come to REFRSH0 to refresh when in the left-over
;; loop.  Backs up the LORP pointer and returns to LOLOOP.
;REFRSH0: T←2, :REFRSH0A;
;REFRSH0A: L←LORP-T, TASK;		Back up the read pointer
;	LORP←L;	**

;NOLOV:	MAR←L←NEWRP+1, :NCHAR1 ; ~~ XM: End of LO List -- avoid too-long chain
;NCHAR:	MAR←L←NEWRP+1;
;NCHAR1:	L←LASTL+1;
;	NEWRP←L;
;	L←T←MD;				T←cmd, L←cmd for test
;	L←MD, SH<0;				L←XY (don't TASK here! T is in use!)
;	XY←L, :NOTCHAR; 			[ NOTCHAR, REGCHAR ]
;REGCHAR: MAR←FONTTABLE+T;
;	ORBITXY ← XY;
;	L←MD+1;
;	MAR←LASTL-1;
;	L←LASTL+1;
;	NOP;		////////////////////////
;GETHW:
;	FONTADR←L;
;	ORBITHEIGHT←L←MD;	Branches on NEXT[7] !!
;	T←MD, :NOREFRSH1; [ NOREFRSH1, REFRSH1 ]
;NOREFRSH1:
;	HEIGHT←L, L←T, TASK;  XM: Timing is very tight. Next instr. is 20th cycle without TASK
;	ORBITDBCWID ← LASTL; **
;	L←0+1, TASK, :TFRCHR;
;!4,1,KILLHEIGHT0;
;REFRSH1: HEIGHT←L, L←T, TASK;
;	ICC←L;		** Save DBCWID
;	L←0+1, :REFRESH;

;REGRULE:
;	ORBITXY ← XY;
;	L←NEWRP+1;
;	L←LASTL+1;
;	MAR←LASTL-1; Carefully placed with respect to double word fetch at GETHW
;	NEWRP←L;
;	L←0, :GETHW;

;!4,5,FONTODD,,,,FONTDONE;
;!1,2,FONTLA,FONTRULE;
;!1,2,FIRSTODD, FONTEVEN;
;!1,2,FONTLO,FONTDN;
;!4,5,FONTRULEC,,,,FONTRULED;
;TFRCHR:
;	RET0←L;	**	Save return address
;	T←FONTADR, BUS=0;
;	L←ONE AND T, :FONTLA;	Check to see if first address odd or even
;FONTLA:
;	MAR←T;	Carefully placed with respect to double word fetch at FONTEVEN
;	L←FONTADR+1, SH=0;
;	BEGFADR←L, :FIRSTODD;  [ FIRSTODD, FONTEVEN ]
;FIRSTODD: NOP, :FONTODD; /////////////// Dammit! ///////////////
;FONTLP:
;	MAR←L←FONTADR+1;
;	NOP;		///////////////////////
;	L←LASTL+1;
;FONTEVEN:
;	ORBITSTATUSx, FONTADR←L;	Branches!! check to see if done
;	ORBITFONT←MD, TASK, :FONTODD;
;FONTODD: ORBITFONT←MD, :FONTLP;	**
;

;; DCS, September 24, 1977  4:56 PM, add Behind-abort, BRANCH band command
;; October 3, 1977  9:33 PM, repair behind-abort (wrong test, wrong status bit)
;; October 6, 1977  5:04 PM, per RFS suggestion, move behind-abort test to rfrsh loop
;; October 7, 1977  11:59 PM, SendVideo is 10, not 4!!!!! (behind-abort)
;; October 16, 1977  3:57 PM, Add bad band code traps, 4000 firmware bit
;; December 27, 1977  2:21 PM, Reassign R71-R76 to get out of Tricon's way
;; March 6, 1978  4:35 PM, revived as component fetched from SpruceMc.Mu
;;   (had been copied in for a while)
;; March 8, 1978  8:56 AM, Left out dispatch constraint specs in latest reorganization
;; March 8, 1978  4:58 PM, store last band in which Count-H (Dover word 8, bit 3) was
;;	seen in command table result word to Program Result (FUNC!8)
;; March 16, 1978  12:06 AM, was TASKing instead of TISKing, causing random branch
;;	into display task -- oh, ugh!
;; March 26, 1978  10:11 PM, count-H fix -- wait two cycles (one necessary, one sometimes)
;; May 9, 1978  9:28 AM, add XM fix comments
;; October 17, 1978 2:46 PM, add immediate command-forwarding to fslot. BWB
;; October 17, 1978  4:51 PM, bum some code (remove high order trap vector, bum a few)
;;