Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file graph.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292open!ImportopenPrintfopenSignal(* write a DOT file with rank information - looks absolutely terrible *)letwrite_dot_rankchancircuit=(* {[
let get_name signal =
(* {[
match names signal with
| [] -> "_" ^ Int64.to_string (uid signal)
| h :: t -> h
]} *)
Int64.to_string (uid signal)
in
]} *)letoutputs=List.fold(Circuit.outputscircuit)~init:(Set.empty(moduleUid))~f:(funsetsignal->Set.addset(uidsignal))in(* create a suitable fan-out mapping *)letfdepss=matchswith|Mem_->[List.hd_exn(depss)]|Reg_->[List.hd_exn(depss)]|_->depssinletfan_out=Signal_graph.fan_out_map~deps:fdeps(Circuit.signal_graphcircuit)inletfind_fan_outsignal=matchMap.findfan_outsignalwith|None->[]|Somes->Set.to_listsinletuidsl=List.mapl~f:uidin(* We start at the inputs, and traverse forward to the outputs, effectively using depth
first search. *)letrecdfsvisitedrankssignals=matchsignalswith|[]->ranks|_->(* add these signals to the visited set *)letvisited=List.foldsignals~init:visited~f:(funsetsignal->Set.addsetsignal)in(* find fan_out from this level *)letsignals=List.concat(List.mapsignals~f:(funsignal->find_fan_outsignal))in(* filter out already visited signals, and outputs *)letsignals=List.filtersignals~f:(funsignal->(not(Set.memvisitedsignal))&¬(Set.memoutputssignal))in(* create set of uids of nodes at this rank *)letrank=List.foldsignals~init:(Set.empty(moduleUid))~f:(funsetsignal->Set.addsetsignal)inifSet.is_emptyrankthenrankselsedfsvisited(rank::ranks)signalsinletranks=dfs(Set.empty(moduleUid))[](Circuit.inputscircuit|>uids)|>List.map~f:Set.to_listin(* create the output level and add it to the ranks *)letranks=List.map(Circuit.outputscircuit)~f:(funs->uids)::ranks|>List.revinletnranks=List.lengthranksin(* write the bit to the left *)fprintfchan"digraph %s {\n"(Circuit.namecircuit);fori=0tonranks-1dofprintfchan"%i"i;ifi<>nranks-1thenfprintfchan" -> "done;fprintfchan"\n";List.iteriranks~f:(funis->fprintfchan" { rank=same; %i [shape=plaintext];\n"i;List.iters~f:(funs->fprintfchan" _%Li;\n"s);fprintfchan"}\n");(* write edges *)Signal_graph.iter(Circuit.signal_graphcircuit)~f:(funs->List.iter(fdepss)~f:(fund->fprintfchan"_%Li -> _%Li;\n"(uidd)(uids)));fprintfchan"}\n";;(* GDL file with manhatten layout - looks much, much nicer *)letwrite_gdl?(names=false)?(widths=false)?(consts=true)?(clocks=false)chancircuit=letquotes="\""^s^"\""infprintfchan"graph: {\n";letprops=["title",quote(Circuit.namecircuit);"manhattenedges","yes";"inportsharing","no";"outportsharing","yes";"node.bordercolor","lightblue"]inletprops=ifwidthsthen("display_edge_labels","yes")::propselsepropsin(* write list of default attributes *)List.iterprops~f:(fun(a,b)->fprintfchan"%s: %s\n"ab);letfoldscs=List.folds~init:""~f:(funsn->ifString.is_emptysthennelsen^c^s)inletnames=letnames=Signal.namessinmatchnameswith|[]->""|[h]->h|h::t->h^" ("^folds","t^")"inletwrite_node?(border="invisible")?(shape="box")?(label="")?(bordercolour="")?(colour="")?(textcolour="")signal=fprintfchan"node: { title: \"%Li\" "(uidsignal);letname=ifString.is_emptylabel||namesthennamesignalelse""in(matchlabel,namewith|"",""->fprintfchan"label: \"none\" "|_,""->fprintfchan"label: \"%s\" "label|"",_->fprintfchan"label: \"\\fI%s\" "name|_->fprintfchan"label: \"%s\\n\\fI%s\" "labelname);fprintfchan"shape: %s "shape;fprintfchan"borderstyle: %s "border;ifnot(String.is_emptytextcolour)thenfprintfchan"textcolor: %s "textcolour;ifnot(String.is_emptybordercolour)thenfprintfchan"bordercolor: %s "bordercolour;ifnot(String.is_emptycolour)thenfprintfchan"color: %s "colour;fprintfchan" }\n"inletis_roms=matchswith|Op(_,Signal_mux)->List.fold(List.tl_exn(depss))~init:true~f:(funbs->b&&is_consts)|_->falseinletreg_depss=matchswith|Reg(_,r)->(ifclocksthen[r.reg_clock]else[])@[List.hd_exn(depss);r.reg_enable]|_->[]inletmem_depss=matchswith|Mem(_,_,r,m)->[List.hd_exn(depss);r.reg_enable;m.mem_read_address;m.mem_write_address]|Multiport_mem(_,_,write_ports)->Array.mapwrite_ports~f:(funwr->[wr.write_clock;wr.write_enable;wr.write_address;wr.write_data])|>Array.to_list|>List.concat|_->[]inletis_inputs=Circuit.is_inputcircuitsinletis_outputs=Circuit.is_outputcircuitsin(* write nodes *)letwrite_nodes=matchswith|Empty->write_node~label:"empty"s|Const(_,c)->write_node~label:(Bits.to_constantc|>Constant.to_hex_string~signedness:Unsigned)s|Wire_->ifList.is_empty(Signal.namess)thenwrite_node~textcolour:"lightgrey"~label:"wire"selseifis_inputsthenwrite_node~textcolour:"red"selseifis_outputsthenwrite_node~textcolour:"red"selsewrite_node~textcolour:"lightgrey"s|Select(_,hi,lo)->write_node~textcolour:"lightgrey"~label:(sprintf"[%i:%i]"hilo)s|Op(_,op)->(matchopwith|Signal_add->write_node~border:"solid"~shape:"circle"~label:"+"s|Signal_sub->write_node~border:"solid"~shape:"circle"~label:"-"s|Signal_mulu->write_node~border:"solid"~shape:"circle"~label:"*"s|Signal_muls->write_node~border:"solid"~shape:"circle"~label:"*+"s|Signal_and->write_node~border:"solid"~shape:"circle"~label:"&"s|Signal_or->write_node~border:"solid"~shape:"circle"~label:"|"s|Signal_xor->write_node~border:"solid"~shape:"circle"~label:"^"s|Signal_eq->write_node~border:"solid"~shape:"circle"~label:"="s|Signal_not->write_node~border:"solid"~shape:"circle"~label:"~"s|Signal_lt->write_node~border:"solid"~shape:"circle"~label:"<"s|Signal_cat->write_node~border:"solid"~shape:"trapeze"~label:"cat"s|Signal_mux->ifis_romsthen(letels=List.length(depss)-1inwrite_node~border:"solid"~shape:"box"~label:(sprintf"rom%i"els)s)elsewrite_node~border:"solid"~shape:"uptrapeze"~label:"mux"s)|Reg_->write_node~bordercolour:"lightblue"~textcolour:"white"~colour:"black"~border:"solid"~label:"reg"s|Mem(_,_,_,m)->write_node~bordercolour:"lightblue"~textcolour:"white"~colour:"black"~border:"solid"~label:(sprintf"mem%i"m.mem_size)s|Multiport_mem(_,mem_size,_)->write_node~bordercolour:"lightblue"~textcolour:"white"~colour:"black"~border:"solid"~label:(sprintf"mem%i"mem_size)s|Mem_read_port_->write_node~bordercolour:"lightblue"~textcolour:"white"~colour:"black"~border:"solid"~label:"mem_rdp"s|Inst(_,_,i)->write_node~border:"solid"~label:(sprintf"inst\n%s"i.inst_name)sin(* specialised dependancies *)letdepss=ifis_romsthen[List.hd_exn(depss)]elseifis_regsthenreg_depsselseifis_memsthenmem_depsselsedepssin(* write edges *)letwrite_edges()=Signal_graph.depth_first_search(Circuit.signal_graphcircuit)~init:(Set.empty(moduleUid))~f_before:(funas->letdeps=depss|>List.filter~f:(funt->not(is_emptyt))inletdeps=ifconststhendepselsedeps|>List.filter~f:(funs->not(is_consts))inif(not(List.is_emptydeps))&¬(is_emptys)then(List.iterdeps~f:(fund->(* Note; labels always specified, even if they are disabled *)fprintfchan"edge: { source: \"%Li\" target: \"%Li\" "(uidd)(uids);if(is_wires&¬(is_outputs))||is_selectsthenfprintfchan"arrowstyle: none ";fprintfchan"color:lightgrey thickness: 1 label: \"%i\" }\n"(widthd));List.fold(s::deps)~init:a~f:(funas->Set.adda(uids)))elsea)inletnodes=write_edges()inSet.iternodes~f:(funu->write_node(Circuit.find_signal_exncircuitu));fprintfchan"}\n";;letaisee3?(args="")?(names=false)?(widths=false)?(consts=true)?(clocks=false)circuit=letname,file=Filename.open_temp_file"aisee3"".gdl"inwrite_gdl~names~widths~consts~clocksfilecircuit;Out_channel.closefile;ignore(Unix.open_process_in("aisee3 "^name^" "^args):Stdio.In_channel.t);;