**Dorado Smalltalk Microcode -- Model 1, XM version
** last edited July 9, 1979 9:58 AM by Deutsch
** By convention, labels starting with ’.’ are used only within the immediate vicinity
** (same subroutine or other local piece of code).
** RBase is maintained as State throughout this code
** last edited on July 14, 1980 3:35 PM by wsh
** changed IFU management so that Pcb is set to -1 iff smalltalk does
*** an IFUJump!!!
Title[DsmallOps.Mc];
Top Level;
KnowRBase[State];
* The Bytecode Interpreter proper
StartByterp:*here after Bytes or Rtrn/Rend
Call[StartIfu];
Byterp:
SupMod ← T ← T - T - 1;*T ← (-1c)
AOop ← T;
BOop ← T;
Mode ← T - T;
Pcb← T, IfuJump[0];* will do one ifujump
*Load data for stack
* Enter here from byte dispatch with MemBase, RBase(=State), and T/Id set up
* Load instance variable
MIFU[0,17,IFU1[==,SelfBr,I.Vars,=]];
MIFU[17,1,IFU1[==,SelfBr,I.Vars17,=]];
* Load activation variable
MIFU[20,17,IFU1[==,TFrameBr,I.Vars,=]];
MIFU[37,1,IFU1[==,TFrameBr,I.Vars17,=]];
* Load literal
MIFU[40,17,IFU1[==,LocFrameBr,I.Vars,=]];
MIFU[57,17,IFU1[==,LocFrameBr,I.Vars17,=]];
MIFU[76,2,IFU1[==,LocFrameBr,I.Vars36,=]];
* Load indirect through literal
MIFU[100,17,IFU1[==,LocFrameBr,I.IndVars,=]];
MIFU[117,17,IFU1[==,LocFrameBr,I.IndVars17,=]];
MIFU[136,17,IFU1[==,LocFrameBr,I.IndVars36,=]];
MIFU[155,3,IFU1[==,LocFrameBr,I.IndVars55,=]];
* Load from arec
MIFU[160,10,IFU1[==,ArecBr,I.Vars,=]];
* Extended loads (no N, so first ID is alpha)
IFU2[210,SelfBr,I.Vars,17];
IFU2[211,TFrameBr,I.Vars,17];
IFU2[212,LocFrameBr,I.Vars,17];
IFU2[213,LocFrameBr,I.IndVars,17];
I.IndVars:
Fetch ← Id, Branch[.IndVars1];
I.IndVars17:
T ← (Id) + (17c), Branch[IndVars];
I.IndVars36:
T ← (Id) + (36c), Branch[IndVars];
I.IndVars55:
T ← (Id) + (55c), Branch[IndVars];
I.Vars:
T ← Id, B ← Mode, DblBranch[Push, Pull, R Even];
I.Vars17:
T ← (Id) + (17c), Branch[Vars];
I.Vars36:
T ← (Id) + (36c), Branch[Vars];
IndVars:
Fetch ← T;*load @ localframe
.IndVars1:
Arg1 ← Md, Call[Hash];*Hash indirect literal object reference
A ← Mode, Branch[AemVars, R Even];*Only dirty if store
Call[Dirty];*Hash indirect literal object reference, dirty
MemBase ← AemMemBase, Branch[Vars];*duplicated for placement
AemVars:
MemBase ← AemMemBase;
Vars:
A ← Mode, DblBranch[Push, Pull, R Even];
Push:*Stack to Data
Fetch ← T;
StackP ← (StackP) + 1, T ← Md;
Shove:*Replace top of stack with T, same as pop and push
Top ← T, Call[RefCkLInc];
RefX4:
T ← StackP;
*Stor:
*T = new stack pointer
*Top = New oop
*Tempframe[Stackp ← T] ← Top
Stor:
MemBase ← TFrameBr;
.Stor1:
StackP ← Fetch ← T;
Arg1 ← Md;
Store ← T, DBuf ← Top, Call[RefCkDec];
Branch[Byterp];
* Load system constants
IFU1[170,TFrameBr,I.ConstM1,17];
IFU1[171,TFrameBr,I.IntConst,0];
IFU1[172,TFrameBr,I.IntConst,1];
IFU1[173,TFrameBr,I.IntConst,2];
IFU1[174,TFrameBr,I.IntConst,12];
IFU1[175,TFrameBr,I.ConstNil,17];
IFU1[176,TFrameBr,I.ConstFalse,17];
IFU1[177,TFrameBr,I.ConstTrue,1];
I.ConstM1:
Top ← T ← OopM1.c, Branch[.Atom];
I.IntConst:
Top ← T ← (Id) + (Oop00.c), Branch[.Atom];
I.ConstNil:
Top ← T ← -1c, Branch[.Atom];
I.ConstFalse:
Top ← T ← FalseOop.c, Branch[.NonAtom];
I.ConstTrue:
Top ← T ← (Id) + (TrueOopm1.c), Branch[.NonAtom];*Id=1
.NonAtom:
Arg1 ← T, Call[RefInc];
.Atom:
T ← (StackP) + 1, MemBase ← TFrameBr, Branch[.Stor1];
*Smash, SmashPop:
*Top = Data to be stored
*Store T into location described by next byte
IFU1[200,TFrameBr,SmashPop,17];
IFU1[201,TFrameBr,Smash,17];
IFU1[202,TFrameBr,Pop,17];
SmashPop:
StackP ← (StackP) - 1;
Smash:
Mode ← (1c);*Resched prevented when Mode#0
Pcb← T - T - 1, IfuJump[0];* did a Smalltalk opcode
Pop:
StackP ← (StackP) - 1;
Pcb← T - T - 1, IfuJump[0];* did a Smalltalk opcode
*Pull Stack to Data--T+MemBase=Addr. of data, Top=new oop to be stored in data
Pull:
Fetch ← T;
Arg1 ← Md;
Store ← T, DBuf ← Top, Call[RefCkDec];*RefD old oop
T ← Top, Call[RefCkLInc];*Do it again, RefI new oop
A ← Mode, Mode ← (0c), Branch[.+2, R Odd];
Branch[RiSubEnd];*placement -- finish subscript store
Pcb← T - T - 1, IfuJump[0];* did a Smalltalk opcode
*Return control to caller (Return from Eval)
* MemBase=TFrameBr (from IFU)
IFUP1[204,TFrameBr,Rend,17];
Rend:
Call[StopIfu];*Smashes MemBase
T ← (StackP) - 1, MemBase ← TFrameBr, Call[DoReturn];
StackP ← (StackP) - (2c);*Can’t do in 1 instr. because of placement conflict
Call[Stash];
Branch[.ReturnEnd];
*Return to sender
* MemBase=ArecBr (from IFU)
IFUP1[203,ArecBr,Rtrn,17];
Rtrn:
Call[StopIfu];*Smashes MemBase
MemBase ← ArecBr;
T ← Senderf.s, Call[DoReturn];*Address sender
.ReturnEnd:
T ← Ctxt, Call[HashL];*Hash current context, dirty...
Call[Dirty];*Only legal after hash call
MemBase ← ArecBr;
BrLo ← T;*T ← Core address of current activation
ArecBase ← T;
* Restore Pcb from arec
T ← MOop00.c;*MOop00.c is -(Oop00.c)
Fetch ← PcF.s;
Pcb ← T + (Md);
* Restore StackP similarly
Fetch ← StackPF.s;
StackP ← T + (Md);
* Restore instance
Fetch ← InstF.s;
T ← Md;
PD ← (T) - (MinAt);
Arg1 ← Md, DblBranch[.NoHash, .DoHash, Carry];
.NoHash:
T ← T - T - 1, Branch[.GotSelf];
.DoHash:
Call[Hash];*T ← C.A.[Arec[Inst]]
Call[Dirty];
.GotSelf:
MemBase ← SelfBr;
BrLo ← T;
SelfBase ← T;
MemBase ← ArecBr;
Fetch ← CodeF.s, Call[HashMd];*get method
Call[MapCode];
MemBase ← ArecBr;
Fetch ← TFrameF.s, Call[HashMd];*get tempframe
Call[Dirty];
MemBase ← TFrameBr;*Referencing TFrame
BrLo ← T; *T ← C.A.[Arec[Tframe]]
TFrameBase ← T;
T ← Name, Call[RefCkLDec];*Zap me
T ← StackP ← (StackP) + 1, MemBase ← TFrameBr;*And push top of old stack on new
Fetch ← T;
Arg1 ← Md;
Store ← T, DBuf ← Top, Call[RefCkDec];
Branch[StartByterp];
*DoReturn--perform an actual control return
*Temp1 ← T = address of context to return to
Subroutine;
DoReturn:
Temp1 ← Fetch ← T;
T ← Ctxt, Ctxt ← Md;*Ctxt ← My sender
Name ← T;*Name ← Current context
Store ← Temp1, DBuf ← AllOnes.c;*Nil my sender
MemBase ← TFrameBr;
Store ← StackP, DBuf ← AllOnes.c, Return;*Nil ref to value (RefI)
Top Level;
*Current--Push current context
IFU1[205,TFrameBr,Current,17];
Current:
StackP ← (StackP) + 1;
T ← Ctxt, Branch[Shove];*Shove takes argument in T
*Super -- send message to superclass
IFU1[206,TFrameBr,Super,17];
Super:
T ← (33c), Branch[NovaCall];*NovaCall 33
SupRet:
Pcb← T - T - 1, IfuJump[0];*Resched prevented when SupMod#nil
*Unimplemented bytecodes
IFUP1[207,TFrameBr,Unimp,17];
MIFU[215,3,IFUP1[==,TFrameBr,Unimp,17]];
Unimp:
Breakpoint;
KnowRBase[State];
*ShortJumps--Control transfer operation of one to eight
* Displacement in T if no IFU
MIFU[220,10,IFUJ1[==,TFrameBr,I.ShortJmp,add[=,2]]];
MIFU[230,10,IFUJ1[==,TFrameBr,I.ShortBfp,add[=,2]]];
I.ShortJmp:
Pcb← T - T - 1, IfuJump[0];*IFU did it
I.ShortBfp:
PD ← (Top) - (FalseOop.c);
StackP ← (StackP) - 1, Branch[.NoJump, Alu=0];*IFU did the jump
T ← (Id) - (PCX’) - 1, Branch[JumpIfu];*Id = Length
.NoJump:
Pcb← T - T - 1, IfuJump[0];
*LongJumps-- Control transfer operations of -1024 to 1023
MIFU[240,10,IFUP2[==,TFrameBr,I.LongJmp,=]];
MIFU[250,10,IFU2[==,TFrameBr,I.LongBfp,=]];
I.LongJmp:
T ← (Id) - (4c);
.LJmp1:
T ← Lsh[T, 10];
T ← (Id) + T;*compute biased displacement
T ← (Id) + T;*add Id = Length
T ← T - (PCX’) - 1, Branch[JumpIfu];
I.LongBfp:
PD ← (Top) - (FalseOop.c);
StackP ← (StackP) - 1, Branch[.+2, Alu=0];
Pcb← T - T - 1, IfuJump[0];*continue in sequence
T ← (Id) - (4c), Branch[.LJmp1];*placement
END;