[Tex/LaTex] High level digital design in TikZ

labelspositioningtikz-pgf

I am very new to TikZ and I have trouble making a diagram similar to the one here:

enter image description here

My problems are specifically making MUX to get to inputs which would be on 1/3 and 2/3 of the width. Taking sigma signal outside of the border while still being above and to the right from the X block. Making all the lines bend with 90% to get to the final nodes. Adding the dX labels next to the operators.

My current code is:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{positioning,intersections,shapes.geometric,fit,arrows,decorations.shapes,decorations.markings}

\begin{document}
\tikzstyle{register} = [rectangle, draw, text centered]
\tikzstyle{multiplexor} = [rectangle, draw, text centered, minimum width = 4em, minimum height = 2em]
\tikzstyle{operation} = [circle, draw, text centered, minimum size=3em]
\tikzstyle{port} = [pin edge={to->,thin,black}]

\begin{tikzpicture}[node distance = 5em, auto]

    \node (mux)     [multiplexor] {MUX};
    \node (delay)   [register, on grid, below of = mux] {Delay};
    \node (add_one) [operation, right of = mux] {$+1$};
    \node (mult)    [operation, on grid, below right of = add_one] {$\times$};
    \node (exp)     [operation, below of = mult] {$\exp$};
    \node (xmin)    [port, above of =  mux, xshift=-1em] {$x_{min}$};
    \node (sigma)   [port, above of = border, above right of = mult] {$sigma$};
    \node (addr)    [port, below of = border, below of = delay] {$address$};
    \node (data)    [port, below of = border, below of = mult] {$data$};

    \node (border) [draw,  dashed,inner sep=3pt,fit = (xmin) (exp)] {}; 

    \draw [->] (sigma)  |-  (mult);
    \draw [->] (xmin)   ->  ([xshift=-2em] mux);
    \draw [->] (add_one) -> (mux);
    \draw [->]  (mux) -> (delay);
    \draw [->] (mux) |- (add_one);
    \draw [->] (add_one) |- (mult);
    \draw [->] (delay) -> (addr);
    \draw [->] (mult) -> (exp);
    \draw [->] (exp) -> (data);

\end{tikzpicture}
\end{document}

which outputs:

enter image description here

Any help would be appreciated.

Best Answer

For these kinds of drawings I'd first inspect which is the most convenient way to locate nodes: you positioned manually the nodes, but in this case I think the matrix library and consequently to position the nodes in a matrix fashion is really convenient.

But let's start first with the styles:

\tikzset{multiplexor/.style={rectangle, draw, align=center, minimum width = 6em, minimum height = 3em}}
\tikzset{register/.style={multiplexor,fill=gray!30}}
\tikzset{operation/.style={circle, draw, align=center, minimum size=3em}}
\tikzset{port/.style={pin edge={to->,thin,black}}}

\tikzset{matrix aspect/.style={matrix of nodes, nodes={outer sep=0pt,inner sep=3pt},column sep=3em,row sep=5ex}}

The first four are more or less yours styles (some differences are: changed a bit the dimensions, used the same base for multiplexor and register and convert \tikzstyle into \tikzset as per Should \tikzset or \tikzstyle be used to define TikZ styles?). The fifth style, instead, concerns the matrix aspect: remember to load the library with \usetikzlibrary{matrix}.

The matrix is the following:

\begin{tikzpicture}[every label/.style={font=\scriptsize}]
\matrix(dig-scheme) [matrix aspect]{
|[multiplexor]|MUX & |[operation]|$+1$ & \\
|[register]|Delay  &                                 & |[operation]|$\times$\\
                   &                                 & |[operation]|exp\\};
\end{tikzpicture}

Consider that with the option matrix of nodes each element has automatically a name in the form: matrix name - row number - column number. Each element, then inherits its own style with the syntax |[style]| and it is possible to omit each time \node{---}; again thanks to the option matrix of nodes.

Now, to locate the labels dx, where x is a,m,e, it is possible to exploit labels: in this case they are positioned with an angle of 10 degrees out of the node; if you want them exactly on the right, use the key right.

The label position phase goes like:

\foreach \name/\place in {da/1-2,dm/2-3,de/3-3}
\node[minimum size=2.5em,label={10:\name}] at (dig-scheme-\place){};

To reduce the labels' font size, in the option of the tikzpicture there's a way to set it in \scriptsize.

Until now, the diagram looks more or less like:

enter image description here

Before starting to connect the elements, I'd go to box the matrix: since its aspect has already been set within the style matrix aspect, the box can be introduced there without changing the picture's code.

\tikzset{matrix aspect/.style={
  matrix of nodes,   
  column sep=3em,
  row sep=5ex,
  draw,
  loosely dashed,
  inner xsep=2em,
  inner ysep=10ex,
  nodes={outer sep=0pt,inner sep=3pt,solid},
  }
}

The new options are:

  • draw: obvious;
  • loosely dashed: to customize the border aspect;
  • inner xsep=2em,inner ysep=10ex: to customize in a different way the horizontal and vertical distance of the matrix border from its content;
  • solid otherwise the internal elements of the matrix will inherit the dashed option.

The result is:

enter image description here

Let's pass now to depict the connections. They require the calc library, so load it.

I'd start with x_min:

\draw[<-] ($(dig-scheme-1-1.north west)!0.3!(dig-scheme-1-1.north east)$)
 --++(0,1) coordinate[label=above:$x_{\min}$];

This is saying that the starting point is the position of the element 1-1 of the matrix placed at 1/3 (from left to right -> north west to north east) going up for 1 cm from there. The text is written through the "label syntax" such that no sort of customization on the font size should be done since it has already been done before with every label/.style={font=\scriptsize}.

Instead, to connect the multiplexer with the element on his right, the following style is needed:

% adapted code from Azetina:
% https://tex.stackexchange.com/questions/76060/combine-two-tikzmark-solutions
\tikzset{square arrow/.style={to path={-- ++(0,1) -| (\tikztotarget)}}}

while the actual connection is:

\draw[<-,square arrow] ($(dig-scheme-1-1.north east)!0.3!(dig-scheme-1-1.north west)$)to (dig-scheme-1-2);

To get exactly the point, 2/3 from left to right, I just inverted the anchors of the multiplexer in the previous connection.

Now it looks:

enter image description here

Proceeding a bit faster, to locate the x and then connect this midway point to the +1 node, one could do:

\draw[->] (dig-scheme-1-1)--(dig-scheme-2-1) node[coordinate,midway,label={left:$x$}](x){};
\draw[->] (x) -| (dig-scheme-1-2) node[coordinate,inner sep=0pt, pos=0.45](y){};

Notice the (y) is the other midway point; with:

\draw[->] (y) |- (dig-scheme-2-3);
\draw[->] (dig-scheme-2-3)--(dig-scheme-3-3);
\draw[->] (dig-scheme-3-3)--($(dig-scheme-3-3 |- dig-scheme.south east)-(0,1)$) coordinate[label=below:data];

it is possible to connect it to \times node and to set also the connection from \times to exp and from exp to the bottom adding the label data. Notice the syntax:

($(dig-scheme-3-3 |- dig-scheme.south east)-(0,1)$)

This says that the final point is computed as the intersection of the element and the south east anchor of the matrix; after that, it is shifted down by 1cm.

Another important thing to be highlighted is that both "middle" points are defined through node[coordinate,...,]: this is because coordinates do not introduce additional space (for a more detailed explanation see TikZ: difference between \node and \coordinate?).

enter image description here

Replicating this concept to:

\draw[->] (dig-scheme-2-1)--($(dig-scheme-2-1 |- dig-scheme.south west)-(0,1)$) coordinate[label=below:address];

allows to have both data and address on the same level.

Finally, we missed just sigma:

\draw[<-] (dig-scheme-2-3.east) -| ($(dig-scheme-2-3.east |- dig-scheme.north east)+(0.5,1)$) coordinate[label=above:sigma];

This is similar to what did before, but we need some horizontal space, the 0.5 to have exactly the connection desired.

BTW: just realize that we need some more horizontal space between the matrix content and border, so the inner xsep=2em should become inner xsep=3em.

enter image description here

The complete code for reference:

\documentclass[tikz,png,border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,matrix}

\tikzset{multiplexor/.style={rectangle, draw, align=center, minimum width = 6em, minimum height = 3em}}
\tikzset{register/.style={multiplexor,fill=gray!30}}
\tikzset{operation/.style={circle, draw, align=center, minimum size=3em,outer sep=0pt}}
\tikzset{port/.style={pin edge={to->,thin,black}}}

% code from Azetina:
% https://tex.stackexchange.com/questions/76060/combine-two-tikzmark-solutions
\tikzset{square arrow/.style={to path={-- ++(0,1) -| (\tikztotarget)}}}

\tikzset{matrix aspect/.style={
  matrix of nodes,   
  column sep=3em,
  row sep=5ex,
  draw,
  loosely dashed,
  inner xsep=3em,
  inner ysep=10ex,
  nodes={outer sep=0pt,inner sep=3pt,solid},
  }
}

\begin{document}
\begin{tikzpicture}[every label/.style={font=\scriptsize},>=stealth]
\matrix(dig-scheme) [matrix aspect]{
|[multiplexor]|MUX & |[operation]|$+1$ & \\
|[register]|Delay  &                                 & |[operation]|$\times$\\
                   &                                 & |[operation]|exp\\};
\foreach \name/\place in {da/1-2,dm/2-3,de/3-3}
\node[minimum size=2.5em,label={10:\name}] at (dig-scheme-\place){};

\draw[<-] ($(dig-scheme-1-1.north west)!0.3!(dig-scheme-1-1.north east)$)
 --++(0,1) coordinate[label=above:$x_{\min}$];
\draw[<-,square arrow] ($(dig-scheme-1-1.north east)!0.3!(dig-scheme-1-1.north west)$)to (dig-scheme-1-2);

\draw[->] (dig-scheme-1-1)--(dig-scheme-2-1) node[coordinate,midway,label={left:$x$}](x){};
\draw[->] (x) -| (dig-scheme-1-2) node[coordinate,inner sep=0pt, pos=0.45](y){};
\draw[->] (y) |- (dig-scheme-2-3);
\draw[->] (dig-scheme-2-3)--(dig-scheme-3-3);
\draw[->] (dig-scheme-3-3)--($(dig-scheme-3-3 |- dig-scheme.south east)-(0,1)$) coordinate[label=below:data];

\draw[->] (dig-scheme-2-1)--($(dig-scheme-2-1 |- dig-scheme.south west)-(0,1)$) coordinate[label=below:address];

\draw[<-] (dig-scheme-2-3.east) -| ($(dig-scheme-2-3.east |- dig-scheme.north east)+(0.5,1)$) coordinate[label=above:sigma];
\end{tikzpicture}
\end{document}
Related Question