123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229open!ImportopenSignalopen!Recipe_intfletclock=input"clock"1letenable=input"enable"1typevar=inttypeinp=Signal.t*Signal.t(* enable * value *)moduleVMap=Map.Make(Int)typeenv={freshId:var;writerInps:inplistVMap.t;outs:Signal.tVMap.t}type'arecipe=Recipeof(Signal.t->env->(Signal.t*env*'a))letdelayclear_tod=reg(Reg_spec.override(Reg_spec.create()~clock:clock)~clear_to)~enabledletdelayEnclear_toenabled=reg(Reg_spec.override(Reg_spec.create()~clock:clock)~clear_to)~enabledletdelayFbclear_tof=reg_fb(Reg_spec.override(Reg_spec.create()~clock:clock)~clear_to)~enable~w:(widthclear_to)fletsetResetsr=delayFbgnd(funq->(s|:q)&:(~:r))moduleMonad=structletreturna=Recipe(funstartenv->(start,env,a))letbind(Recipem)f=Recipe(funstartenv->let(fin0,env0,a)=mstartenvinletRecipef=fainlet(fin1,env1,b)=ffin0env0in(fin1,env1,b))let(>>=)=bindlet(>>)mf=bindm(fun_->f)endopenMonadletskip=Recipe(funstartenv->(delaygndstart)--"skip_fin",env,())letrecwait=function|0->return()|n->skip>>wait(n-1)letgen_par_fincomb_finfin'fin=letfin=setResetfin'fininifcomb_finthenfin'|:finelsefinletpar2?(comb_fin=true)(Recipep)(Recipeq)=Recipe(funstartenv->let(fin0,env0,a)=pstartenvinlet(fin1,env1,b)=qstartenv0inletfin=wire1infin<==(gen_par_fincomb_finfin0fin&:gen_par_fincomb_finfin1fin);(fin,env1,(a,b)))let(|||)pq=par2~comb_fin:truepqletpar?(comb_fin=true)r=Recipe(funstartenv->letfinl,env,al=List.foldr~init:([],env,[])~f:(fun(finl,env,al)(Reciper)->letfin,env,a=rstartenvin(fin::finl,env,a::al))inletfin=wire1--"par_fin"infin<==reduce~f:(&:)(List.mapfinl~f:(funfin'->gen_par_fincomb_finfin'fin));(fin,env,List.reval))letcondc(Recipep)(Recipeq)=Recipe(funstartenv->let(fin0,_,_)=p(start&:c)envinlet(fin1,env1,_)=q(start&:(~:c))envin((fin0|:fin1)--"cond_fin",env1,()))letiterc(Recipep)=Recipe(funstartenv->letready=wire1--"iter_ready"inlet(fin,env',b)=p((c&:ready)--"iter_start")envinready<==(start|:fin);(((~:c)&:ready)--"iter_fin",env',b))letforeverp=itervddpletwaitWhilea=iteraskipletwaitUntila=iter(~:a)skipletfollowstart(Reciper)=letinitialEnv={freshId=0;writerInps=VMap.empty;outs=VMap.empty}inletfin,env,a=rstartinitialEnvin(* connect writerInps to outs *)Map.iterienv.outs~f:(fun~key:v~data:o->tryletinps=Map.find_exnenv.writerInpsvinletenable=reduce~f:(|:)(List.mapinps~f:fst)inletvalue=reduce~f:(|:)(List.mapinps~f:(fun(e,v)->mux2ev(zero(widthv))))ino<==(delayEn(zero(widtho))enablevalue)with_->(* this can lead to combinatorial loops, so perhaps an exception would be better
*)printf"unassigned var; defaulting to zero\n";o<==(zero(widtho))(* unassigned variable *));fin,aletcreateVarenva=letv=env.freshIdinv,{envwithfreshId=v+1;outs=Map.setenv.outs~key:v~data:a}letofListal=List.foldal~init:VMap.empty~f:(funm(k,v)->Map.setm~key:k~data:v)letaddInpsenval=letmerge~key:_=function|`Lefta|`Righta->Somea|`Both(a,b)->Some(a@b)in{envwithwriterInps=Map.merge(ofListal)env.writerInps~f:merge}letnewVar?namen=Recipe(funstartenv->letout=matchnamewithNone->wiren|Somex->(wiren)--xinletv,env'=createVarenvoutin(start,env',v))letreadVarv=Recipe(funstartenv->(start,env,Map.find_exnenv.outsv))letassignal=Recipe(funstartenv->letal'=List.mapal~f:(fun(a,b)->a,[start,b])in(delaygndstart,addInpsenval',()))letwriteVarva=assign[v,a]letmodifyVarfv=readVarv>>=funa->writeVarv(fa)letrewriteVarfvw=readVarv>>=funa->writeVarw(fa)moduletypeSame=Samewithtypevar:=varwithtype'arecipe:='arecipemoduleSame(X:Interface.Pre)=structtype'asame='aX.tletsmap~ft=X.map~ftletszipxy=X.(to_list(map2~f:(funab->a,b)xy))letreada=Recipe(funstartenv->(start,env,smap~f:(funa->Map.find_exnenv.outsa)a))letrewritefab=reada>>=funx->assign(szipb(fx))letapplyfa=rewritefaaletsetab=rewrite(fun_->b)aaletiftefapq=reada>>=funb->cond(fb)pqletwhile_fap=reada>>=funb->iter(fb)pletnewVar()=letmkvarnbl=newVar~name:("newVar_"^n)b>>=funv->return((n,v)::l)inletrecfml=matchm,lwith|None,[]->failwith"Same.newVar: no elements"|None,(n,b)::t->f(Some(mkvarnb[]))t|Somem,(n,b)::t->f(Some(m>>=mkvarnb))t|Somem,[]->minletm=fNoneX.(to_listt)inm>>=funl->return(X.map~f:(fun(n,_)->tryList.Assoc.find_exnln~equal:String.equalwithNot_found_s_|Caml.Not_found->failwith("Not_found "^n))X.t)endmoduleSVar=Same(structtype'at='a[@@derivingsexp_of]lett="var",0letitera~f=faletiter2ab~f=fabletmapa~f=faletmap2ab~f=fabletto_lista=[a]end)(* not so sure these are particularly useful; interfaces can do the job better *)moduleSList=Same(structtype'at='alist[@@derivingsexp_of]lett=[]letiterl~f=List.iterl~fletiter2l0l1~f=List.iter2_exnl0l1~fletmapl~f=List.mapl~fletmap2l0l1~f=List.map2_exnl0l1~fletto_lista=aend)moduleSArray=Same(structtype'at='aarray[@@derivingsexp_of]lett=[||]letitert~f=Array.itert~fletiter2t1t2~f=Array.iter2_exnt1t2~fletmapa~f=Array.mapa~fletmap2ab~f=Array.init(Array.lengtha)~f:(funi->fa.(i)b.(i))letto_list=Array.to_listend)moduleSTuple2=Same(structtype'at='a*'a[@@derivingsexp_of]lett=("a",0),("b",0)letiter(a,b)~f=fa;fbletiter2(a,b)(c,d)~f=fac;fbdletmap(a,b)~f=(fa,fb)letmap2(a,b)(c,d)~f=(fac,fbd)letto_list(a,b)=[a;b]end)moduleSTuple3=Same(structtype'at='a*'a*'a[@@derivingsexp_of]lett=("a",0),("b",0),("c",0)letiter(a,b,c)~f=fa;fb;fcletiter2(a,b,c)(d,e,f)~f:fn=fnad;fnbe;fncfletmap(a,b,c)~f=(fa,fb,fc)letmap2(a,b,c)(d,e,f)~f:fn=(fnad,fnbe,fncf)letto_list(a,b,c)=[a;b;c]end)