library simulation_comm; import 'dart:isolate'; import 'dart:convert'; typedef DartInterpreter configure(bool disabledEdges, bool disableOutputLogic); bool _disableEdges; bool _disableOutputLogic; Map provider={}; const bool DEBUG=false; const bool DEBUG_RUN=false; class GlobalState { static GlobalState gs; ///The interpreter that is used DartInterpreter di; ///The values of the ports as last seen Map prevValues; ///A list of ports that are monitored Set subscribedPorts; ///Cached version of the description Map Map descMap; Description desc; SendPort send; GlobalState(this.di, this.send) { prevValues={}; subscribedPorts=new Set(); desc=di.description; descMap=desc.map; gs=this; } void sendAssert(int assertIdx, String msg) { send.send(Request.sendAssert(assertIdx, msg)); } void sendString(String str){ send.send(Request.string(str)); } } /** * Called from the isolate. It handles all the message dispatching etc. */ void handleReceive(configure config, SendPort send){ GlobalState gs=new GlobalState(config(false, false),send); gs.di.initConstants(); ReceivePort port = new ReceivePort(); send.send(Request.getSimpleRequest(Request.SENDPORT, port.sendPort)); port.listen((Map map){ try { if (DEBUG && map[Request.TYPE]!=Request.GET_DELTA_CYCLE) gs.sendString("Received: $map"); switch (map[Request.TYPE]) { case Request.GETSTATE: var values=new List(); for (int i=0;i remove=[]; provider.forEach((k,StimuliProvider v){ if (v.isConstantBeyond(gs.di.deltaCycle)){ remove.add(k); if (DEBUG) gs.sendString("Removing provider for idx:$k"); } }); remove.forEach((k)=>provider.remove(k)); } void runUntilChange(GlobalState gs, SendPort send) { Map res; var sw = new Stopwatch()..start(); do { res=_doRun(gs); } while(res.isEmpty && sw.elapsedMilliseconds<200); res[-1]=gs.di.deltaCycle; send.send(Request.getSimpleRequest(Request.PORT_STAT,res)); } void runTimed(GlobalState gs, SendPort send) { Map> res={}; var sw = new Stopwatch()..start(); do { var tmp=_doRun(gs); tmp.forEach((k, v){ var map = res[k]; if (map==null) map=res[k]={}; map[gs.di.deltaCycle]=v; }); } while(sw.elapsedMilliseconds<200); send.send(Request.getSimpleRequest(Request.PORT_STAT_RECORD,res)); } void run(GlobalState gs, SendPort send) { var res = _doRun(gs); res[-1]=gs.di.deltaCycle; send.send(Request.getSimpleRequest(Request.PORT_STAT, res)); } void setState(Map subMap, DartInterpreter interpreter) { subMap.forEach((idx,val){ provider.remove(idx); interpreter.setVar(idx, val); }); } Map _doRun(GlobalState gs) { var interpreter=gs.di; int dc=interpreter.deltaCycle; if (DEBUG_RUN) gs.sendString("Running dc: $dc"); provider.forEach((_, StimuliProvider p)=>p.setData(interpreter, dc)); interpreter.run(); Map response={}; gs.subscribedPorts.forEach((idx){ var newVal=interpreter.getVar(idx); var prev = gs.prevValues[idx]; if (prev!=newVal){ response[idx]=newVal; gs.prevValues[idx]=newVal; } }); if (DEBUG_RUN) gs.sendString("Sending response from run $response"); return response; } abstract class DartInterpreter { void run(); void initConstants(); String getName(int idx); int getIndex(String name); dynamic getVar(int idx, {int offset}); void setVar(int idx, dynamic value, {int offset}); int get deltaCycle; int get varNum; bool disableEdges; bool disableRegOutputLogic; Description get description; List ASSERTS=["FATAL", "ERROR", "WARNING", "INFO"]; void pshdl_assertThat_bool_EAssert_s(bool assumption, int assertIdx, String msg){ if (!assumption){ GlobalState.gs.sendString(ASSERTS[assertIdx]+": "+msg); if (assertIdx < 2){ GlobalState.gs.sendAssert(assertIdx, msg); } } } } class Request { /** * Returns a [Description] as Map */ static const int DESCRIBE=1; /** * Returns a [List] with all values of all variables */ static const int GETSTATE=DESCRIBE+1; /** * Returns a [List] with all values of all variables */ static const int SETSTATE=GETSTATE+1; /** * Invokes the [DartInterpreter.run()] method and returns a map of all changed * outputs. An output is a variable with direction IN or direction INOUT. * The key of the map is the idx and the value the new value of the variable. */ static const int RUN=SETSTATE+1; /** * Invokes the [DartInterpreter.run()] method until a change of an output port occurs. */ static const int RUN_UNITL_CHANGE=RUN+1; /** * Invokes the [DartInterpreter.run()] method until a change of an output port occurs. */ static const int RUN_TIMED=RUN_UNITL_CHANGE+1; /** * Takes a [Map] of all variable indicies and their new value. After setting * the new values, a run is performed as with [Request.RUN] */ static const int SETSTATE_RUN=RUN_TIMED+1; /** * Takes a [Map] of all variable indicies and their new value. After setting * the new values, a run is performed as with [Request.RUN_UNITL_CHANGE] */ static const int SETSTATE_RUN_UNITL_CHANGE=SETSTATE_RUN+1; /** * Takes a [Map] of all variable indicies and their new value. After setting * the new values, a run is performed as with [Request.RUN_TIMED] */ static const int SETSTATE_RUN_TIMED=SETSTATE_RUN_UNITL_CHANGE+1; /** * Closes the port */ static const int CLOSE=SETSTATE_RUN_TIMED+1; /** * Creates a new instance of the [DartInterpreter] with the config given in the map. * The following properties can be set: * * [Request.DISABLE_EDGE] for disabling the edge detection * * [Request.DISABLE_OUTPUTLOGIC] for disabling the combinatorial logic after the register */ static const int CONFIGURE=CLOSE+1; /** * Retrieves the current Delta cycle */ static const int GET_DELTA_CYCLE=CONFIGURE+1; static const int CONFIGURE_PROVIDER=GET_DELTA_CYCLE+1; /* * When send as request, it contains a List of idx vor the value. When used as reply * it is a mapping of idx -> value of variables that changed. The delta cycle is encoded in -1 */ static const int PORT_STAT=CONFIGURE_PROVIDER+1; /* * Reply for a Map of idx -> dc -> value */ static const int PORT_STAT_RECORD=PORT_STAT+1; static const int SENDPORT=PORT_STAT_RECORD+1; static const int MESSAGE=SENDPORT+1; static const int TYPE=MESSAGE+1; ///A list of indexes that are monitored static const int SUBSCRIBE_PORTS=TYPE+1; static const int ASSERT=SUBSCRIBE_PORTS+1; static const String DISABLE_EDGE='disableEdge'; static const String DISABLE_OUTPUTLOGIC='disableOutputLogic'; static const String PROVIDER_TYPE="providerType"; static const int PROVIDER_TYPE_CLOCK=0; ///When true, a 1 will be used when disabledEdge static const String PROVIDER_TYPE_CLOCK_POSEDGE="providerClockPosEdge"; static const int PROVIDER_TYPE_PULSE=1; static const String PROVIDER_TYPE_PULSE_DURATION="providerPulseDuration"; static const String PROVIDER_TYPE_PULSE_PEAK="providerPulsePeak"; static const String PROVIDER_TYPE_PULSE_REST="providerPulseRest"; static const String PROVIDER_IDX="providerIdx"; static const String PROVIDER_ARGS="providerArgs"; static Map getIntMap(int req, dynamic val){ return {req:val}; } static Map getSimpleRequest(int req, dynamic val){ var map={}; map[TYPE]=req; if (val!=null) map[req]=val; return map; } static Map string(String val){ return getSimpleRequest(MESSAGE, val); } static Map sendAssert(int assertLevel, String msg){ return getSimpleRequest(ASSERT, msg); } static Map getConfigureRequest(bool disableEdges, bool disableOutputLogic){ return {DISABLE_EDGE: disableEdges, DISABLE_OUTPUTLOGIC: disableOutputLogic}; } static Map getProviderRequest(int type, int idx, Map args){ var map={}; map[PROVIDER_TYPE]=type; map[PROVIDER_IDX]=idx; map[PROVIDER_ARGS]=args; return map; } static Map getPulseProviderArgs(int peak, int rest, int duration){ var map={}; map[PROVIDER_TYPE_PULSE_PEAK]=peak; map[PROVIDER_TYPE_PULSE_REST]=rest; map[PROVIDER_TYPE_PULSE_DURATION]=duration; return map; } static Map getClockProviderArgs(bool posEdge){ var map={}; map[PROVIDER_TYPE_CLOCK_POSEDGE]=posEdge; return map; } } class Port{ final String name; final int width; final bool clock; final bool reset; final int idx; static const int TYPE_BIT=0; static const int TYPE_INT=1; static const int TYPE_UINT=2; static const int TYPE_BOOL=3; static const int TYPE_STRING=4; static const int TYPE_ENUM=5; final int type; List dimensions=[]; String get idName => name.replaceAll('\.', ''); Port(this.idx, this.name, this.width, this.type, {this.clock:false, this.reset:false, this.dimensions}); Port.fromMap(Map map): this.idx=map['idx'], this.type=map['type'], this.name=map['name'], this.width=map['width'], this.clock=map['clock'], this.reset=map['reset']; Map get map => {'idx':idx, 'name':name, 'width':width, 'clock':clock, 'reset':reset, 'type':type }; toString() => map; } class Description { String moduleName; List inPorts; List inOutPorts; List outPorts; List internalPorts; Map nameIdx={}; Description(this.inPorts, this.inOutPorts, this.outPorts, this.internalPorts, this.nameIdx, this.moduleName); Description.fromMap(Map map) : this.moduleName=map['moduleName'], this.inPorts=map['inPorts'].map((Map p)=>new Port.fromMap(p)).toList(), this.inOutPorts=map['inOutPorts'].map((Map p)=>new Port.fromMap(p)).toList(), this.outPorts=map['outPorts'].map((Map p)=>new Port.fromMap(p)).toList(), this.internalPorts=map['internalPorts'].map((Map p)=>new Port.fromMap(p)).toList(), this.nameIdx=map['nameIdx']; Map get map => { 'inPorts':inPorts.map((p)=>p.map).toList(), 'inOutPorts':inOutPorts.map((p)=>p.map).toList(), 'outPorts':outPorts.map((p)=>p.map).toList(), 'internalPorts':internalPorts.map((p)=>p.map).toList(), 'nameIdx':nameIdx, 'moduleName': moduleName }; Map get reverseIdxMap { var res={}; nameIdx.forEach((k,v){ res[v]=k; }); return res; } toString() => JSON.encode(map); } abstract class StimuliProvider { bool isConstantBeyond(int deltaCycle); void setData(DartInterpreter di, int deltaCycle); } class ToggleProvider implements StimuliProvider { final int idx; final int duration; final int firstVal; final int secondVal; bool first=false; ToggleProvider(this.idx, this.duration, this.firstVal, this.secondVal); void setData(DartInterpreter di, int deltaCycle) { if (deltaCycle%duration == 0) first=!first; di.setVar(idx, first?firstVal:secondVal); } bool isConstantBeyond(int deltaCycle) => false; } class ClockProvider implements StimuliProvider { final int idx; final bool posEdge; bool runOnce=false; ClockProvider(this.idx, this.posEdge); void setData(DartInterpreter di, int deltaCycle) { runOnce=true; if (_disableEdges) { var val = posEdge?1:0; di.setVar(idx, val); } else di.setVar(idx, deltaCycle&1); } bool isConstantBeyond(int deltaCycle) { return false; } } class PulseProvider implements StimuliProvider { final int idx; final int duration; final int peak; final int rest; final int startCycle; PulseProvider(this.idx, this.startCycle, this.duration, this.peak, this.rest); void setData(DartInterpreter di, int deltaCycle) { if ((deltaCycle-startCycle)>=duration) { di.setVar(idx,rest); }else { di.setVar(idx,peak); } } bool isConstantBeyond(int deltaCycle) { return (deltaCycle-startCycle)>duration; } }