You are on page 1of 9

Reading VHDL 7 Datapaths

Here we shall consider the construction of the data-paths in our CPU, those bits
which will compute our desired function or process.

1. DataPath 1 The Humble Register.


A CPU datapath consists of ALUs, MUXes, and Registers. We have seen VHDL code
for a MUX already. Code for an ALU is straightforward, but the behaviour and code
for a register may cause you a little trouble. So lets first investigate how a reg works
in isolation. Heres the symbol for a register

clear
load
clock

D
Q

The register is memory and at any time will hold a value. Whatever value is in the
register appears at the output Q. (By the way think of all datapaths as 8-bit). How do
you get a value into the register? Via the input D (also 8 bits). But this value does not
just get directly in. In other words, the registers contents (and its output) may be
different from the value waiting to get input at D. So how does this value waiting
actually get in? It has to be clocked in by the clock signal. And it will only get in if
the signal load is high on a low-to-high transition of the clock signal. Like this:

clock

load

Data input to reg now

Lets have a look at the VHDL code for a register:

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

entity reg is
port ( clock :
clear :
load :
D
:
Q
:
end reg;

in std_logic;
in std_logic;
in std_logic;
in std_logic_vector( 7 downto 0);
out std_logic_vector( 7 downto 0));

architecture Behavioural of reg is


begin
process (clock,clear,load)
begin
if clear = '1' then Q <="00000000";
elsif (rising_edge(clock)) then
if load = '1' then Q <= D;
end if;
end if;
end process;
end Behavioural;

Lines 12-18 define the input and output signals. First the three single bit control
inputs, then the 8-bit data bus D in. Finally the 8-bit output bus Q. The architecture
code defines how the reg behaves. Line 25 implements the clear function, setting
the output bits to zero. Then we test for a rising edge of the clock in line 26and if
there is a rising clock then if load = 1 (line 27) then we set Q equal to D, ie the data
is passed from the input to the output. Interestingly we have not explicitly stored the
value in an internal variable. We use Q to remember this value for us.
Load up and inspect the VHDL. Make a synthesis, then apply a test waveform. Heres
one I used:

2. DataPath 3 A simple Adder


Lets attack a simple computational problem. We must design some hardware to do
the following: We are given a number A and we must process this number as
follows:
A=A+3

That means we wish to add 3 to the number A, and perhaps output the result. We may
need to do this many times. So what do we need?
1.
2.
3.
4.
5.

A register to hold the value of A


An ALU to do the addition
The constant 3 to add
A way of feeding back the previous result into a new calculation.
An output from our machine.

Following out discussions in class, youll agree that the following architecture is
required:

clear
load
clock

D
Reg A
Q

reg2alu

const

Y
ALU
Z
alu2reg

Signals marked with a


blob are inputs and
outputs to the datapath

output

There is a register Reg A which stores number A. The ALU does the add 3stuff
and theres an output signal.
Note that there are three inputs to this datapath: The clear, load and clock signals
into the register which define its behaviour. And there is one output output from the
datapath. Note there is no data. The register can be cleared to 0 using its clear input
signal.
How does this circuit work? Well say we assert the clear signal on the reg. This will
set its contents to 00000000, which will appear directly on its output. It will go
immediately into the alu which will sum 0 with 3, and 3 will appear immediately at
the output of the alu. This is fed back into the regs input, but will not go straight in.
Remember the reg only accepts an input when (i) the load signal is high (1) and (ii)
there is a low-to-high clock transition. When these signals are aswserted then the 3 is
loaded and stored, and immediately appears at the output of the reg where it falls once
more into the alu to be summed with 3 to give 6 and so on.

Lets now analyze the VHDL code to synthesize this CPU. Well take a top-down
approach, starting from the datapath description, and bottoming out at the individual
components.

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

--------------- now define the whole datapath ---------------------library ieee;


use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity datapath is
port ( clock,load,clear : in std_logic;
output : out std_logic_vector (7 downto 0));
end datapath;
architecture Structural of datapath is
component alu
port ( X : in std_logic_vector (7 downto 0);
Y : in std_logic_vector (7 downto 0);
Z : out std_logic_vector (7 downto 0));
end component;
component reg
port ( clock,load,clear : in std_logic;
D : in std_logic_vector (7 downto 0);
Q : out std_logic_vector (7 downto 0));
end component;
signal reg2alu : std_logic_vector (7 downto 0);
signal alu2reg : std_logic_vector (7 downto 0);
signal const : std_logic_vector (7 downto 0);
begin
const <= "00000011";
U0: reg port map(clock,load,clear,alu2reg,reg2alu);
U1: alu port map(reg2alu,const,alu2reg);
output <= alu2reg;
end Structural;

So whats going on here? Well lines 63-66 define the inputs and outputs to the whole
datapath (shown as blobs in the schematic). There are (i) the clock, load and store
signals needed by the register, and (ii) the output of the datapath. (This is an 8-bit bus
as you can see by reading line 65). Then line 68 says that we are dealing with a
structural description or architecture we are specifying in this code, which
functional blocks are connected to each other, and with which signals. There then
follow a series of component declarations. These are the functional blocks which
make up our datapath, the register and the alu. Each component declares the port (ie
inputs and outputs) for that component. This agrees with the corresponding port
description in each components entity code, which well see in a bit.
Lines 82-84 declare the connection wires or buses between our components. Such as
the reg2alu bus which sends the output of the register to the input of the ALU. And
the alu2reg signal bus feeds the output of the ALU back into the register. The third
signal is just the constant (3) input into the ALU.

Lines 86-93 define the working of the whole datapath. First we assign the value 3
to const in line 88.
But the wiring-up of the components, their interconnection, is defined in lines 9091. First we take the register. You must read line 90 while keeping an eye on lines 7779. The latter tell us that reg expects input signals clock, load, clear, an input value
on bus D. And the reg will output a value on bus Q. Line 90 says that the regs
clock load and clear are assigned to the datapaths clock load and clear. Also that
the input value D is actually the datapath alu2reg (check out the schematic!).
Finally, that the Q output is assigned to the datapath reg2alu.
In other words, we have specified to the reg which input and output signals
correspond to those it expects.
Similarly in line 91 we have specified how the alu is connected; it gets its inputs from
the signal reg2alu, and const and sends it output to alu2reg which feeds back
into the register.
Now lets go up a level to the specification of the components of the datapath. Well
take one example, the ALU. Heres the VHDL code for the ALU:

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

------------------- first define the ALU-----------------------entity alu is


port ( X : in std_logic_vector (7 downto 0);
Y : in std_logic_vector (7 downto 0);
Z : out std_logic_vector (7 downto 0));
end alu;
architecture Behavioural of alu is
begin
process(X,Y)
begin
Z <= X+Y;
end process;
end Behavioural;

There are two sections, entity and architecture . The architecture is simple - we
merely add the two inputs X and Y! Note that X and Y appear as arguments to the
function process(). This allows process to recalculate the value of Z whenever X and
Y change this is concurrent processing.
How can we test the code? Using ModelSim. But we have to generate the input
control signals. We need a clock, some loads and a clear. And we should arrange for
at least two additions to be made. Heres a testbench waveform I constructed. Note
the end tome 3000ns. Loads of clocks, and the first signal to go high is clear. Note

low the load signals are positioned with respect to the rising edges of the clocks.
Loads are stable high during these clock transitions.

3. DataPath 4 A more complex CPU


Lets now turn to a more complex CPU datapath. We shall now have (i) data coming
into the circuit, and (ii) an ALU which can execute four functions. Heres the circuit:

input const

muxSel
mux2alu

Y
ALU

alu0
alu1

Z
reg2alu
alu2reg

clear
load
clock

Reg A

output

First lets define the ALU function. Well there are four possible functions we shall
use, each selected by one of the four combinations of the two alu signals alu0 and
alu1:
alu1
0
0
1
1

alu0
0
1
0
1

function
passthrough
X +Y
X OR Y
X AND Y

The register is unchanged from the previous example. The mux has two inputs in0
and in1 and we shall agree to fix things so that when muxSel = 0 then in0 is
selected and so forth.
What can this datapath do? Im not certain! Certainly more than the previous one.
This is one question for you to answer. But first, lets glance at the VHDL. Again we
shall start with the top-level, the structural code where we connect various bits
together:

81 entity datapath is
82
port ( clock,load,clear : in std_logic;
83
muxSel : in std_logic;
84
aluSel : in std_logic_vector (1 downto 0);
85
input : in std_logic_vector (7 downto 0);
86
output : out std_logic_vector (7 downto 0));
87 end datapath;
88
89 architecture Structural of datapath is
90
91 component alu
92
port ( aluSel : in std_logic_vector (1 downto 0);
93
X : in std_logic_vector (7 downto 0);
94
Y : in std_logic_vector (7 downto 0);
95
Z : out std_logic_vector (7 downto 0));
96 end component;
97
98 component reg
99
port ( clock,load,clear : in std_logic;
100
D : in std_logic_vector (7 downto 0);
101
Q : out std_logic_vector (7 downto 0));
102 end component;
103
104 component mux
105 port ( sel : in std_logic;
106
in0 : in std_logic_vector (7 downto 0);
107
in1 : in std_logic_vector (7 downto 0);
108
opt : out std_logic_vector (7 downto 0));
109 end component;
110
111---------------------- Now Build the datapath ------------112
113 signal mux2alu : std_logic_vector (7 downto 0);
114 signal alu2reg : std_logic_vector (7 downto 0);
115 signal reg2alu : std_logic_vector (7 downto 0);
116 signal const
: std_logic_vector (7 downto 0);
117
118
begin
119
const <= "00000001";
110
U0: mux port map(muxSel,input,const);
111
U1: alu port map(aluSel,mux2alu,reg2alu,alu2reg);
112
U2: reg port map(clock,load,clear,alu2reg,reg2alu);
113
114
output <= reg2alu;
115
116 end Structural;

First input and output signals to the datapath. These are defined in lines 82-86 where
we see the usual reg control signals. But we also have a muxSel (mux selector) and a

pair of alu select signals (note this is a 2-bit logic vector). We also have an 8-bit input
bus and an 8-bit output bus.
Signals interconnecting the various components are defined in lines 113-116 where
the naming is fairly obvious (thanks to a little inspiration). The actual interconnecting
is done in lines 120-122 where these interconnect signals are used. The complete
structure should now be clear.
Lets turn to the ALU code and inspect this:

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

entity alu is
port ( aluSel : in std_logic_vector (1 downto 0);
X : in std_logic_vector (7 downto 0);
Y : in std_logic_vector (7 downto 0);
Z : out std_logic_vector (7 downto 0));
end alu;
architecture Behavioural of alu is
begin
process(aluSel, X,Y)
begin
case aluSel is
when "00" => Z <= X;
when "01" => Z <= X + Y;
when "10" => Z <= X OR Y;
when others => Z <= X AND B;
end case;
end process;
end Behavioural;

The port() statement in lines 14-17 defines signals coming in and out of the ALU.
Two data buses X and Y go in, and W comes out. There are two select signals which
form the 2-bit vector aluSel. Now inside the architecture, which is our usual
behavioural. The case block lines 24-29 select which of the 4 functions is selected.
Note that 00 selects the passthrough function where input X is passed straight out
as Z.
Finally we must glance at the code for the MUX :

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

entity mux is
port ( sel : in
in0 : in
in1 : in
opt : out
end mux;

std_logic;
std_logic_vector (7 downto 0);
std_logic_vector (7 downto 0);
std_logic_vector (7 downto 0));

architecture Behavioural of mux is


begin
process(sel,in0,in1)
begin
if (sel = '0') then opt <= in0;
else opt <= in1;
end if;
end process;
end Behavioural;

The only thing really noteworthy here is lines 70-72 where the value of sel is tested
and the output assigned.

You might also like