High level digital design in TikZ
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:
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:
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:
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?).
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
.
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}
Only a partial answer: getting the "1/3" and "2/3" anchors is tricky as things stand, but, if you don't mind hacking (and I would like to encourage it), it is fairly straightforward to add anchors to the rectangle shape.
Hopefully it is obvious what must be changed to rename the anchors to something more catchy.
\documentclass{standalone}
\usepackage{tikz}
\makeatletter
\expandafter\def\csname pgf@anchor@rectangle@one third north west\endcsname{%
% The \southwest and \northeast macros are automatically defined.
% We need to set \pgf@x and \pgf@y (which are both TeX dimensions)
% to the approriate coordinates for the anchor.
%
% For the X coordinate this is simply 2/3*SW_X + 1/3*NE_X,
% (where SW_X is the X coordinate of the south west point and
% NE_X is the coordinate of the north west point).
%
% The Y coordinate is provided by the \northeast macro.
%
\pgf@process{\southwest}%
\pgf@xa=0.66666\pgf@x%
\pgf@process{\northeast}%
\pgf@x=0.33333\pgf@x
\advance\pgf@x by\pgf@xa
}
\expandafter\def\csname pgf@anchor@rectangle@one third north east\endcsname{%
% Similar to above except the X coordinate is 1/3*SW_X + 2/3*NE_X.
\pgf@process{\southwest}%
\pgf@xa=0.33333\pgf@x%
\pgf@process{\northeast}%
\pgf@x=0.66666\pgf@x%
\advance\pgf@x by\pgf@xa
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw [help lines] grid (3, 2);
\node [draw, shape=rectangle, minimum width=3cm] at (1.5,1)(rectangle) {A rectangle};
\draw [->] (0,1.75) -| (rectangle.one third north west);
\draw [->] (3,1.75) -| (rectangle.one third north east);
\end{tikzpicture}
\end{document}
I should also add a caveat: if you set the outer xsep
to something large this will mess up the positioning. But! With more hacking (a bit more involved this time), we can take this into account (the result is the same as before).
\documentclass{standalone}
\usepackage{tikz}
\makeatletter
\expandafter\def\csname pgf@anchor@rectangle@one third north west\endcsname{%
\pgf@process{\southwest}%
% Add the outer xsep
\advance\pgf@x by\outerxsep\relax%
\pgf@xa=0.66666\pgf@x%
\pgf@process{\northeast}%
% Subtract the outer xsep
\advance\pgf@x by-\outerxsep\relax%
\pgf@x=0.33333\pgf@x
\advance\pgf@x by\pgf@xa
}
\expandafter\def\csname pgf@anchor@rectangle@one third north east\endcsname{%
% Similar to above except the X coordinate is 1/3*SW_X + 2/3*NE_X.
\pgf@process{\southwest}%
% Add the outer xsep
\advance\pgf@x by\outerxsep\relax%
\pgf@xa=0.33333\pgf@x%
\pgf@process{\northeast}%
% Subtract the outer xsep
\advance\pgf@x by-\outerxsep\relax%
\pgf@x=0.66666\pgf@x%
\advance\pgf@x by\pgf@xa
}
\pgfutil@g@addto@macro\pgf@sh@s@rectangle{\pgf@sh@resaveddimen{\outerxsep}{\pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/outer xsep}}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw [help lines] grid (3, 2);
\node [draw, shape=rectangle, minimum width=3cm, outer xsep=1cm] at (1.5,1)(rectangle) {A rectangle};
\draw [->] (0,1.75) -| (rectangle.one third north west);
\draw [->] (3,1.75) -| (rectangle.one third north east);
\end{tikzpicture}
\end{document}