123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310open!ImportopenSignalopen!Recipe_intftypevar=inttypeinp=Signal.t*Signal.t(* enable * value *)moduleVMap=Map.Make(Int)typeenv={freshId:var;writerInps:inplistVMap.t;outs:Signal.tVMap.t;clock:Signal.t;enable:Signal.t}type'at=Recipeof(Signal.t->env->Signal.t*env*'a)includeMonad.Make(structtypenonrec'at='atletreturna=Recipe(funstartenv->start,env,a)letbind(Recipem)~f=Recipe(funstartenv->letfin0,env0,a=mstartenvinlet(Recipef)=fainletfin1,env1,b=ffin0env0infin1,env1,b);;letmap=`Define_using_bindend)letdelay~env~clear_tod=letclock=env.clockinletenable=env.enableinreg(Reg_spec.override(Reg_spec.create()~clock)~clear_to)~enabled;;letdelay_with_enable~env~clear_to~enabled=letclock=env.clockinreg(Reg_spec.override(Reg_spec.create()~clock)~clear_to)~enabled;;letdelayFb~clock~enable~clear_tof=reg_fb(Reg_spec.override(Reg_spec.create()~clock)~clear_to)~enable~w:(widthclear_to)f;;letsetReset~clock~enablesr=delayFb~clock~enable~clear_to:gnd(funq->s|:q&:~:r);;letskip=Recipe(funstartenv->delay~env~clear_to:gndstart--"skip_fin",env,());;letrecwait=function|0->return()|n->skip>>=fun_->wait(n-1);;letgen_par_fin~clock~enable~comb_finfin'fin=letfin=setReset~clock~enablefin'fininifcomb_finthenfin'|:finelsefin;;letpar2?(comb_fin=true)(Recipep)(Recipeq)=Recipe(funstartenv->letfin0,env0,a=pstartenvinletfin1,env1,b=qstartenv0inletfin=wire1infin<==(gen_par_fin~clock:env.clock~enable:env.enable~comb_finfin0fin&:gen_par_fin~clock:env.clock~enable:env.enable~comb_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=rstartenvinfin::finl,env,a::al)inletpar_fin=wire1--"par_fin"inletpar_fin=reduce~f:(&:)(List.mapfinl~f:(funfin'->gen_par_fin~clock:env.clock~enable:env.enable~comb_finfin'par_fin))inpar_fin,env,List.reval);;letcondc(Recipep)(Recipeq)=Recipe(funstartenv->letfin0,_,_=p(start&:c)envinletfin1,env1,_=q(start&:~:c)envin(fin0|:fin1)--"cond_fin",env1,());;letiterc(Recipep)=Recipe(funstartenv->letready=wire1--"iter_ready"inletfin,env',b=p((c&:ready)--"iter_start")envinready<==(start|:fin);(~:c&:ready)--"iter_fin",env',b);;letforeverp=itervddpletwait_whilea=iteraskipletwait_untila=iter~:askipletfollow~clock~enablestart(Reciper)=letinitialEnv={freshId=0;writerInps=VMap.empty;outs=VMap.empty;enable;clock}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<==delay_with_enable~env~clear_to:(zero(widtho))~enablevaluewith|_->(* 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,a;;letcreateVarenva=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};;letnew_var?namen=Recipe(funstartenv->letout=matchnamewith|None->wiren|Somex->wiren--xinletv,env'=createVarenvoutinstart,env',v);;letread_varv=Recipe(funstartenv->start,env,Map.find_exnenv.outsv)letassignal=Recipe(funstartenv->letal'=List.mapal~f:(fun(a,b)->a,[start,b])indelay~env~clear_to:gndstart,addInpsenval',());;letwrite_varva=assign[v,a]letmodify_varfv=read_varv>>=funa->write_varv(fa)letrewrite_varfvw=read_varv>>=funa->write_varw(fa)moduletypeSame=Samewithtypevar:=varwithtype'arecipe:='atmoduleSame(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))letapply~fa=rewritefaaletsetab=rewrite(fun_->b)aaletif_fa~then_~else_=reada>>=funb->cond(fb)then_else_letwhile_fa~do_=reada>>=funb->iter(fb)do_letnew_var()=letmkvarnbl=new_var~name:("new_var_"^n)b>>=funv->return((n,v)::l)inletrecfml=matchm,lwith|None,[]->failwith"Same.new_var: 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.equalwith|Not_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;fb;;letiter2(a,b)(c,d)~f=fac;fbd;;letmap(a,b)~f=fa,fbletmap2(a,b)(c,d)~f=fac,fbdletto_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;fc;;letiter2(a,b,c)(d,e,f)~f:fn=fnad;fnbe;fncf;;letmap(a,b,c)~f=fa,fb,fcletmap2(a,b,c)(d,e,f)~f:fn=fnad,fnbe,fncfletto_list(a,b,c)=[a;b;c]end)