[Tex/LaTex] Block diagrams in TikZ: Is there a simpler way to draw the block diagram

tikz-pgf

I have justed started using TikZ and this block diagram was my first piece of art. Why art? Because it took me ages and I have had the feeling that drawing this kind of diagram could be simplified greatly if I had a deeper understanding of TikZ.
Could you help me out to find a way to simplify this diagram or to find a suitable library?

Basically, it is a block diagram of a digital circuit, which describes the basic building blocks of that circuit. (If you are wondering what this circuit is used for, please refer to: https://github.com/Xilinx/XilinxVirtualCable, which is a project with a similiar goal).

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows,positioning, calc}
\begin{document}

\begin{figure}
\centering
\begin{tikzpicture}
\def\frow{2.5}
\def\rrow{2.7}
\def\srow{5}
\def\brow{6.5}
\def\trow{8}  

\tiny
\tikzset{
bignode/.style={rectangle,draw=black, top color=white, inner    sep=1em,minimum width=1.75cm, minimum height=4.0cm, text centered},
mynode/.style={rectangle,draw=black, top color=white, inner sep=1em,minimum width=1.5cm, minimum height=1cm, text centered},
ifnode/.style={rectangle,dashed,draw=black, top color=white, inner sep=1em,minimum width=1.5cm, minimum height=1cm, text centered, fill=yellow},
fifonode/.style={rectangle,draw=black, top color=white, inner sep=1pt,minimum width=0.9cm, minimum height=0.4cm, text centered},
regnode/.style={rectangle,draw=black, top color=white, inner sep=1pt,minimum width=1.2cm, minimum height=0.4cm, text centered},
sarrow/.style={->, >=latex'},
carrow/.style={<->, >=latex', dashed},
branch/.style={fill,circle,minimum size=2pt,inner sep=0pt},
acaption/.style={below, midway, text width=1cm, align=center}
 }
%\draw[help lines] (0,0) grid (10,6);
\node (axi) at (0.5,4.25) {AXI Bus};
\node[bignode, label=above:AXI IF] (axiif) at (\frow,2.5) {};
\node[regnode] (datareg) at (\rrow,4.25) {Data};
\node[regnode] (statusreg) at (\rrow,3.8) {Status}; 
\node[regnode] (controlreg) at (\rrow,3.35) {Control};  

\node[ifnode, label=above:IF IN] (ifin) at (\srow,1) {};
\node[fifonode] (tdofifo) at (\srow+0.25,1.25) {FIFO};
\node[mynode, label=above:IF TIMER] (iftimer) at (\srow,2.5) {};
\node[ifnode, label=above:IF OUT] (ifout) at (\srow,4) {};
\node[fifonode] (tmsfifo) at (\srow+0.25,4.25) {FIFO};
\node[fifonode] (tdififo) at (\srow+0.25,3.75) {FIFO};

\node[mynode, label=above:TMS Serializer] (tmsser) at (\trow,4.75) {};
\node[mynode, label=above:TDI Serializer] (tdiser) at (\trow,3.25) {};
\node[mynode, label=above:TDO Deserializer] (tdodeser) at (\trow,1) {};


\draw [sarrow] (tmsfifo.east) |- ++(right:0.5) |- node[above] {Data} ($ (tmsser.west)+(0,0.25) $);
\draw [sarrow] ($(tmsser.east)+(0,0.25)$) -- ++(right:1.25) node [right]{TMS};
\draw [sarrow] (tdififo.east) |- ++(right:0.5) |- node[below] {Data} ($ (tdiser.west)+(0,0.25) $);
\draw [sarrow] ($(tdiser.east)+(0,0.25)$) -- ++(right:1.25) node [right]{TDI};
\draw [sarrow, <-] (tdofifo.east) -| ++(right:0.5) |- node[below] {Data} ($ (tdodeser.west)+(0,0.25) $);
\draw [sarrow, <-] ($(tdodeser.east)+(0,0.25)$) -- ++(right:1.25) node [right]{TDO};
\draw [sarrow] ($(iftimer.east)+(0,-0.25)$) -- ++(right:4.25) node [right]{TCK};


\draw[sarrow] (iftimer.east) -- ++(right:0.5) node[above] {Timing} -- ++(right:0.5) node [branch](timer_branch){} -- ++(up:0.75) node [branch](timer_branch2){} -- (tdiser.west);
\draw[sarrow] (timer_branch) |- (tdodeser.west);
\draw[sarrow] (timer_branch2) |- (tmsser.west);

\draw[sarrow, <->] (datareg.east) -- ++(right:0.5) node [branch](datab){} -- ++(right:0.7) node [branch](datab2){} -- (tmsfifo.west);
\draw[sarrow] (datab2) |- (tdififo.west);
\draw[sarrow] (datab) |- (tdofifo.west);

\draw[sarrow] (axi) -- ++(right:1.25) node [branch] (axib) {} -- ++(down:0.45) node [branch] (axib2) {} -- (statusreg.west);
\draw[sarrow] (axib) -- (datareg.west);
\draw[sarrow] (axib2) |-  (controlreg.west);

\draw[carrow] (iftimer.west) -- (axiif.east) node [acaption] {Control/ Status};
\draw[carrow] (ifin.west) -- ($(axiif.east)+(0,-1.5)$) node [acaption] {Control/ Status};
\draw[carrow] (ifout.west) -- ($(axiif.east)+(0,1.5)$) node [acaption] {Control/ Status};

\end{tikzpicture} 
\medskip
\caption{AXI-JTAG Peripheral} 
\end{figure}

\end{document}

Best Answer

Actually that's a very good code. I changed some things:

  • Since arrows is deprecated, I added arrows.meta instead. Unfortunately, latex' and stealth' are not available so I switched to the most similar arrow which is >={Stealth}. You're free to keep using arrows, which is available along with arrows.spaced for compatibility but they're considered deprecated.

  • I placed your tikzset in the preamble. This is not required, it's just my personal preference since I find it to be more organized:

    Settings and options -> Preamble
    Actual code -> Document

    I also usually draw first all the nodes, then all the edges. This is for better readability, but it's still personal preference.

  • Since most of your nodes had rectangle,draw=black, top color=white,text centered repeated in each node style, I added another style called basic with these options. Then if you write basic in the other node styles, all these options will be included, with the difference that now you don't have overcrowded style options. See code for this.

  • The little black circles specified as

     branch/.style={fill,circle,minimum size=2pt,inner sep=0pt},
    

    created a white space around them:

    enter image description here

    This is due to the fact that you didn't set the outer sep which is positive by default. If you set it to 0, there's still space, but if you set it to -1pt, then:

    enter image description here

    By the way, if you say inner/outer sep=0, you don't need to specify pt, cm,ex,em and so on. Just 0 will do.

I don't think there are other things, maybe I could fix the spacing in Control/Status - let me know, your code was very well written, especially if it was your first.

Output

enter image description here

Code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, positioning, calc}

\tikzset{
    basic/.style={rectangle,draw=black, top color=white,text centered},
    bignode/.style={basic, inner sep=1em,minimum width=1.75cm, minimum height=4.0cm},
    mynode/.style={basic, inner sep=1em,minimum width=1.5cm, minimum height=1cm},
    ifnode/.style={basic,dashed, inner sep=1em,minimum width=1.5cm, minimum height=1cm, fill=yellow},
    fifonode/.style={basic, inner sep=1pt,minimum width=0.9cm, minimum height=0.4cm},
    regnode/.style={basic, inner sep=1pt,minimum width=1.2cm, minimum height=0.4cm},
    sarrow/.style={->, >={Stealth}},
    carrow/.style={<->, >={Stealth}, dashed},
    branch/.style={fill,circle,minimum size=2pt,outer sep=-1pt,inner sep=0pt},
    acaption/.style={below, midway, text width=1cm, align=center}
    }

\begin{document}
\begin{figure}
\centering
\begin{tikzpicture}\tiny
\def\frow{2.5}
\def\rrow{2.7}
\def\srow{5}
\def\brow{6.5}
\def\trow{8}  

%\draw[help lines] (0,0) grid (10,6);
\node (axi) at (0.5,4.25) {AXI Bus};
\node[bignode, label=above:AXI IF] (axiif) at (\frow,2.5) {};
\node[regnode] (datareg) at (\rrow,4.25) {Data};
\node[regnode] (statusreg) at (\rrow,3.8) {Status}; 
\node[regnode] (controlreg) at (\rrow,3.35) {Control};  

\node[ifnode, label=above:IF IN] (ifin) at (\srow,1) {};
\node[fifonode] (tdofifo) at (\srow+0.25,1.25) {FIFO};
\node[mynode, label=above:IF TIMER] (iftimer) at (\srow,2.5) {};
\node[ifnode, label=above:IF OUT] (ifout) at (\srow,4) {};
\node[fifonode] (tmsfifo) at (\srow+0.25,4.25) {FIFO};
\node[fifonode] (tdififo) at (\srow+0.25,3.75) {FIFO};

\node[mynode, label=above:TMS Serializer] (tmsser) at (\trow,4.75) {};
\node[mynode, label=above:TDI Serializer] (tdiser) at (\trow,3.25) {};
\node[mynode, label=above:TDO Deserializer] (tdodeser) at (\trow,1) {};


\draw [sarrow] (tmsfifo.east) |- ++(right:0.5) |- node[above] {Data} ($ (tmsser.west)+(0,0.25) $);
\draw [sarrow] ($(tmsser.east)+(0,0.25)$) -- ++(right:1.25) node [right]{TMS};
\draw [sarrow] (tdififo.east) |- ++(right:0.5) |- node[below] {Data} ($ (tdiser.west)+(0,0.25) $);
\draw [sarrow] ($(tdiser.east)+(0,0.25)$) -- ++(right:1.25) node [right]{TDI};
\draw [sarrow, <-] (tdofifo.east) -| ++(right:0.5) |- node[below] {Data} ($ (tdodeser.west)+(0,0.25) $);
\draw [sarrow, <-] ($(tdodeser.east)+(0,0.25)$) -- ++(right:1.25) node [right]{TDO};
\draw [sarrow] ($(iftimer.east)+(0,-0.25)$) -- ++(right:4.25) node [right]{TCK};


\draw[sarrow] (iftimer.east) -- ++(right:0.5) node[above] {Timing} -- ++(right:0.5) node [branch](timer_branch){} -- ++(up:0.75) node [branch](timer_branch2){} -- (tdiser.west);
\draw[sarrow] (timer_branch) |- (tdodeser.west);
\draw[sarrow] (timer_branch2) |- (tmsser.west);

\draw[sarrow, <->] (datareg.east) -- ++(right:0.5) node [branch](datab){} -- ++(right:0.7) node [branch](datab2){} -- (tmsfifo.west);
\draw[sarrow] (datab2) |- (tdififo.west);
\draw[sarrow] (datab) |- (tdofifo.west);

\draw[sarrow] (axi) -- ++(right:1.25) node [branch] (axib) {} -- ++(down:0.45) node [branch] (axib2) {} -- (statusreg.west);
\draw[sarrow] (axib) -- (datareg.west);
\draw[sarrow] (axib2) |-  (controlreg.west);

\draw[carrow] (iftimer.west) -- (axiif.east) node [acaption] {Control/ Status};
\draw[carrow] (ifin.west) -- ($(axiif.east)+(0,-1.5)$) node [acaption] {Control/ Status};
\draw[carrow] (ifout.west) -- ($(axiif.east)+(0,1.5)$) node [acaption] {Control/ Status};

\end{tikzpicture} 
\medskip
\caption{AXI-JTAG Peripheral} 
\end{figure}
\end{document}