|
@@ -0,0 +1,347 @@
|
|
|
|
+(** Active Cells Runtime Base Code for Variations of ActiveCellsRuntime Implementations
|
|
|
|
+ Felix Friedrich, ETH Zürich, 2015
|
|
|
|
+*)
|
|
|
|
+module ActiveCellsRuntime;
|
|
|
|
+
|
|
|
|
+import
|
|
|
|
+ system, Heaps, Modules, Diagnostics, Strings, Objects;
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ EnableTrace* = true;
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ (* do not inherit from this object -- not supported. This object contains hidden fields instantiated by the compiler that would be lost. *)
|
|
|
|
+ Cell* = object (* must be exported for compiler *)
|
|
|
|
+ var
|
|
|
|
+ c: any;
|
|
|
|
+ end Cell;
|
|
|
|
+
|
|
|
|
+ Context*= object
|
|
|
|
+
|
|
|
|
+ procedure Allocate*(scope: any; var c: any; t: Modules.TypeDesc; const name: array of char; isCellNet, isEngine: boolean);
|
|
|
|
+ end Allocate;
|
|
|
|
+
|
|
|
|
+ procedure AddPort*(c: any; var p: any; const name: array of char; inout: set; width: longint);
|
|
|
|
+ end AddPort;
|
|
|
|
+
|
|
|
|
+ procedure AddPortArray*(c: any; var ports: any; const name: array of char; inout: set; width: longint; const lens: array of longint);
|
|
|
|
+ end AddPortArray;
|
|
|
|
+
|
|
|
|
+ procedure AddStaticPortArray*(c: any; var ports: array of any; const name: array of char; inout: set; width: longint);
|
|
|
|
+ end AddStaticPortArray;
|
|
|
|
+
|
|
|
|
+ procedure AddPortIntegerProperty*(p: any; const name: array of char; value: longint);
|
|
|
|
+ end AddPortIntegerProperty;
|
|
|
|
+
|
|
|
|
+ procedure AddFlagProperty*(c: any; const name: array of char);
|
|
|
|
+ end AddFlagProperty;
|
|
|
|
+
|
|
|
|
+ procedure AddStringProperty*(c: any; const name: array of char; const value: array of char);
|
|
|
|
+ end AddStringProperty;
|
|
|
|
+
|
|
|
|
+ procedure AddIntegerProperty*(c: any; const name: array of char; value: longint);
|
|
|
|
+ end AddIntegerProperty;
|
|
|
|
+
|
|
|
|
+ procedure FinishedProperties*(c: any);
|
|
|
|
+ end FinishedProperties;
|
|
|
|
+
|
|
|
|
+ procedure Connect*(outPort, inPort: any; depth: longint);
|
|
|
|
+ end Connect;
|
|
|
|
+
|
|
|
|
+ procedure Delegate*(netPort: any; cellPort: any);
|
|
|
|
+ end Delegate;
|
|
|
|
+
|
|
|
|
+ procedure Start*(c: any; proc: procedure{DELEGATE});
|
|
|
|
+ end Start;
|
|
|
|
+
|
|
|
|
+ procedure Send*(p: any; value: longint);
|
|
|
|
+ end Send;
|
|
|
|
+
|
|
|
|
+ procedure Receive*(p: any; var value: longint);
|
|
|
|
+ end Receive;
|
|
|
|
+
|
|
|
|
+ end Context;
|
|
|
|
+
|
|
|
|
+ Launcher* = object
|
|
|
|
+ var
|
|
|
|
+ proc: procedure {DELEGATE};
|
|
|
|
+ context: Context;
|
|
|
|
+ finished: boolean;
|
|
|
|
+
|
|
|
|
+ procedure & Init*(context: Context);
|
|
|
|
+ begin
|
|
|
|
+ self.context := context;
|
|
|
|
+ proc := nil;
|
|
|
|
+ finished := false;
|
|
|
|
+ end Init;
|
|
|
|
+
|
|
|
|
+ procedure Start*(p: procedure{DELEGATE}; doWait: boolean);
|
|
|
|
+ begin{EXCLUSIVE}
|
|
|
|
+ proc := p;
|
|
|
|
+ await(~doWait or finished);
|
|
|
|
+ end Start;
|
|
|
|
+
|
|
|
|
+ begin{ACTIVE,EXCLUSIVE}
|
|
|
|
+ await(proc # nil);
|
|
|
|
+ proc;
|
|
|
|
+ finished := true;
|
|
|
|
+ end Launcher;
|
|
|
|
+
|
|
|
|
+ procedure GetContext(): Context;
|
|
|
|
+ begin
|
|
|
|
+ return Objects.ActiveObject()(Launcher).context;
|
|
|
|
+ end GetContext;
|
|
|
|
+
|
|
|
|
+ procedure AllocateOnContext(context: Context;scope: Cell; var c: Cell; tag: address; const name: array of char; isCellnet, isEngine: boolean);
|
|
|
|
+ var
|
|
|
|
+ a: any;
|
|
|
|
+ typeInfo: Modules.TypeDesc;
|
|
|
|
+ s, ac: any;
|
|
|
|
+ begin
|
|
|
|
+
|
|
|
|
+ (* allocation of cells must use the tag provided, it contains all internally stored metadata *)
|
|
|
|
+ Heaps.NewRec(a, tag, false);
|
|
|
|
+ system.get(tag-4,typeInfo);
|
|
|
|
+
|
|
|
|
+ if EnableTrace then trace(scope, c, typeInfo, name, isCellnet, isEngine); end;
|
|
|
|
+
|
|
|
|
+ if scope # nil then s := scope.c else s := nil end;
|
|
|
|
+ if c # nil then ac := c.c else ac := nil end;
|
|
|
|
+
|
|
|
|
+ c := a(Cell);
|
|
|
|
+ context.Allocate(s, ac, typeInfo, name, isCellnet, isEngine);
|
|
|
|
+ c.c := ac;
|
|
|
|
+ end AllocateOnContext;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ procedure Allocate*(scope: Cell; var c: Cell; tag: address; const name: array of char; isCellnet, isEngine: boolean);
|
|
|
|
+ begin
|
|
|
|
+ AllocateOnContext(GetContext(), scope, c, tag, name, isCellnet, isEngine);
|
|
|
|
+ end Allocate;
|
|
|
|
+
|
|
|
|
+ procedure AddPort*(c: Cell; var p: any; const name: array of char; inout: set; width: longint);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(c,p,name, inout, width); end;
|
|
|
|
+ GetContext().AddPort(c.c, p, name, inout, width);
|
|
|
|
+ end AddPort;
|
|
|
|
+
|
|
|
|
+ procedure AddPortArray*(c: Cell; var ports: any; const name: array of char; inout: set; width: longint; const lens: array of longint);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(name, inout, width, len(lens)); end;
|
|
|
|
+ GetContext().AddPortArray(c.c, ports, name, inout, width, lens);
|
|
|
|
+ end AddPortArray;
|
|
|
|
+
|
|
|
|
+ procedure AddStaticPortArray*(c: Cell; var ports: array of any; const name: array of char; inout: set; width: longint);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(name, inout, width, len(ports)); end;
|
|
|
|
+ GetContext().AddStaticPortArray(c.c, ports, name, inout, width);
|
|
|
|
+ end AddStaticPortArray;
|
|
|
|
+
|
|
|
|
+ procedure AddPortIntegerProperty*(p: any; const name: array of char; value: longint);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(p, name, value); end;
|
|
|
|
+ GetContext().AddPortIntegerProperty(p,name,value);
|
|
|
|
+ end AddPortIntegerProperty;
|
|
|
|
+
|
|
|
|
+ procedure AddFlagProperty*(c: Cell; const name: array of char);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(c, name); end;
|
|
|
|
+ GetContext().AddFlagProperty(c.c, name);
|
|
|
|
+ end AddFlagProperty;
|
|
|
|
+
|
|
|
|
+ procedure AddStringProperty*(c: Cell; const name: array of char; var newValue: array of char; const value: array of char);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(c, name, newValue, value); end;
|
|
|
|
+ copy(value, newValue);
|
|
|
|
+ GetContext().AddStringProperty(c.c, name, value);
|
|
|
|
+ end AddStringProperty;
|
|
|
|
+
|
|
|
|
+ procedure AddIntegerProperty*(c: Cell; const name: array of char; var newValue: longint; value: longint);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(c, name, newValue, value); end;
|
|
|
|
+ newValue := value;
|
|
|
|
+ GetContext().AddIntegerProperty(c.c, name, value);
|
|
|
|
+ end AddIntegerProperty;
|
|
|
|
+
|
|
|
|
+ procedure FinishedProperties*(c: Cell);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(c); end;
|
|
|
|
+ GetContext().FinishedProperties(c.c);
|
|
|
|
+ end FinishedProperties;
|
|
|
|
+
|
|
|
|
+ procedure Connect*(outPort, inPort: any; depth: longint);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(outPort, inPort, outPort, inPort, depth); end;
|
|
|
|
+ GetContext().Connect(outPort, inPort, depth);
|
|
|
|
+ end Connect;
|
|
|
|
+
|
|
|
|
+ procedure Delegate*(netPort: any; cellPort: any);
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(netPort, cellPort); end;
|
|
|
|
+ GetContext().Delegate(netPort, cellPort);
|
|
|
|
+ end Delegate;
|
|
|
|
+
|
|
|
|
+ procedure Start*(c: Cell; proc: procedure{DELEGATE});
|
|
|
|
+ begin
|
|
|
|
+ if EnableTrace then trace(c, proc); end;
|
|
|
|
+ GetContext().Start(c.c, proc);
|
|
|
|
+ end Start;
|
|
|
|
+
|
|
|
|
+ procedure Send*(p: any; value: longint);
|
|
|
|
+ begin
|
|
|
|
+ GetContext().Send(p, value);
|
|
|
|
+ end Send;
|
|
|
|
+
|
|
|
|
+ procedure Receive*(p: any; var value: longint);
|
|
|
|
+ begin
|
|
|
|
+ GetContext().Receive(p, value);
|
|
|
|
+ end Receive;
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ Module = pointer to record
|
|
|
|
+ next: Module;
|
|
|
|
+ checked, imports: boolean;
|
|
|
|
+ m: Modules.Module
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ procedure Find(root: Module; m: Modules.Module): Module;
|
|
|
|
+ begin
|
|
|
|
+ while (root # nil) & (root.m # m) do root := root.next end;
|
|
|
|
+ return root
|
|
|
|
+ end Find;
|
|
|
|
+
|
|
|
|
+ procedure Imports(root, m: Module; const name: array of char): boolean;
|
|
|
|
+ var i: longint;
|
|
|
|
+ begin
|
|
|
|
+ if ~m.checked then
|
|
|
|
+ if m.m.name # name then
|
|
|
|
+ i := 0;
|
|
|
|
+ while i # len(m.m.module) do
|
|
|
|
+ if (m.m.module[i].name = name) or Imports(root, Find(root, m.m.module[i]), name) then
|
|
|
|
+ m.imports := true; i := len(m.m.module)
|
|
|
|
+ else
|
|
|
|
+ inc(i)
|
|
|
|
+ end
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ m.imports := true
|
|
|
|
+ end;
|
|
|
|
+ m.checked := true
|
|
|
|
+ end;
|
|
|
|
+ return m.imports
|
|
|
|
+ end Imports;
|
|
|
|
+
|
|
|
|
+ (*! caution: this is not thread safe -- must be moved to Modules.Mod *)
|
|
|
|
+ procedure CopyModules(): Module;
|
|
|
|
+ var firstm, lastm, c: Module; m: Modules.Module;
|
|
|
|
+ begin
|
|
|
|
+ new(firstm); firstm.next := nil; lastm := firstm;
|
|
|
|
+ m := Modules.root;
|
|
|
|
+ while m # nil do
|
|
|
|
+ new(c); c.checked := false; c.imports := false; c.m := m;
|
|
|
|
+ c.next := nil; lastm.next := c; lastm := c;
|
|
|
|
+ m := m.next
|
|
|
|
+ end;
|
|
|
|
+ return firstm.next
|
|
|
|
+ end CopyModules;
|
|
|
|
+
|
|
|
|
+ procedure FreeDownTo(const modulename: array of char): longint;
|
|
|
|
+ var
|
|
|
|
+ root, m: Module; res: longint;
|
|
|
|
+ nbrOfUnloadedModules : longint;
|
|
|
|
+ msg: array 32 of char;
|
|
|
|
+ begin
|
|
|
|
+ nbrOfUnloadedModules := 0;
|
|
|
|
+ root := CopyModules();
|
|
|
|
+ m := root;
|
|
|
|
+ while m # nil do
|
|
|
|
+ if Imports(root, m, modulename) then
|
|
|
|
+ Modules.FreeModule(m.m.name, res, msg);
|
|
|
|
+ if res # 0 then
|
|
|
|
+ (*context.error.String(msg);*)
|
|
|
|
+ else
|
|
|
|
+ inc(nbrOfUnloadedModules);
|
|
|
|
+ end
|
|
|
|
+ end;
|
|
|
|
+ m := m.next
|
|
|
|
+ end;
|
|
|
|
+ return nbrOfUnloadedModules;
|
|
|
|
+ end FreeDownTo;
|
|
|
|
+
|
|
|
|
+ procedure Execute*( const cellNet: array of char; context: Context; diagnostics: Diagnostics.Diagnostics);
|
|
|
|
+ type
|
|
|
|
+ StartProc = procedure{DELEGATE}();
|
|
|
|
+
|
|
|
|
+ Starter = object
|
|
|
|
+ var
|
|
|
|
+ p: StartProc;
|
|
|
|
+ c: Cell;
|
|
|
|
+
|
|
|
|
+ procedure & InitStarter(proc: address; scope: Cell);
|
|
|
|
+ var startProcDesc: record proc: address; selfParam: address; end;
|
|
|
|
+ begin
|
|
|
|
+ startProcDesc.proc := proc;
|
|
|
|
+ startProcDesc.selfParam := scope;
|
|
|
|
+ system.move(address of startProcDesc, address of p, 2 * size of address);
|
|
|
|
+ c := scope;
|
|
|
|
+ end InitStarter;
|
|
|
|
+
|
|
|
|
+ procedure P;
|
|
|
|
+ begin
|
|
|
|
+ Start(c, p)
|
|
|
|
+ end P;
|
|
|
|
+ end Starter
|
|
|
|
+
|
|
|
|
+ var
|
|
|
|
+ moduleName, typeName: array 256 of char;
|
|
|
|
+ m: Modules.Module;
|
|
|
|
+ typeInfo: Modules.TypeDesc;
|
|
|
|
+ i, res: longint;
|
|
|
|
+ str: array 256 of char;
|
|
|
|
+ scope: Cell;
|
|
|
|
+ unloaded: longint;
|
|
|
|
+ starter: Starter;
|
|
|
|
+ launcher: Launcher;
|
|
|
|
+ begin
|
|
|
|
+ i := Strings.IndexOfByte2(".",cellNet);
|
|
|
|
+ if i = -1 then
|
|
|
|
+ diagnostics.Error("",Diagnostics.Invalid,Diagnostics.Invalid, "cellNet malformed");
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ Strings.Copy(cellNet,0,i,moduleName);
|
|
|
|
+ Strings.Copy(cellNet,i+1,Strings.Length(cellNet)-Strings.Length(moduleName),typeName);
|
|
|
|
+
|
|
|
|
+ unloaded := FreeDownTo(moduleName);
|
|
|
|
+ if unloaded > 0 then
|
|
|
|
+ (*param.ctx.Information("", Diagnostics.Invalid,Diagnostics.Invalid,"unloaded " & unloaded & " modules")*)
|
|
|
|
+ end;
|
|
|
|
+ m := Modules.ThisModule(moduleName,res,str);
|
|
|
|
+
|
|
|
|
+ if m = nil then
|
|
|
|
+ (*
|
|
|
|
+ param.ctx.Error("",Diagnostics.Invalid,HdlBackend.ErrNotFound,'failed to load module "' & moduleName & '"');
|
|
|
|
+ *)
|
|
|
|
+ end;
|
|
|
|
+ typeInfo := Modules.ThisType(m,typeName);
|
|
|
|
+ if typeInfo = nil then
|
|
|
|
+ (*
|
|
|
|
+ param.ctx.Error("",Diagnostics.Invalid,HdlBackend.ErrNotFound,'failed to find cellnet type "' & param.architectureName & '" in module "' & moduleName & '"');
|
|
|
|
+ return nil;
|
|
|
|
+ *)
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ assert(len(typeInfo.procedures) = 1);
|
|
|
|
+ assert(typeInfo.procedures[0].name^ = "@Body");
|
|
|
|
+
|
|
|
|
+ (* allocate the top level cellnet *)
|
|
|
|
+ AllocateOnContext(context, nil,scope,typeInfo.tag,typeName,true,false);
|
|
|
|
+ assert(scope # nil);
|
|
|
|
+ assert(scope.c # nil);
|
|
|
|
+
|
|
|
|
+ new(starter, typeInfo.procedures[0].address, scope);
|
|
|
|
+ new(launcher, context);
|
|
|
|
+ launcher.Start(starter.P, true);
|
|
|
|
+ end Execute;
|
|
|
|
+
|
|
|
|
+end ActiveCellsRuntime.
|
|
|
|
+
|