; IfsBcplUtil.Mu  --  Ifs Bcpl runtime utilities (except GetFrame and Return)
; Copyright Xerox Corporation 1979, 1980, 1981

; Last modified May 3, 1981  3:18 PM by Taft

; Last modified by Taft, March 3, 1980  11:16 AM
; - add ObjCall, STA3JSRI instructions
; Last modified by Wobber, February 20, 1980  12:20 PM
; - renamed NOINT to NOINTR to resolve name conflict
; Last modified by Butterfield, February 20, 1980  9:21 PM
; - use runtime dispatch #77 for REGJSR - 2/20/80
; - remove String and NewFrame and move XFrame - 11/29
; - make NewFrame be XFrame - 10/29
; - have jsr .+ go to String - 10/29
; - add Xjmp0-3, XReturn, NewFrame, XFrame, and String - 8/20
; - add extended emulator: don't PREDEF NOVEM, and START, RAMCYCX, and TRAP1;
;   change SHIFT; and delete RAMRET, TORAM, and TRAP1 label - 8/20
; - return to START or StartX depending on call - 8/15
; - use XMAR for PC related fetches - 8/15
; - use XBcplUtility, trap BcplUtility - 8/2
; - reorder the uCalls - 8/1/79

; Derived from BcplUtil.mu:
; Last modified October 16, 1977  6:38 PM


; All Bcpl runtime utilities in this module are invoked by an opcode
; of the form XXnnn, where XX is the opcode for the main dispatch in RamTrap
; and nnn is the DISP field used for sub-dispatching here.

!377,100,Lq0.6, Lq1.6, Lq0.5, Lq1.5, Lq0.4, Lq1.4, Lq0.3, Lq1.3,
	 Lq0.2, Lq1.2, Lq0.1, Lq1.1,      , Sq0.7, Sq1.7, Sq0.6,
	 Sq1.6, Sq0.5, Sq1.5, Sq0.4, Sq1.4, Sq0.3, Sq1.3, Sq0.2,
	 Sq1.2, Sq0.1, Sq1.1,      , Xjmp0, Xjmp1, Xjmp2, Xjmp3,
	   Ior,   Xor,   Eqv,  Mult,DivRem,   Rem,   Lsh,   Rsh,
	Branch,Lookup,      ,Finish, Abort,LongJump,    ,MulPlus,
	  Snq0,  Snq1,  Ly01,  Ly10,  Sy01,  Sy10,XReturn,     ,
	XFrame,      ,      ,      ,      ,      ,      ,REGJSR;


; RamTrap dispatches to BcplUtility and XBcplUtility

; **********
; For debugging: trap if XBcplUtility executed in XM
; !1,2, NonZeroBankReg, ZeroBankReg;

; XBcplUtility:
; 	MAR ← 177740;  Make sure the emulator bank register is zero
; 	T← 17;
; 	L← MD AND T;
; 	SH=0;
; 	:NonZeroBankReg;  [NonZeroBankReg, ZeroBankReg]
; NonZeroBankReg: :TRAP1X;
; ZeroBankReg:
; **********

XBcplUtility:
	SINK←DISP, BUS, TASK;		Branch on sub-code
	:Lq0.6;

BcplUtility: :TRAP1X;  trap any old callers

; LongJump
; Jumps to AC3 + @AC3
; Calling sequence is:
;	jsr @355
;	 target-. (i.e., a self-relative pointer)

LongJump:
	XMAR←T←AC3;
LongJ1:	NOP;
	L←MD+T, TASK;

; Some useful exit sequences

%300,321,21, Start2,,,MultDnX;	(binary xx00x1xxx1 and xx11x1xxx1)
!11,2, Start3,StartX;		(even and an odd with 10 bit on)

; These exits can be used only by BcplUtility routines.
; If the BcplUtility routine was called by a BcplUtil trap opcode
; (from bank 0) then IDISP ors 10 into NEXT.
; If it was called by a page 0 JSR caught by the extended emulator
; then IDISP ors 1 into NEXT.
Start0:	PC←L;			Branch here having done L← new PC;
Start1:	L←PC, IDISP, TASK;

; Here after executing L← new PC, TASK.
; If a NEXT[9] branch is pending then return to extended emulator
; else return to standard emulator.
Start2:	PC←L, :Start3;		[Start3, StartX]

Start3:	SWMODE, :START;		returning to ROM0
; Note: instruction at START in RAM itself branches to START.

; Branch
; Calling sequence is:
;	lda 0 switchon value
;	jsr @350
;	 value of last case
;	 number of cases
;	 lastTarget-.
;	 ...
;	 firstTarget-.
;	return here if out of range, AC0 unchanged

!1,2, Bran0, Bran1;
!1,2, Bran2, Bran3;

Branch:	XMAR←T←AC3;		Fetch value of last case
	L←2+T;
	AC3←L;			AC3← address of first branch table entry
	T←AC0;			Value we are branching on
	L←MD-T;			L← lastCase-value, carry← lastCase ge value
	XMAR←T←AC3-1;		Fetch number of cases
	T←LREG, L←LREG+T, ALUCY;  T← lastCase-value, L← AC3+(lastCase-value)-1
	SAD←L, :Bran0;	[Bran0, Bran1]  Save address-1 of branch table entry

; Value greater than last case, take out of range exit.
Bran0:	L←T←MD, :Bran1a; 	Finish fetch of numCases, turn off ALUCY

; Value le last case, test number of cases
Bran1:	L←MD-T-1, T←MD;		L← numCases-(lastCase-value)-1, T← numCases
Bran1a:	L←AC3+T, ALUCY, TASK;	Carry if numCases gr (lastCase-value)
	AC3←L, :Bran2;		[Bran2, Bran3] Adr of inst after branch table

; Value in range, execute branch.
; SAD/ address-1 of branch table entry
Bran3:	XMAR←T←SAD+1, :LongJ1;	Just like LongJump

; Value less than first case, take out of range exit.
Bran2:	L←AC3, IDISP, :Start2;

; Lookup
; Calling sequence is:
;	lda 0 switchon value
;	jsr @351
;	 number of cases
;	 case value 1
;	 target1-.
;	 ...
;	 case value n
;	 targetn-.
;	return here if out of range

!1,2, Look0, Look1;
!1,2, Look2, Look3;

Lookup:	XMAR←T←AC3;		Fetch number of cases
	NOP;
	L←MD+T, T←MD;		L← AC3+numCases, T← numCases
	L←LREG+T+1, TASK;	L← AC3+(2*numCases)+1
	AC1←L;			Save for end test

Look0:	XMAR←T←AC3+1;		Increment pointer, fetch next case value
	L←AC1-T;		Test for end
	T←AC0, L←T, SH=0;	T← switchon value
	AC3←L, :Look2;		[Look2, Look3]
Look2:	L←MD-T;			Compare switchon value with case
	L←AC3+1, SH=0, TASK;	Increment pointer again
	AC3←L, :Look0;		[Look0, Look1]

; Found matching case value.  AC3/ address of dispatch for case.
Look1:	XMAR←T←AC3, :LongJ1;	Just like LongJump

; Lookup failed.  AC3/ adr of inst after lookup table
Look3:	L←AC3, TASK, :Start0;

; Right shift
; Computes ac0 ← ac0 rshift ac1
; Called by jsr @347
; Note that shift count may be either positive or negative

!1,2, RshPos, RshNeg;
!1,2, RshG16, RshL16;
!1,2, RshG8, RshL8;
!17,10, Rsh0, Rsh1, Rsh2, Rsh3, Rsh4, Rsh5, Rsh6, Rsh7;  Use the last 10 of 20
!1,1, RshN1;
!1,1, LtoAC0;

Rsh:	L←T←AC1;		Shift count negative?
	L←17-T, SH<0;		16 or greater?
	L←10 AND T, ALUCY, :RshPos; [RshPos, RshNeg] 8 or greater?
RshPos:	L←7 AND T, SH=0, :RshG16; [RshG16, RshL16] Compute count mod 8
RshL16:	T←177400, :RshG8;	[RshG8, RshL8]

; Shift count in range 8 to 15.  Start by right-shifting 8
RshG8:	L←AC0.T;
	AC0←L LCY 8;  RshL8 can do the rest since Rsh0-7 are !17,10

; Shift count less than 8.  Branch on shift count (mod 16)
RshL8:	SINK←AC1, BUS;
	L←AC0, :Rsh0;

; This shift table is also used in the Lq0.n series of instructions
Rsh7:	AC0←L RSH 1;
Lq0.6:	L←AC0, TASK;
Rsh6:	AC0←L RSH 1;
Lq0.5:	L←AC0, TASK;
Rsh5:	AC0←L RSH 1;
Lq0.4:	L←AC0, TASK;
Rsh4:	AC0←L RSH 1;
Lq0.3:	L←AC0, TASK;
Rsh3:	AC0←L RSH 1;
Lq0.2:	L←AC0, TASK;
Rsh2:	AC0←L RSH 1;
Lq0.1:	L←AC0, TASK;
Rsh1:	AC0←L RSH 1, :Bran2;	Do PC←AC3 and go to START or StartX

; Shift count 0, do nothing
Rsh0:	L←AC3, IDISP, :Start2;	Do PC←L and go to START or StartX

; Shift count 16 or greater, return zero
RshG16:	L←0, TASK, :LtoAC0;	[LtoAC0, LtoAC0]  (Rsh1 instead of LtoAC0?)
LtoAC0:	AC0←L, :Bran2;		Do PC←AC3 and go to START or StartX

; Shift count negative.  Convert to Left Shift
RshNeg:	L←0-T, TASK;		[RshN1, RshN1] Negate shift count
RshN1:	AC1←L, :Lsh;

; Right shift constant amount
; Computes ac0 ← ac0 rshift n (n in range 1 to 7)
; Calling sequence is:
;	lda 0 value
;	jsr 314 - 2*n
; (dispatches into Lq0.n table, above)


; Right shift constant amount
; Computes ac1 ← ac1 rshift n (n in range 1 to 7)
; Calling sequence is:
;	lda 1 value
;	jsr 315 - 2*n

Lq1.6:	L←AC1;
	AC1←L RSH 1;
Lq1.5:	L←AC1;
	AC1←L RSH 1;
Lq1.4:	L←AC1;
	AC1←L RSH 1;
Lq1.3:	L←AC1;
	AC1←L RSH 1;
Lq1.2:	L←AC1;
	AC1←L RSH 1;
Lq1.1:	L←AC1, TASK;
	AC1←L RSH 1, :Bran2;	Do PC←AC3 and go to START or StartX

; Left shift
; Computes ac0 ← ac0 lshift ac1
; called by jsr @346
; Note that shift count may be either positive or negative

!1,2, LshPos, LshNeg;
!1,2, LshG16, LshL16;
!1,2, LshG8, LshL8;
!7,10, Lsh0, Lsh1, Lsh2, Lsh3, Lsh4, Lsh5, Lsh6, Lsh7;
!1,1, LshN1;

Lsh:	L←T←AC1;		Shift count negative?
	L←17-T, SH<0;		16 or greater?
	L←10 AND T, ALUCY, :LshPos; [LshPos, LshNeg] 8 or greater?
LshPos:	L←7 AND T, SH=0, :LshG16; [LshG16, LshL16] Compute count mod 8
LshL16:	T←377, :LshG8;		[LshG8, LshL8]

; Shift count in range 8 to 15.  Start by left-shifting 8
LshG8:	T←AC0.T;
	SINK←LREG, L←T, BUS, TASK;  Branch on shift count mod 8
	AC0←L LCY 8, :Lsh0;

; Shift count less than 8.  Branch on shift count
LshL8:	SINK←AC1, BUS, TASK;
	:Lsh0;

Lsh7:	L←AC0;
	AC0←L LSH 1;
Lsh6:	L←AC0;
	AC0←L LSH 1;
Lsh5:	L←AC0;
	AC0←L LSH 1;
Lsh4:	L←AC0;
	AC0←L LSH 1;
Lsh3:	L←AC0;
	AC0←L LSH 1;
Lsh2:	L←AC0;
	AC0←L LSH 1;
Lsh1:	L←AC0, TASK;
	AC0←L LSH 1, :Bran2;	Do PC←AC3 and go to START or StartX

; Shift count 0, do nothing
Lsh0:	L←AC0, TASK, :LtoAC0;

; Shift count 16 or greater, return zero
LshG16:	L←0, TASK, :LtoAC0;	[LtoAC0, LtoAC0]

; Shift count negative.  Convert to Right Shift
LshNeg:	L←0-T, TASK;		[LshN1, LshN1] Negate shift count
LshN1:	AC1←L, :Rsh;

; Ior
; Computes ac0 ← ac0 % ac1
; Called by jsr @340

Ior:	T←AC1;
	L←AC0 OR T, TASK, :LtoAC0;


; Xor
; Computes ac0 ← ac0 xor ac1
; Called by jsr @341

Xor:	T←AC1;
Xor1:	L←AC0 XOR T, TASK, :LtoAC0;


; Eqv
; Computes ac0 ← ac0 eqv ac1
; Called by jsr @342

Eqv:	T←AC1;
	L←ALLONES XOR T;	ac0 eqv ac1 = ac0 xor (not ac1)
	T←LREG, :Xor1;


; MulPlus
; Computes ac0 ← ac3 ← (ac1*@ac3)+ac0
; Calling sequence is:
;	lda 0 addend
;	lda 1 multiplicand
;	jsr @357
;	 multiplier
;	return here with result in ac0 and ac3

!1,2, MPNoAd, MPAdd;
!1,2, MPLoop, MPDone;

MulPlus:
	XMAR←AC3;		Start fetch of multiplier
	L←AC3+1;		Compute return pc
	PC←L;
	L←MD, BUSODD, :MPLp1;	Test low bit of multiplier

; MulPlus loop.  During each iteration, the multiplier is right-shifted 1
; and the multiplicand is left-shifted 1.  The loop terminates when the
; multiplier becomes zero.  This is good because in the standard use of
; MulPlus the multiplier is typically a small integer.
MPLoop:	L←AC3, BUSODD;		Test low bit of multiplier
MPLp1:	AC3←L RSH 1, :MPNoAd;	[MPNoAd, MPAdd] Shift it out

; Multiplier bit was 0, don't add but just shift multiplicand
MPNoAd:	L←AC1, SH=0, TASK, :MPShft; Test for no more bits in multiplier

; Multiplier bit was 1, add multiplicand to product
MPAdd:	T←AC1;			Multiplicand
	L←AC0+T;		Add to partial product
	AC0←L, L←T, TASK;	L← multiplicand
MPShft:	AC1←L LSH 1, :MPLoop;	[MPLoop, MPDone] Shift multiplicand left

; Here when done
MPDone:	L←AC0, IDISP;		Copy result to ac3
	AC3←L, :Start3;

; Mult
; Computes (ac0,ac1) ← ac0*ac1
; Called by jsr @343

!1,2, DoMul, NoMul;
!1,2, MNoAdd, MAdd;
!1,2, NoSpil, Spill;
%20,337,317, MultLp, MultDn;	(binary xx11x01111 and xx11x11111)

Mult:	L←AC0-1, BUS=0;		Get multiplicand-1, test for zero
	SAD←L, L←0, :DoMul;	[DoMul, NoMul] Save it away
DoMul:	AC0←L;			Init partial product to 0
	L←disp.300+1, TASK;	top two bits determine return
	IR←LREG;		Init loop count; done when it reaches X20

; Multiply loop
MultLp:	L←AC1, BUSODD;		Test low bit of multiplier
	T←AC0, :MNoAdd;		[MNoAdd, MAdd] Get partial product

; Multiplier bit was 1, add multiplicand to product
MAdd:	L←T←SAD+T+1;		Add multiplicand to partial product
	L←AC1, ALUCY;		Low part of partial product

; Multiplier bit was 0, just shift multiplicand and partial product
MNoAdd:	AC1←L MRSH 1, L←T, T←0, :NoSpil; [NoSpil, Spill]
Spill:	T←ONE;			Carry into high partial product
NoSpil:	AC0←L MRSH 1;
	L←DISP+1, BUS, TASK;	Check and update loop count
	IR←LREG, :MultLp;	[MultLp, MultDn] MultDn if DISP was X20

; Here when done
MultDn:	SINK←DISP, BUS;		top two bits of DISP to go to START or StartX
	L←AC3, :Start2;		[Start2, MultDnX] MultDnX if DISP is 321

MultDnX: PC←L, :StartX;

; Here when multiplicand is zero, just return zero
NoMul:	AC1←L, :Bran2;

; DivRem (and Rem, which is needed by the extended emulator)
; Computes ac1 ← ac0/ac1 and ac0 ← ac0 rem ac1 (signed)
; Called by jsr@344 or jsr@345

!1,2, DvsPos, DvsNeg;
!1,2, DndPos, DndNeg;
!1,2, NoSub, DoSub;
!1,2, DivLp, DivDn;
!1,2, RemPos, RemNeg;
!1,2, QuoPos, QuoNeg;

Rem:	:DivRem;		the extended emulator needs this
DivRem:	L←T←AC1;		Fetch divisor
	SAD←L, SH<0;		Save it, test sign
	XREG←L, L←0-T, :DvsPos;	[DvsPos, DvsNeg] Save original divisor
DvsNeg:	SAD←L;			Negative, negate divisor
DvsPos:	L←T←AC0;		Fetch dividend
	PC←L, L←0-T, SH<0;	Save it, test sign
	:DndPos;		[DndPos, DndNeg] Init loop count
DndNeg:	T←LREG;			Negative, negate dividend
DndPos:	L←20;			Init loop count
	XH←L, L←0, :DivLp0;	Init high dividend

; Divide loop
DivLp:	L←AC0;			Current high dividend
	T←AC1;			Current low dividend and quotient
DivLp0:	AC0←L MLSH 1, L←T;	Shift another bit into high dividend
	AC1←L LSH 1;		Shift a zero into quotient
	T←SAD;			Divisor
	L←AC0-T, T←AC0;		Try to subtract divisor from high dividend
	AC0←L, ALUCY;		Store dividend assuming subtract ok
	L←XH-1, :NoSub;	[NoSub, DoSub] Decrement and test loop count

; Subtract ok, put a 1 in the quotient
DoSub:	XH←L;			Update loop count
	L←AC1+1, SH=0, TASK;	Change quotient bit to 1
	AC1←L, :DivLp;		[DivLp, DivDn] Branch if done

; Subtract not ok, restore old dividend and leave quotient bit 0
NoSub:	XH←L, L←T, SH=0, TASK;	Update loop count
	AC0←L, :DivLp;		[DivLp, DivDn] Restore AC0, branch if done

; Here when done.  Fix up signs and exit
DivDn:	L←PC;			Get original dividend
	T←AC0, SH<0;		Test sign
	L←0-T, T←0, :RemPos;	[RemPos, RemNeg]
RemNeg:	AC0←L, T←0-1;		Was negative, negate remainder
RemPos:	L←XREG XOR T;		Get divisor sign, xor with dividend
	T←AC1, SH<0;		Test sign
	L←0-T, TASK, :QuoPos;
QuoNeg:	AC1←L, :Bran2;		Negate quotient
QuoPos:	:Bran2;			Set PC←AC3 and go to START or StartX

; Sq0
; Left shifts data a constant amount, then stores in partial-word field
; in same manner as Snq0.
; Executes @ac1 ← (@ac1 & not @ac3) + ((ac0 lshift n) & @ac3)
; Calling sequence is:
;	lda 0 value (right-justified)
;	lda 1 address of word being stored into
;	jsr 333 - 2*n (n is number of left shifts desired, in range 0-7)
;	 mask word (ones in field being stored into, zeroes elsewhere)
;	returns here

Sq0.7:	L←AC0;
	AC0←L LSH 1;
Sq0.6:	L←AC0;
	AC0←L LSH 1;
Sq0.5:	L←AC0;
	AC0←L LSH 1;
Sq0.4:	L←AC0;
	AC0←L LSH 1;
Sq0.3:	L←AC0;
	AC0←L LSH 1;
Sq0.2:	L←AC0;
	AC0←L LSH 1;
Sq0.1:	L←AC0, TASK;
	AC0←L LSH 1, :Snq0;


; Snq0
; Stores partial-word field into a structure.
; Executes @ac1 ← (@ac1 & not @ac3) + (ac0 & @ac3)
; Calling sequence is:
;	lda 0 value (must be bit-aligned with field being stored into)
;	lda 1 address of word being stored into
;	jsr @360
;	 mask word (ones in field being stored into, zeroes elsewhere)
;	returns here

Snq0:	XMAR←AC3;		Fetch mask
	L←AC1;			Address of word being stored into
Snq0a:	T←MD;
	MAR←LREG;		Fetch word being stored into
	AC1←L;			Save address (in case came from Snq1)
	L←MD AND NOT T;		Zero bits to be changed
	MAR←AC1;		Start to store back updated word
	T←AC0.T;		Mask out extraneous bits in new value
	L←LREG+T, TASK;		Merge new bits into old word
	MD←LREG;		Store back in memory
	L←AC3+1, IDISP,	:Start2; PC←AC3+1 and go to START or StartX

; Sq1
; Left shifts data a constant amount, then stores in partial-word field
; in same manner as Snq1.
; Executes @ac0 ← (@ac0 & not @ac3) + ((ac1 lshift n) & @ac3)
; Calling sequence is:
;	lda 1 value (right-justified)
;	lda 0 address of word being stored into
;	jsr 334 - 2*n (n is number of left shifts desired, in range 0-7)
;	 mask word (ones in field being stored into, zeroes elsewhere)
;	returns here

Sq1.7:	L←AC1;
	AC1←L LSH 1;
Sq1.6:	L←AC1;
	AC1←L LSH 1;
Sq1.5:	L←AC1;
	AC1←L LSH 1;
Sq1.4:	L←AC1;
	AC1←L LSH 1;
Sq1.3:	L←AC1;
	AC1←L LSH 1;
Sq1.2:	L←AC1;
	AC1←L LSH 1;
Sq1.1:	L←AC1, TASK;
	AC1←L LSH 1, :Snq1;


; Snq1
; Stores partial-word field into a structure.
; Executes @ac0 ← (@ac0 & not @ac3) + ac1 & @ac3
; Calling sequence is:
;	lda 1 value (must be bit-aligned with field being stored into)
;	lda 0 address of word being stored into
;	jsr @360
;	 mask word (ones in field being stored into, zeroes elsewhere)
;	returns here

Snq1:	XMAR←AC3;		Fetch mask
	L←AC1;			Get value
	T←AC0;			Get address
	AC0←L, L←T, :Snq0a;	Swap them and join common code

; Load byte from array
; Loads the ac1'th byte from the array pointed to by ac0
; and returns it right-justified in ac0.
; Called by jsr @362
; Note:  ac1 may be negative.

!1,2, Ly01P, Ly01N;
!1,2, Ly01L, Ly01R;

Ly01:	L←AC1;			Get index
	T←AC0, SH<0;		Get address, test for negative index
	MTEMP←L RSH 1, :Ly01P;	[Ly01P, Ly01N] Divide index by 2

Ly01N:	T←77777+T+1;		Negative index, extend sign of index/2
Ly01P:	MAR←MTEMP+T;		Positive index, start fetch
	SINK←AC1, BUSODD;	Which byte?
	T←377, :Ly01L;		[Ly01L, Ly01R]

Ly01L:	L←MD AND NOT T, TASK;	Left byte, mask and swap to right
	AC0←L LCY 8, :Bran2;

Ly01R:	L←MD AND T, TASK, :LtoAC0; Right byte, mask and store


; Load byte from array
; Loads the ac0'th byte from the array pointed to by ac1
; and returns it right-justified in ac1.
; Called by jsr @363
; Note:  ac0 may be negative.

!1,2, Ly10P, Ly10N;
!1,2, Ly10L, Ly10R;

Ly10:	L←AC0;			Get index
	T←AC1, SH<0;		Get address, test for negative index
	MTEMP←L RSH 1, :Ly10P;	[Ly10P, Ly10N] Divide index by 2

Ly10N:	T←77777+T+1;		Negative index, extend sign of index/2
Ly10P:	MAR←MTEMP+T;		Positive index, start fetch
	SINK←AC0, BUSODD;	Which byte?
	T←377, :Ly10L;		[Ly10L, Ly10R]

Ly10L:	L←MD AND NOT T, TASK;	Left byte, mask and swap to right
	AC1←L LCY 8, :Bran2;

Ly10R:	L←MD AND T, TASK;	Right byte, mask and store
	AC1←L, :Bran2;

; Store byte into array
; Stores the byte now contained in frame temp 3 (ac2!3) into
; the ac1'th byte of the array pointed to by ac0.
; Called by jsr@364
; Note:  ac1 may be negative.

!1,2, Sy01P, Sy01N;
!1,2, Sy01L, Sy01R;

Sy01:	L←AC1;			Get index
	T←3, SH<0;		Frame offset, test for negative index
	MAR←AC2+T, :Sy01P;	[Sy01P, Sy01N] Start fetch of byte to store

Sy01N:	MTEMP←L MRSH 1, :Sy01A;	Negative index, divide by 2 and extend sign
Sy01P:	MTEMP←L RSH 1;		Positive index, just divide by 2

Sy01A:	T←MTEMP;		Get word index
	L←AC0+T;		Compute address of word
	T←MD;			Here comes the byte to store
	MTEMP←L;		Save word address
	MAR←MTEMP;		Fetch word being stored into
	SINK←AC1, BUSODD;	Which byte?
Sy01C:	L←377 AND T, T←377, :Sy01L; [Sy01L, Sy01R] Isolate byte being stored

Sy01L:	AC1←L LCY 8;		Storing into left byte, swap halves
	L←MD AND T, :Sy01B;	Zero left byte of word being stored into

Sy01R:	AC1←L;			Storing into right byte, already set up
	L←MD AND NOT T;		Zero right byte of word being stored into

Sy01B:	MAR←MTEMP;		Start store
	T←LREG;			Existing contents to preserve
	L←AC1 OR T, TASK;	Merge old and new bytes
	MD←LREG, :Bran2;  Finish store, then PC←AC3 and go to START or StartX


; Store byte into array
; Stores the byte now contained in frame temp 3 (ac2!3) into
; the ac0'th byte of the array pointed to by ac1.
; Called by jsr@365
; Note:  ac0 may be negative.

!1,2, Sy10P, Sy10N;

Sy10:	L←AC0;			Get index
	T←3, SH<0;		Frame offset, test for negative index
	MAR←AC2+T, :Sy10P;	[Sy10P, Sy10N] Start fetch of byte to store

Sy10N:	MTEMP←L MRSH 1, :Sy10A;	Negative index, divide by 2 and extend sign
Sy10P:	MTEMP←L RSH 1;		Positive index, just divide by 2

Sy10A:	T←MTEMP;		Get word index
	L←AC1+T;		Compute address of word
	T←MD;			Here comes the byte to store
	MTEMP←L;		Save word address
	MAR←MTEMP;		Fetch word being stored into
	SINK←AC0, BUSODD, :Sy01C; Which byte? Join common code