;#altoconsts23.mu;get definitions,constant allocations

; last modified by Butterfield, March 6, 1980 11:34 AM
; - add PCgetsLret tag for MainMc - 3/6
; - commented out unused rett - 3/6/80

;Dispatch definitions:

;!20,1,START;
return address for emulator restart
;!37,1,TRAP1;
!645,1,TRAP;
for microcode 13
;!120,1,MUL;
!124,20,BLT,BLKS,,,,,,,,,,MUL,DIV,,BITBLOT;

;REGISTERS USED BY NOVA EMULATOR
$AC0
$R3; ac’s are backwards because the hardware supplies
; the complement address when addressing from ir
$AC1
$R2;
$AC2
$R1;
$AC3
$R0;
$NWW
$R4;
$SAD
$R5;
$PC
$R6;
$XREG
$R7;
$LastL
$R40; not a real S register, but rather L gated to the bus
;Clock (in refresh task) R11,R37
;Ethernet R12,R13
;Display controller: R20-R30
;Disk Controller: R31-R34

;Available: R5,R10,R14-17,R35-36
$Arg0
$R10;
$Arg1
$R12;WATCH OUT! EtherNet location
$Arg2
$R17;
$M1
$R15;
$N1
$R16;
$M2
$R35;
$N2
$R36;

$S1
$R41;sign
$E1
$R42;exponent

$S2
$R43;
$E2
$R44;

$maxAC
$R45;
$EOffset
$R46;
$MOffset
$R47;
$NOffset
$R50;

$ErrorAddress$R51;
$FPwork
$R52;
$Temp
$R53;
$CRY
$R54;

$Mode
$R55;0 for add, -1 for subtract
$ShiftCount
$R56;
$SubRet
$R57;

;rett:
TASK;most general return (Return&TASK)
retn:
NOP;return, do nop first (prev inst has task)
ret:
SWMODE;
:START;back to ROM

!37,40,Routine0,Routine1,Routine2,Routine3,Routine4,Routine5,Routine6,Routine7,Routine10,Routine11,Routine12,Routine13,,Routine15,Routine16,Routine17,,,,Routine23;
TRAP:
SINK←DISP,BUS,:dispatch;
TRAP1:
SINK←DISP,BUS;"or" low-order 8 bits of IR into "NEXT"
dispatch:
NOP,:Routine0;

;---------------------------------------------------------------
;multiply subroutine
;---------------------------------------------------------------


!7,10,MulRet,MulRet1,MulRet2,MulRet3;
!1,2,DOMUL,NOMUL;
!1,2,MPYL,MPYA;
!1,2,NOADDIER,ADDIER;
!1,2,NOSPILL,SPILL;
!1,2,NOADDX,ADDX;
!1,2,NOSPILLX,SPILLX;

MUL:
SubRet←L;
L←Arg2-1, BUS=0;
MPYX:
XREG←L,L←0,:DOMUL;
DOMUL:
TASK,L←-10+1;
SAD←L;
MPYL:
L←Arg1,BUSODD;
T←Arg0,:NOADDIER;
NOADDIER:
Arg1←L MRSH 1,L←T,T←0,:NOSPILL;
ADDIER:
L←T←XREG+INCT;
L←Arg1,ALUCY,:NOADDIER;
SPILL:
T←ONE;
NOSPILL:
Arg0←L MRSH 1;
L←Arg1,BUSODD;
T←Arg0,:NOADDX;
NOADDX:
Arg1←L MRSH 1,L←T,T←0,:NOSPILLX;
ADDX:
L←T←XREG+INCT;
L←Arg1,ALUCY,:NOADDX;
SPILLX:
T←ONE;
NOSPILLX:
Arg0←L MRSH 1;
L←SAD+1,BUS=0,TASK;
SAD←L,:MPYL;
NOMUL:
T←Arg0;
Arg0←L,L←T,TASK;
Arg1←L;
MPYA: SINK←SubRet,BUS;
NOP,:MulRet;

;---------------------------------------------------------------
;divide subroutine
;---------------------------------------------------------------

!7,10,DivRet,DivRet1,DivRet2;
!1,2,DODIV,NODIV;
!1,2,DIVL,ENDDIV;
!1,2,NOOVF,OVF;
!1,2,DX0,DX1;
!1,2,NOSUB,DOSUB;

DIV:
SubRet←L;
T←Arg2;
DIVX:
L←Arg0-T;Do the divide only if Arg2>Arg0
ALUCY,TASK,SAD←L,L←0+1;
:DODIV,SAD←L LSH 1;SAD←2, count the loop by shifting
NODIV:
SINK←SubRet,BUS;
DRET:
NOP,:DivRet;
DODIV:
L←Arg0,:DIV1;
DIVL:
L←Arg0;
DIV1:
SH<0,T←Arg1;will the left shift of the dividend overflow?
:NOOVF,Arg0←L MLSH 1,L←T←0+T;L←Arg1,T←0
OVF:
Arg1←L LSH 1,L←0+INCT,:NOV1;L←1: shift overflowed
NOOVF:
Arg1←L LSH 1,L←T;L←0: shift ok
NOV1:
T←Arg2,SH=0;
L←Arg0-T,:DX0;
DX1:
ALUCY;do the test only if the shift didn’t overflow. If it did, L is still correct
T←Arg1,:NOSUB;but the test would go the wrong way
DX0:
T←Arg1,:DOSUB;
DOSUB:
Arg0←L,L←0+INCT;do the subtract
Arg1←L;and put a 1 in the quotient
NOSUB:
L←SAD,BUS=0,TASK;
SAD←L LSH 1,:DIVL;
ENDDIV:
SINK←SubRet,BUS,:DRET;

;---------------------------------------------------------------
;load up arguments (in AC0,AC1) into registers
;---------------------------------------------------------------

!7,10,LoadRet,LoadRet1,LoadRet2,,PackedVectorRet;
!1,2,Acc,PackedVector;
!1,2,ACOK,ACER;
!1,2,ACpos,ACneg;
!1,2,ACpos1,ACneg1;

LoadArgs: SubRet←L;
L←T←AC0;
L←maxAC-T,SH<0;make sure AC is in range
MAR←L←FPwork+T,SH<0,:ACpos;!1,2,ACpos,ACneg;
ACpos:
Temp←L,:ACOK;!1,2,ACOK,ACER;
ACOK:
T←EOffset;
L←MD;
MAR←Temp+T;
S1←L;
L←MD;
T←MOffset;

MAR←Temp+T;
E1←L;
T←NOffset;
L←MD;

MAR←Temp+T;
M1←L;

L←T←AC1;
L←maxAC-T,SH<0;
L←MD,SH<0,TASK,:ACpos1;!1,2,ACpos1,ACneg1;
ACneg1: N1←L,:PackedVector;

ACpos1:
N1←L,:Acc;!1,2,Acc,PackedVector;

ACneg: L←3,:DoErrorReturn;
an AC must be positive
ACER:
L←3,:DoErrorReturn;

;and now, argument two
Acc:
T←AC1;
MAR←L←FPwork+T;
Temp←L;
T←EOffset;
L←MD;

MAR←Temp+T;
S2←L;
L←MD;
T←MOffset;

MAR←Temp+T;
E2←L;
T←NOffset;
L←MD;

MAR←Temp+T;
M2←L;
L←MD,TASK;
N2←L,:LRET;

;and, the big return
LRET:
SINK←SubRet,BUS;
NOP,:LoadRet;

!1,2,PVPos,PVNeg;
!1,2,PVLowNonZero,PVLowZero;
!1,2,PVExpBias,PVNoExpBias;

PackedVector:
;load M2 from packed vector (addr in AC1), return via SubReg and LoadRet
MAR←AC1;
NOP;
L←MD;

MAR←AC1+1;
Arg0←L;first word
L←MD,TASK;
Arg1←L;second word

L←Arg0;check for sign
NOP,SH<0;
T←Arg1,:PVPos;

PVNeg:
L←0-T;negate the double word, store S2=-1
Arg1←L,SH=0;
T←Arg0,:PVLowNonZero;!1,2,PVLowNonZero,PVLowZero;
PVLowNonZero:
L←ALLONES XOR T,:PVStore;complement
PVLowZero:
L←0-T,:PVStore;negate if low word 0
PVStore:
Arg0←L,L←0-1,TASK,:PVSign;set sign=-1
PVPos:
L←0,TASK;
PVSign:
S2←L;

;now, double word LShift 1, for 8-bit addressing ease
L←T←Arg1;low order
Arg1←L LSH 1;
L←Arg0,TASK;
Arg0←L MLSH 1;

;flip the args around, to be [M2a,E2][N2,M2b]
L←Arg0,TASK;
Arg0←L LCY 8;
L←Arg1,TASK;
Arg1←L LCY 8;

;now, place the right halves
T←377;
L←Arg0 AND T;E2
E2←L;
L←Arg1 AND T,TASK;M2b
M2←L;

;and the right halves
T←177400;
L←Arg1 AND T;N2
N2←L;
L←Arg0 AND T;M2a
T←M2;
L←LastL OR T;M2a,M2b=M2
M2←L,SH=0;
T←200,:PVExpBias;exponent is exponent+200, unless exponent=0
PVExpBias:
L←E2-T,TASK;
E2←L,:LRET;
PVNoExpBias:NOP,:LRET;

;---------------------------------------------------------------
;FLDI
load floating point accumulator with integer value
;---------------------------------------------------------------
!1,2,Pos,Neg;
!1,2,LdNonZero,LdZero;
!1,2,LowNonZero1,LowZero1;

Routine10: L←T←AC1;
M1←L,SH<0;
L←20,:Pos;
Pos:
SINK←M1,BUS=0;
E1←L,:LdNonZero;
LdNonZero:
L←0,:Store;
Neg:
E1←L;
L←0-T;negate number
M1←L,L←0-1;
Store:
S1←L;
L←0,TASK;
N1←L;

;now, normalize
NormI:
L←M1;
NOP,SH<0;

!1,2,NormICont,StoreAndReturn;

NOP,:NormICont;
NormICont:
M1←L LSH 1;
L←E1-1,TASK;
E1←L,:NormI;

LdZero:
L←0,:LowZero1;

;---------------------------------------------------------------
;Put result back into FP in AC0, and do subroutine return
;---------------------------------------------------------------
!1,2,ACOK2,ACER2;
!1,2,ACpos2,ACneg2;

StoreAndReturn: L←T←AC0;
L←maxAC-T,SH<0;make sure AC is in range
MAR←L←FPwork+T,SH<0,:ACpos2;!1,2,ACpos2,ACneg2;
ACpos2:
Temp←L,:ACOK2;
ACOK2:
T←EOffset;
MD←S1;

MAR←Temp+T;
NOP,TASK;
MD←E1;
T←MOffset;

MAR←Temp+T;
T←NOffset;
MD←M1;

MAR←Temp+T;
NOP,TASK;
MD←N1,:ret;

ACER2:
L←3,:DoErrorReturn;
ACneg2:
L←3,:DoErrorReturn;

;---------------------------------------------------------------
;Load register pointed to by Arg0
;---------------------------------------------------------------

!7,10,LoadOneRet,LoadOneRet1,LoadOneRet2,LoadOneRet3,LoadOneRet4,LoadOneRet5,LoadOneRet6;
!1,2,ACOK1,ACER1;
!1,2,ACpos3,ACneg3;

LoadRegOne: SubRet←L;
L←T←Arg0;
L←maxAC-T,SH<0;
MAR←L←FPwork+T,SH<0,:ACpos3;!1,2,ACpos3,ACneg3;
ACpos3:
Temp←L,:ACOK1;
ACOK1:
T←EOffset;
L←MD;

MAR←Temp+T;
S1←L;
L←MD;
T←MOffset;

MAR←Temp+T;
E1←L;
T←NOffset;
L←MD;

MAR←Temp+T;
M1←L;
L←MD,TASK;
N1←L;

;and, the big return
SINK←SubRet,BUS;
NOP,:LoadOneRet;

ACneg3:L←3,:DoErrorReturn;
ACER1:L←3,:DoErrorReturn;

;--------------------------------------------------------------------------------
;FST
store floating point accumulator into packed vector [ERROR 1: exponent too large]
;--------------------------------------------------------------------------------
!1,2,FSTNonZero,FSTZero;
!1,2,FSTWrite,FSTNeg;
!1,2,FSTError,FSTOK;
!1,2,FSTDPNeg,FSTDPPos;
!1,2,FSTDPLowNonZero,FSTDPLowZero;

Routine15:
L←AC0;
Arg0←L;
L←5,:LoadRegOne;
LoadOneRet5:
L←M1,BUS=0;a,b
Arg0←L LCY 8,:FSTNonZero;b,a
FSTZero:
NOP,:FSTDPPos;

FSTNonZero:
L←N1;c,d
Arg1←L LCY 8;d,c
T←377;
L←Arg1 AND T,TASK;
Arg1←L;0,c
T←177400;
T←Arg0.T;b,0
L←Arg1 OR T,TASK;
Arg1←L;b,c
T←377;
L←Arg0 AND T,TASK;
Arg0←L;0,a

T←200;
L←E1+T,TASK;
M1←L LCY 8;
;check low order 8 bits of M1 are 0, else ERROR=1
T←M1;
L←377 AND T;
L←Arg0 OR T,SH=0;e,a
Arg0←L,:FSTError;
FSTError:
L←ONE,:DoErrorReturn;

;and double shift right
FSTOK:
L←T←Arg0;
M1←L RSH 1;
L←Arg1,TASK;
N1←L MRSH 1;

L←S1;
T←N1,SH<0;
L←0-T,:FSTWrite;
FSTWrite:
NOP,:FSTDPPos;

;--------------------------------------------------------------------------------;FTR return truncated floating point ac (integer value) [ERROR=0: exponent too large]
;--------------------------------------------------------------------------------
!1,2,TrExpOK,TrExpZero;
!1,2,TrExpOvfl,TrExpO
K1;
!1,2,TrLoop,TrLoopDone;
!1,2,TrNeg,TrPos;

Routine11:
L←AC0,TASK;
Arg0←L;
L←2,:LoadRegOne;
LoadOneRet2:
L←E1-1;test for exponent <= 0, ifso, return 0
T←20,SH<0;
L←0,:TrExpOK;!1,2,TrExpOK,TrExpZero;

TrExpOK:
L←E1-T;test for exp ge 16, if so, ERROR 0
E1←L,SH<0;this will be the shift counter, Exponent-16
NOP,:TrExpOvfl;!1,2,TrExpOvfl,TrExpOK1;

TrExpOK1:
L←E1+1,BUS=0;
E1←L,:TrLoop;!1,2,TrLoop,TrLoopDone
TrLoop:
L←M1;
M1←L RSH 1,:TrExpOK1;

TrLoopDone:
SINK←S1,BUS=0;
T←M1,:TrNeg;

TrNeg:
L←0-T,:TrExpZero;

TrPos:
L←M1,:TrExpZero;

TrExpOvfl:
L←0,:DoErrorReturn;
TrExpZero:
AC0←L,TASK,:retn;

;---------------------------------------------------------------
;FNEG negate floating point ac
;---------------------------------------------------------------
!1,2,NegOK,NegZero;

Routine12:
L←AC0;
Arg0←L;
L←3,:LoadRegOne;
LoadOneRet3:
SINK←M1,BUS=0;
T←ALLONES,:NegOK;
NegOK:
L←S1 XOR T,TASK;
S1←L,:StoreAndReturn;
NegZero:
TASK,:retn;

;---------------------------------------------------------------
;FSN return -1,0,1 according to sign
;---------------------------------------------------------------
!1,2,SnCont,SnZero;
!1,2,SnPos,SnNeg;

Routine13:
L←AC0,TASK;
Arg0←L;
L←4,:LoadRegOne;
LoadOneRet4:
SINK←M1,BUS=0;
L←S1,:SnCont;
SnCont:
L←ONE,SH<0;
NOP,:SnPos;
SnNeg:
L←ALLONES,:SnPos;
SnZero:
L←0;
SnPos:
AC0←L,TASK,:retn;

;---------------------------------------------------------------
;FLD floating point load register from register
;---------------------------------------------------------------
!1,2,FLDAcc,FLDPackedV;
!1,2,ACpos4,ACneg4;

Routine5:
L←T←AC1;
L←maxAC-T,SH<0;check for Packed vector or AC
L←AC1,SH<0,TASK,:ACpos4;!1,2,ACpos4,ACneg4;
ACpos4:
Arg0←L,:FLDAcc;
ACneg4:
Arg0←L,:FLDPackedV;

FLDAcc:
L←0,:LoadRegOne;
LoadOneRet:
NOP,:StoreAndReturn;

FLDPackedV:
L←4;
SubRet←L,:PackedVector;stuff Packed vector into [S2,E2,M2,N2]
PackedVectorRet:
L←S2,TASK;
S1←L;
L←E2,TASK;
E1←L;
L←M2,TASK;
M1←L;
L←N2,:StoreN1AndReturn;

;---------------------------------------------------------------
;FLDV floating point load from unpacked vector
;---------------------------------------------------------------
Routine6:MAR←AC1;
NOP;
L←MD;

MAR←AC1+1;
S1←L;
L←AC1+1;
AC1←L;
L←MD,TASK;
E1←L;

MAR←L←AC1+1;
AC1←L;
L←MD;

MAR←AC1+1;
M1←L;
L←MD,TASK;
StoreN1AndReturn:
N1←L,:StoreAndReturn;

;---------------------------------------------------------------
;FSTV floating point store unpacked into vector
;---------------------------------------------------------------
Routine7:L←AC0;
Arg0←L,L←0+1,:LoadRegOne;
LoadOneRet1:
MAR←AC1;
NOP,TASK;
MD←S1;

MAR←L←AC1+1;
L←LastL+1;
AC1←L,TASK;
MD←E1,:FSTDPPos;
;--------------------------------------------------------------------------------;initialization: AC0 has floating point AC work area start, AC1 has Error routine address
;--------------------------------------------------------------------------------
Routine0: MAR←AC0;
L←AC0+1;
FPwork←L;
L←MD;
EOffset←L;
L←EOffset-1,TASK;
maxAC←L;
T←EOffset;
L←EOffset+T;
MOffset←L;
L←MOffset+T;
NOffset←L;

L←AC1,TASK;
ErrorAddress←L,:ret;

DoErrorReturn: AC0←L;
called with error code in L
L←ErrorAddress,TASK;
PCgetsLret: PC←L,:ret;

;---------------------------------------------------------------
;FMP floating point multiply
;---------------------------------------------------------------

!1,2,FMPNonZero,FMPZero;
!1,2,FMPNonZero1,FMPZero1;

Routine1: L←0,:LoadArgs;

;add exponents, like in any multiply
LoadRet:
T←E1;
L←E2+T,TASK;
E1←L;

;and xor signs
T←S1;
L←S2 XOR T,TASK;
S1←L;

;first multiply: high*low
L←M1;
Arg1←L,SH=0;
L←N2,:FMPNonZero;
FMPZero:
L←0,:LowZero1;return 0
FMPNonZero:
Arg2←L,L←0;
Arg0←L,:MUL;L must be 0 for SubRet
MulRet: L←Arg0,TASK;
Temp←L;

;second multiply: other high*other low
L←M2;
Arg1←L,SH=0;
L←N1,:FMPNonZero1;
FMPZero1:
L←0,:LowZero1;
FMPNonZero1:
Arg2←L,L←0;
Arg0←L,L←0+1,:MUL;L must have 1 for Subroutine Return
MulRet1: T←Arg0;

!1,2,NoCarry,Carry;

;add results, set carry if overflow
L←Temp+T;
Arg0←L,ALUCY;
L←0,:NoCarry;
Carry:
L←ONE;
NoCarry:
CRY←L;

!1,2,Carry1,NoCarry1;

;last multiply: high*high (plus stuff left in Arg0)
L←M1,TASK;
Arg1←L;
L←M2;
Arg2←L;
L←2,:MUL;
MulRet2: SINK←CRY,BUS=0;
L←Arg0,:Carry1;!1,2,Carry1,NoCarry1
Carry1:
L←Arg0+1;low+low resulted in a carry, add it now
NoCarry1:
M1←L,SH<0;now, check normalization

!1,2,Normalize,NoNormalize;
!1,2,NonZero,Zero;

T←Arg1,:Normalize;7 instructions since last TASK
Normalize:
M1←L MLSH 1;8
L←Arg1,SH=0;9
N1←L LSH 1,:NonZero;10
NonZero:
L←E1-1,TASK;decrement exponent to account for shift
E1←L,:StoreAndReturn;

NoNormalize:
L←Arg1,TASK;
N1←L,:StoreAndReturn;
Zero:
L←0,:LowZero1;

;---------------------------------------------------------------
;FDV floating point divide
;---------------------------------------------------------------

Routine2: L←ONE,:LoadArgs;

!1,2,DivOK,DivErr;
!1,2,DivOK1,DIV0;

LoadRet1: SINK←M2,BUS=0;
NOP,:DivOK;

DivErr:
L←2,:DoErrorReturn;

;first, subtract exponents
DivOK:
T←E2;
L←E1-T,TASK;
E1←L;

;now, xor signs
T←S1;
L←S2 XOR T;
S1←L;

;first, (M1,N1)/M2
L←T←M1,BUS=0;check for zero dividend
Arg0←L,:DivOK1;
DIV0:
TASK,:retn;dividend is already 0, just return
DivOK1:
L←ALLONES XOR T,TASK;NOT Arg0
Temp←L;
L←N1,TASK;
Arg1←L;
L←T←M2;
Arg2←L;

;unsigned test for Arg0<Arg2: ADCZ# 0,2,SZC
L←Temp+T;(NOT Arg0)+Arg2
NOP,ALUCY;

!1,2,DivC,D0;

L←T←Arg0,:DivC;
DivC:
Arg0←L RSH 1;divide dividend by two (rshift)
L←Arg1;
Arg1←L MRSH 1;
L←E1+1,TASK;bump exponent
E1←L;
D0:
L←0,:DIV;
DivRet:
L←Arg1;
M1←L,L←0;save high order results
Arg1←L,L←0+1,:DIV;now AC0,1 have remainder,0
DivRet1:
L←Arg1;
N1←L,L←0,TASK;save low order result

;now, answer is "too big" because low order bits of divisor were not included.
;so, we form correction term (N2/M2)*HighAnswer
Arg0←L;
L←N2,TASK;
Arg1←L;low order divisor
L←M1,TASK;
Arg2←L;high order answer so far
L←3,:MUL;(N2*M1)
MulRet3:
T←Arg0;
L←ALLONES XOR T;NOT Arg0;
T←M2;ADCZ# 0,2,SZCcheck for divide overflow
L←LastL+T;JMP D2divide won’t overflow
L←M2,ALUCY;

!1,2,DivC2,D2;
Arg2←L,:DivC2;
DivC2:
L←M1-1,TASK;decrement high order part of answer (because correction is to low order part)
M1←L;
T←M2;and subtract "one" from dividend
L←Arg0-T,TASK;
Arg0←L;
D2:
L←2,:DIV;(N2*M1)/M2
DivRet2:
T←Arg1;
L←N1-T;(uncorrected low order result)-(second correction)
Arg0←L,ALUCY;5if zero carry, then decrease high order part too

!1,2,Dec,NoDec;
!1,2,Norm,D1;

L←M1,:Dec;6
Dec:
L←M1-1;7
M1←L;8
NoDec:
NOP,SH<0;9get high order part of answer (could be unnormalized from either DSZ above)
T←Arg0,:Norm;10!1,2,Norm,D1;
Norm:
M1←L MLSH 1;11
L←E1-1,TASK;decrement exponent to account for shift
E1←L;
L←Arg0,TASK;
N1←L LSH 1,:StoreAndReturn;

D1:
L←Arg0,TASK;
N1←L,:StoreAndReturn;

;----------------------------------------------------
;floating point add and subtract
;----------------------------------------------------

Routine3:
L←0,TASK,:StoreMode;
Routine4:
L←ALLONES,TASK;
StoreMode:
Mode←L;

L←2,:LoadArgs;

;Preshift arguments until they match
LoadRet2:T←M1;
mantissa zero check
L←M2 AND T;
SINK←LastL,BUS=0;

!1,2,Sh,NoShz;

T←E1,:Sh;
Sh:
L←E2-T;if exponents are the same, no shift either
SINK←LastL,BUS=0;

!1,2,Sh1,NoSh;
!1,2,E1lsE2,E1grE2;
ShiftCount←L,:Sh1;
Sh1:
TASK,SH<0;

NOP,:E1lsE2;

E1lsE2:
L←E2,TASK;
E1←L;we’ll shift until exponent matches E2
T←ShiftCount;
L←37-T;
TASK,SH<0;37 is max number of shifts, if SH ge 0 then fix

!1,2,NoFix,Fix;
!1,2,More,Shifted;

NOP,:NoFix;
NoFix:
L←T←M1;
More:
M1←L RSH 1;
L←N1;
N1←L MRSH 1;
L←ShiftCount-1;
ShiftCount←L,SH=0;
L←T←M1,:More;

Fix:
L←0;set both words of mantissa1 to 0
M1←L,TASK;
N1←L,:EndShift;

Shifted:
NOP,:EndShift;
NoSh:
NOP,:EndShift;

!1,2,ExpOK,ExpWrite;

NoShz:
SINK←M1,BUS=0;if first arg is zero, then E1←E2
L←E2,TASK,:ExpOK;
ExpWrite:
E1←L;
ExpOK:
NOP,:EndShift;

E1grE2:
T←ShiftCount;actually, negative shift count
L←37+T;
TASK,SH<0;

!1,2,NoFix1,Fix1;
!1,2,More1,Shifted1;

NOP,:NoFix1;
NoFix1:
L←T←M2;
More1:
M2←L RSH 1;
L←N2;
N2←L MRSH 1;
L←ShiftCount+1;
ShiftCount←L,SH=0;
L←T←M2,:More1;

Fix1:
L←0;
M2←L,TASK;
N2←L,:EndShift;

Shifted1:
NOP,:EndShift;

;end of PRESHIFT
;now: ADD1 is Add(+ +), Add(- -), Sub(+ -), Sub(- +)
;and ADD2 is Add(+ -), Add(- +), Sub(+ +), Sub(- -)
; so: ADD1 if ((S1 XOR S2) XOR MODE) eq 0, and ADD2 otherwise

EndShift: T←S1;
L←S2 XOR T;0 if same, -1 if different
T←Mode;
L←LastL XOR T;0 if ADD1, -1 if ADD2
TASK,SH<0;

!1,2,ADD1,ADD2;

NOP,:ADD1;

ADD1:
T←N1;
L←N2+T;
N1←L,ALUCY;
!1,2,A1NoCarry,A1Carry;
T←M1,:A1NoCarry;
A1Carry:
L←M2+T+1,:A1Store;
A1NoCarry:
L←M2+T;
A1Store:
M1←L,ALUCY,TASK;
!1,2,A1xNoCarry,A1xCarry;
NOP,:A1xNoCarry;
A1xCarry:
T←L←M1;post shift
M1←L RSH 1;
L←N1,TASK;
N1←L MRSH 1;
T←100000;
L←M1 OR T;high order bit should have been shifted in
M1←L;
L←E1+1,TASK;
E1←L,:StoreAndReturn;
A1xNoCarry:
NOP,:StoreAndReturn;

ADD2:
T←N2;
L←N1-T;
N1←L,ALUCY;low order result

!1,2,Add2NoCarry,Add2Carry;

T←M2,:Add2NoCarry;
Add2NoCarry:
T←ALLONES;
L←M2 XOR T;COM M2
T←M1;
L←LastL+T,:Add2C;no carry, do one’s complement subtract
Add2Carry:
L←M1-T;carry, do two’s complement subtract
Add2C:
M1←L,ALUCY;

!1,2,Add2Sign,Add2NoSign;
!1,2,LowNonZero,LowZero;

L←0,:Add2Sign;if no carry, sign changed!!!!

Add2Sign:
T←N1,BUS=0;double length negate starts here
L←0-T,:LowNonZero;
LowNonZero:N1←L,T←0-1;
L←M1 XOR T,:Add2Cx;complement
LowZero:
T←M1;
L←0-T;negate (note that N1 is already 0, so no need to update it)
Add2Cx:
M1←L,T←0-1;
L←S1 XOR T,TASK;complement sign
S1←L;
L←0;

Add2NoSign:
ShiftCount←L;
L←M1,BUS=0;

!1,2,HiNonZero,HiZero;

NOP,:HiNonZero;

HiNonZero:
TASK,SH<0;

!1,2,Add2Norm,Add2NoNorm;

NOP,:Add2Norm;
Add2Norm:
L←N1;
NOP,SH<0;
!1,2,Add2NoCarryL,Add2CarryL;
N1←L LSH 1,T←0,:Add2NoCarryL;
Add2CarryL:
T←ALLONES;
Add2NoCarryL:
L←M1;
M1←L MLSH 1;
L←ShiftCount+1,TASK;
ShiftCount←L;
L←M1,:HiNonZero;

Add2NoNorm:T←ShiftCount;
L←E1-T,TASK;
E1←L,:StoreAndReturn;

HiZero:
L←N1,BUS=0;

;!1,2,LowNonZero1,LowZero1;
defined above

M1←L,L←0,:LowNonZero1;
LowNonZero1:
N1←L;zero out low order
L←20,TASK;
ShiftCount←L;16 shifts done like wildfire
L←M1,:HiNonZero;

LowZero1:E1←L;
S1←L;
M1←L,TASK;
N1←L,:StoreAndReturn;

;----------------------------------------------------------------------
; FLDDP
;----------------------------------------------------------------------
!1,2,FLDDPPos,FLDDPNeg;
!1,2,FLDDPLowNonZero,FLDDPLowZero;
!1,2,FLDDPHiNonZero,FLDDPHiZero;
!1,2,FLDDPCont,FLDDPAllZero;
!1,2,FLDDPShift,FLDDPNormalized;

Routine16:
;load M2 from packed vector (addr in AC1), return via SubReg and LoadRet
MAR←AC1;
NOP;
L←MD;

MAR←AC1+1;
Arg0←L;first word (high order)
L←MD,TASK;
Arg1←L;second word (low order)

L←Arg0;check for sign
NOP,SH<0;
T←Arg1,:FLDDPPos;

FLDDPNeg:
L←0-T;negate the double word, store S2=-1
Arg1←L,SH=0;
T←Arg0,:FLDDPLowNonZero;!1,2,FLDDPLowNonZero,FLDDPLowZero;
FLDDPLowNonZero:
L←ALLONES XOR T,:FLDDPStore;complement
FLDDPLowZero:
L←0-T,:FLDDPStore;negate if low word 0
FLDDPStore:
Arg0←L,L←0-1,TASK,:FLDDPSign;set sign=-1
FLDDPPos:
L←0,TASK;
FLDDPSign:
S1←L;

;now, double word LShift until normalized
L←20;
E1←L;16 decimal if already normalized

SINK←Arg0,BUS=0;
NOP,:FLDDPHiNonZero;!1,2,HiNonZero,HiZero

FLDDPHiZero: SINK←Arg1,BUS=0;
L←0,:FLDDPCont;!1,2,FLDDPCont,FLDDPAllZero;
FLDDPCont: E1←L;
16 shifts like wildfire
L←Arg1;
Arg0←L,L←0;
Arg1←L,:FLDDPHiNonZero;
FLDDPAllZero: L←0,:LowZero1;

FLDDPHiNonZero: L←Arg0;
NOP,SH<0;
NOP,:FLDDPShift;!1,2,FLDDPShift,FLDDPNormalized

FLDDPShift:
L←T←Arg1;low order
Arg1←L LSH 1;
L←Arg0,TASK;
Arg0←L MLSH 1;
L←E1-1;
E1←L,:FLDDPHiNonZero;

FLDDPNormalized: L←Arg0;
M1←L;
L←Arg1;
N1←L,:StoreAndReturn;

;----------------------------------------------------------------------
; FSTDP
;----------------------------------------------------------------------
!1,2,FSTDPE1OK,FSTDPE1Overflow;
!1,2,FSTDPShift,FSTDPNormalized;

Routine17: L←AC0;
Arg0←L;
L←6,:LoadRegOne;
LoadOneRet6: T←E1;
L←17-T;E1 must be < 16 decimal
E1←L,SH<0;
NOP,:FSTDPE1OK;!1,2,FSTDPE1OK,FSTDPE1Overflow

FSTDPE1Overflow: L←4,:DoErrorReturn;

FSTDPShift: L←T←M1,:FSTDPSh1;
FSTDPE1OK: L←T←M1;
high order
FSTDPSh1:
M1←L RSH 1;
L←N1,TASK;
N1←L MRSH 1;
L←E1-1,BUS=0;
E1←L,:FSTDPShift;FSTDPShift,FSTDPNormalized;

FSTDPNormalized: SINK←S1,BUS=0;
T←N1,:FSTDPNeg;!1,2,FSTDPNeg,FSTDPPos;

FSTDPNeg:
L←0-T;negate the double word, store S2=-1
FSTNeg:
N1←L,SH=0;
T←M1,:FSTDPLowNonZero;!1,2,FSTDPLowNonZero,FSTDPLowZero;
FSTDPLowNonZero:
L←ALLONES XOR T,:FSTDPStore;complement
FSTDPLowZero:
L←0-T,:FSTDPStore;negate if low word 0
FSTDPStore:
M1←L;

FSTDPPos:
MAR←AC1;
TASK;
MD←M1;
MAR←AC1+1;
TASK;
MD←N1,:ret;