The Single Cycle CPU Project

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 16

EGR 321 --- Computer Organization

Project 3: Single-Cycle CPU Design Using VHDL


California Baptist University
Fall Semester 2014
Due: Monday, December 8, 2014
Objectives
In this project, you will use the Quartus II 9.1 software (downloadable at:
https://www.altera.com/download/dnl-index.jsp
and select by version as: Version 9.1, Quartus II Subscription Edition, use it as 30-day trial) to
write VHDL programs to design and simulate a single-cycle CPU shown in Figure 1. The CPU
can execute the following instructions: add, sub, and, or, slt, lw, and sw.

Figure 1. The single-cycle CPU.

Step 1. Build a 32-bit Register


Create a new project named register32 to implement the 32-bit register shown in Figure 2.

Figure 2. 32-bit register.


The inputs of the register are: a 1-bit asynchronous active-high clear signal clr; a clock signal clk;
a 1-bit control input ld; a 32-bit data input D. The output is a 32-bit data output Q (i.e., the

register state value). When ld = 1, the register will load the input D to Q; when ld = 0, it keeps its
current Q value. Complete the following VHDL code for the register.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity register32 is
port(
clr: in std_logic;
-- async. clear
clk: in std_logic;
-- clock
ld: in std_logic;
-- load
D: in std_logic_vector(31 downto 0); -- data input
Q: out std_logic_vector(31 downto 0) ); -- data output
end entity register32;
---------------------------------------------------architecture register32_arch of register32 is
begin
-- fill in your code here
end architecture register32_arch;

Use the given waveform file register32.vwf (available on Blackboard) to simulate your register32
design. Submit your code and simulation result in your project report.

Step 2. Build a 32-bit 2-to-1 MUX


Create a new project named mux2to1_32 to implement a 32-bit 2-to-1 MUX. The inputs of the
MUX are: a 1-bit selection input sel; a 32-bit data input X0; a 32-bit data input X1. The output is a
32-bit data output Y. When sel = 0, Y = X0; when sel = 1, Y = X1. Complete the following VHDL
code for the MUX. Then use the given waveform file mux2to1_32.vwf (available on Blackboard)
to simulate your mux2to1_32 design. Submit your code and simulation result in your project
report.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity mux2to1_32 is
port(
sel: in std_logic; -- selection bit input
X0: in std_logic_vector(31 downto 0); -- first input
X1: in std_logic_vector(31 downto 0); -- second input
Y: out std_logic_vector(31 downto 0)); -- output
end entity mux2to1_32;
---------------------------------------------------architecture mux2to1_32_arch of mux2to1_32 is
begin
-- fill in your code here
end architecture mux2to1_32_arch;

Step 3. Build the Program Counter (PC) Update Circuit

Create a new project named pc_update to implement the subcircuit shown in Figure 3 (with the
inputs/outputs shown outside the dotted box).

Figure 3. The PC update circuit.


The inputs of the circuit are: a clock signal clk; a 1-bit control input incH_ldL; a 32-bit data input
PCInput (for inputting an instruction address specified by the user for initialization purpose). The
output is a 32-bit data output InstrAddr (for the updated instruction address). Complete the
following VHDL code for the PC update circuit. Then use the given waveform file pc_update.vwf
(available on Blackboard) to simulate your pc_update design. Submit your code and simulation
result in your project report.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity pc_update is
port( clk: in std_logic; -- clock
incH_ldL: in std_logic; -- increment PC = PC + 4 when high,
-- load PCInput when low
PCInput: in std_logic_vector(31 downto 0); -- external input for PC
InstrAddr: out std_logic_vector(31 downto 0) ); -- instruction address
end entity pc_update;
---------------------------------------------------architecture pc_update_arch of pc_update is
component register32 is
port(
clr: in std_logic;
-- async. clear
clk: in std_logic;
-- clock
ld: in std_logic;
-- load
D: in std_logic_vector(31 downto 0); -- data input
Q: out std_logic_vector(31 downto 0) ); -- data output
end component register32;
component mux2to1_32 is
port(
sel: in std_logic; -- selection bit input
X0: in std_logic_vector(31 downto 0); -- first input
X1: in std_logic_vector(31 downto 0); -- second input
Y: out std_logic_vector(31 downto 0)); -- output
end component mux2to1_32;
signal PC_current: std_logic_vector(31 downto 0); -- the current state of
-- PC reg
signal PC_add_4: std_logic_vector(31 downto 0); -- output from the adder

signal PC_next: std_logic_vector(31 downto 0); -- output from the MUX


begin
-- fill in your code here
end architecture pc_update_arch;

Step 4. Build the Instruction Memory


Create a new project named instr_mem to implement the instruction memory shown in Figure 4.

Figure 4. The instruction memory.


To make this project tractable, here we simply assume that the instruction memory can hold
up to 8 instructions. The inputs of the instruction memory are: a 32-bit address input Addr; a 1bit control input init (for initializing instructions at all memory locations). The outputs are a 32bit data output Instr (i.e., the fetched instruction); eight 32-bit data outputs I_word_0 to I_word_7
corresponding to the content of the eight memory words (for testing and simulation purpose).
When init = 1, the instruction memory will be initialized using default values (i.e., the
instructions we want to test). Instr always provides us with the instruction at address Addr. The
following VHDL codes (instr_mem.vhd and the implementation of the basic memory component
mem_word.vhd) related to the instruction memory are given to you (also available on
Blackboard).
-- To make this project tractable, here we simply assume
-- that the instruction memory can hold 8 instructions.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity instr_mem is
port(
Addr: in std_logic_vector(31 downto 0); -- instr addr
Instr: out std_logic_vector(31 downto 0); -- fetched instr
-- the following signals are for initialization
-- and testing purposes
init: in std_logic; -- initialization control signal
-- (connect to WE)
-- the following 8 outputs are only for simulation purpose
-- they are corresponding to the eight instruction words
-- in instruction memory
I_word_0: out std_logic_vector(31 downto 0); -- instr word in
-- memory location 0
I_word_1: out std_logic_vector(31 downto 0);
I_word_2: out std_logic_vector(31 downto 0);
I_word_3: out std_logic_vector(31 downto 0);

I_word_4: out
I_word_5: out
I_word_6: out
I_word_7: out
end entity instr_mem;

std_logic_vector(31
std_logic_vector(31
std_logic_vector(31
std_logic_vector(31

downto
downto
downto
downto

0);
0);
0);
0) );

---------------------------------------------------architecture instr_mem_arch of instr_mem is


component mem_word is
port(
sel:
WE:
RE:
Din:
Dout:
Q:

in std_logic; -- memory word select


in std_logic; -- write enable
in std_logic; -- read enable
in std_logic_vector(31 downto 0); -- input word
out std_logic_vector(31 downto 0); -- output word
out std_logic_vector(31 downto 0) -- state
-- (for testing purpose)

);
end component mem_word;
type RAM is array (integer range <>) of std_logic_vector (31 downto 0);
signal instr_word: RAM (0 to 7); -- eight instruction words
begin
-- instr_word(0) initialized to lw $1, 0($0) ;hex instr code: 8C010000
mem_word_0: mem_word
port map( sel => '1', WE => init, RE => '1',
Din => "10001100000000010000000000000000",
Dout => instr_word(0), Q => I_word_0 );
-- instr_word(1) initialized to lw $2, 4($0) ;hex instr code: 8C020004
mem_word_1: mem_word
port map( sel => '1', WE => init, RE => '1',
Din => "10001100000000100000000000000100",
Dout => instr_word(1), Q => I_word_1 );
-- instr_word(2) initialized to add $3, $1, $2 ;hex instr code: 00221820
mem_word_2: mem_word
port map( sel => '1', WE => init, RE => '1',
Din => "00000000001000100001100000100000",
Dout => instr_word(2), Q => I_word_2 );
-- instr_word(3) initialized to sw $3, 8($0) ;hex instr code: AC030008
mem_word_3: mem_word
port map( sel => '1', WE => init, RE => '1',
Din => "10101100000000110000000000001000",
Dout => instr_word(3), Q => I_word_3 );
-- instr_word(4) initialized to sub $4, $2, $1 ;hex instr code: 00412022
mem_word_4: mem_word
port map( sel => '1', WE => init, RE => '1',
Din => "00000000010000010010000000100010",
Dout => instr_word(4), Q => I_word_4 );
-- instr_word(5) initialized to and $5, $1, $2 ;hex instr code: 00222824
mem_word_5: mem_word
port map( sel => '1', WE => init, RE => '1',
Din => "00000000001000100010100000100100",
Dout => instr_word(5), Q => I_word_5 );

-- instr_word(6) initialized to or $6, $1, $2 ;hex instr code: 00223025


mem_word_6: mem_word
port map( sel => '1', WE => init, RE => '1',
Din => "00000000001000100011000000100101",
Dout => instr_word(6), Q => I_word_6 );
-- instr_word(7) initialized to slt $2, $1, $6 ;hex instr code: 0026102A
mem_word_7: mem_word
port map( sel => '1', WE => init, RE => '1',
Din => "00000000001001100001000000101010",
Dout => instr_word(7), Q => I_word_7 );
-- use word address
Instr <= instr_word(conv_integer(Addr(4 downto 2)));
end architecture instr_mem_arch;

The following is the VHDL code for basic memory component.


------

32-bit asynchronous memory word


Be sure to let WE = 1 after the Sin and Rin
have become stable when perfoming simulation.
Note: If WE goes to 0 and Din changes at the same time,
the new Din will be latched.

library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity mem_word is
port(
sel: in std_logic; -- memory word select
WE: in std_logic; -- write enable
RE: in std_logic; -- read enable
Din: in std_logic_vector(31 downto 0); -- input word
Dout: out std_logic_vector(31 downto 0); -- output word
Q: out std_logic_vector(31 downto 0) -- state
-- (for testing purpose)
);
end entity mem_word;
---------------------------------------------------architecture mem_word_arch of mem_word is
signal Din_not, Sin, Rin: std_logic_vector(31 downto 0);
signal Qa, Qb: std_logic_vector(31 downto 0);
begin
Sin(0)
Sin(1)
Sin(2)
Sin(3)
Sin(4)
Sin(5)
Sin(6)
Sin(7)
Sin(8)
Sin(9)

<=
<=
<=
<=
<=
<=
<=
<=
<=
<=

sel
sel
sel
sel
sel
sel
sel
sel
sel
sel

and
and
and
and
and
and
and
and
and
and

Din(0)
Din(1)
Din(2)
Din(3)
Din(4)
Din(5)
Din(6)
Din(7)
Din(8)
Din(9)

and
and
and
and
and
and
and
and
and
and

WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;

Sin(10)
Sin(11)
Sin(12)
Sin(13)
Sin(14)
Sin(15)
Sin(16)
Sin(17)
Sin(18)
Sin(19)
Sin(20)
Sin(21)
Sin(22)
Sin(23)
Sin(24)
Sin(25)
Sin(26)
Sin(27)
Sin(28)
Sin(29)
Sin(30)
Sin(31)

<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=
<=

sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel
sel

and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and

Din(10)
Din(11)
Din(12)
Din(13)
Din(14)
Din(15)
Din(16)
Din(17)
Din(18)
Din(19)
Din(20)
Din(21)
Din(22)
Din(23)
Din(24)
Din(25)
Din(26)
Din(27)
Din(28)
Din(29)
Din(30)
Din(31)

and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and
and

WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;
WE;

Din_not <= not Din;


Rin(0) <= sel and Din_not(0) and WE;
Rin(1) <= sel and Din_not(1) and WE;
Rin(2) <= sel and Din_not(2) and WE;
Rin(3) <= sel and Din_not(3) and WE;
Rin(4) <= sel and Din_not(4) and WE;
Rin(5) <= sel and Din_not(5) and WE;
Rin(6) <= sel and Din_not(6) and WE;
Rin(7) <= sel and Din_not(7) and WE;
Rin(8) <= sel and Din_not(8) and WE;
Rin(9) <= sel and Din_not(9) and WE;
Rin(10) <= sel and Din_not(10) and WE;
Rin(11) <= sel and Din_not(11) and WE;
Rin(12) <= sel and Din_not(12) and WE;
Rin(13) <= sel and Din_not(13) and WE;
Rin(14) <= sel and Din_not(14) and WE;
Rin(15) <= sel and Din_not(15) and WE;
Rin(16) <= sel and Din_not(16) and WE;
Rin(17) <= sel and Din_not(17) and WE;
Rin(18) <= sel and Din_not(18) and WE;
Rin(19) <= sel and Din_not(19) and WE;
Rin(20) <= sel and Din_not(20) and WE;
Rin(21) <= sel and Din_not(21) and WE;
Rin(22) <= sel and Din_not(22) and WE;
Rin(23) <= sel and Din_not(23) and WE;
Rin(24) <= sel and Din_not(24) and WE;
Rin(25) <= sel and Din_not(25) and WE;
Rin(26) <= sel and Din_not(26) and WE;
Rin(27) <= sel and Din_not(27) and WE;
Rin(28) <= sel and Din_not(28) and WE;
Rin(29) <= sel and Din_not(29) and WE;
Rin(30) <= sel and Din_not(30) and WE;
Rin(31) <= sel and Din_not(31) and WE;
Qa <= Rin nor Qb;
Qb <= Sin nor Qa;
with std_logic_vector'(sel,RE) select
Dout <= Qa when "11",

(others => 'Z') when others;


Q <= Qa;
end architecture mem_word_arch;

Step 5. Build the Register File


Create a new project named reg_file to implement the register file shown in Figure 5.

Figure 5. The register file.


To make this project tractable, here we simply assume that there are 8 registers (with
register 0 holding the value zero and cannot be changed). The inputs of reg_file are: a clock
signal clk; a 1-bit control input RegWrite; a 5-bit address input RsAddr; a 5-bit address input
RtAddr; a 5-bit address input RdAddr; a 32-bit data input WriteData. The outputs are: a 32-bit
data output RsAddr; a 32-bit data input Rt; eight 32-bit data outputs Reg_word_0 to
Reg_word_7 corresponding to the content of the eight register words (for testing and simulation
purpose). Complete the following VHDL code for the register file circuit. Then use the given
waveform file reg_file.vwf (available on Blackboard) to simulate your reg_file design. Submit
your code and simulation result in your project report.
-- To make this project tractable, here we simply assume
-- that the register file has 8 instructions.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity reg_file is
port(
clk: in std_logic;
RegWrite: in std_logic;
RsAddr: in std_logic_vector(4 downto 0);
RtAddr: in std_logic_vector(4 downto 0);
RdAddr: in std_logic_vector(4 downto 0);
WriteData: in std_logic_vector(31 downto 0);
Rs: out std_logic_vector(31 downto 0);
Rt: out std_logic_vector(31 downto 0);
-- the following 8 outputs are only for simulation purpose
-- they are corresponding to the eight register words in
-- the register file
Reg_word_0: out std_logic_vector(31 downto 0); -- reg word 0

Reg_word_1: out
Reg_word_2: out
Reg_word_3: out
Reg_word_4: out
Reg_word_5: out
Reg_word_6: out
Reg_word_7: out
end entity reg_file;

std_logic_vector(31
std_logic_vector(31
std_logic_vector(31
std_logic_vector(31
std_logic_vector(31
std_logic_vector(31
std_logic_vector(31

downto
downto
downto
downto
downto
downto
downto

0);
0);
0);
0);
0);
0);
0) );

---------------------------------------------------architecture reg_file_arch of reg_file is


begin
-- fill in your code here
end architecture reg_file_arch;

Step 6. Build the ALU


Create a new project named alu to implement the ALU shown in Figure 6.

Figure 6. The ALU.


The inputs of alu are: a 32-bit data input A; a 32-bit data input B; a 4-bit control input ALUCtrl
(which determines the operations A+B, A-B, etc.; use the ALU control input code given in Table
4.12 in text). The output is a 32-bit data output S. The ALU should implement the following five
operations: add, sub, and, or, slt. You do not need to generate overflow or zero signals. All data
inputs are regarded as signed numbers. Complete the following VHDL code for the ALU circuit.
Then use the given waveform file alu.vwf (available on Blackboard) to simulate your alu design.
Submit your code and simulation result in your project report.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity alu is
port(

A: in std_logic_vector(31 downto 0); -- input A


B: in std_logic_vector(31 downto 0); -- input B
ALUCtrl: in std_logic_vector (3 downto 0); -- 4-bit oper code
S: out std_logic_vector(31 downto 0)); -- output S
end entity alu;
---------------------------------------------------architecture alu_arch of alu is
begin
-- fill in your code here

end architecture alu_arch;

Step 7. Build the Data Memory


Create a new project named data_mem to implement the data memory shown in Figure 7.

Figure 7. The data memory.


To make this project tractable, here we simply assume that the data memory can hold up to
8 data words. The inputs of the data memory are: a 1-bit control input MemRead; a 1-bit control
input MemWrite; a 32-bit address input Addr; a 32-bit data input WriteData; a 1-bit control input
init (for initializing data at all memory locations). The outputs are a 32-bit data output ReadData;
eight 32-bit data outputs D_word_0 to D_word_7 corresponding to the content of the eight
memory words (for testing and simulation purpose). When init = 1, the data memory will be
initialized using default values (i.e., the initial data). The following VHDL code (available on
Blackboard) for the data memory is given to you (the component code mem_word.vhd is given in
Step 4).
------

To make this project tractable, here we simply assume


that the data memory can hold 8 data words.
The WriteData must be stable before MemWrite is asserted.
The WriteData must be stable when MemWrite is de-asserted,
otherwise the new WriteData will be latched.

library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity data_mem is
port( MemRead: in std_logic; -- read enable
MemWrite: in std_logic; -- write enable
Addr: in std_logic_vector(31 downto 0); -- address input
WriteData: in std_logic_vector(31 downto 0); -- data input
ReadData: out std_logic_vector(31 downto 0); -- data output
-- the following signals are for initialization
-- and testing purposes
init: in std_logic; -- initialization control signal
-- the following 8 outputs are only for simulation purpose
-- they are corresponding to the eight data words
-- in data memory
D_word_0: out std_logic_vector(31 downto 0); -- data word in
-- memory location 0
D_word_1: out std_logic_vector(31 downto 0);
D_word_2: out std_logic_vector(31 downto 0);
D_word_3: out std_logic_vector(31 downto 0);

10

D_word_4: out
D_word_5: out
D_word_6: out
D_word_7: out
);
end entity data_mem;

std_logic_vector(31
std_logic_vector(31
std_logic_vector(31
std_logic_vector(31

downto
downto
downto
downto

0);
0);
0);
0)

---------------------------------------------------architecture data_mem_arch of data_mem is


component mem_word is
port(
sel: in std_logic; -- memory word select
WE: in std_logic; -- write enable
RE: in std_logic; -- read enable
Din: in std_logic_vector(31 downto 0); -- input word
Dout: out std_logic_vector(31 downto 0); -- output word
Q: out std_logic_vector(31 downto 0) -- state
-- (for testing purpose)
);
end component mem_word;
signal cond: std_logic_vector(31 downto 0); -- condition word
-- which copies init 32 times
signal active_mem: std_logic_vector(0 to 7); -- assert 1 for bit
-- position to the corresponding selected memory word

type RAM is array (integer range <>) of std_logic_vector (31 downto 0);
signal data_word: RAM (0 to 7);
begin
with init select
cond <= (others => '0') when '0',
(others => '1') when others;
with Addr(4 downto 2) select
active_mem <= "10000000" when
"01000000" when
"00100000" when
"00010000" when
"00001000" when
"00000100" when
"00000010" when
"00000001" when

"000",
"001",
"010",
"011",
"100",
"101",
"110",
others;

-- data_word(0) initialized to hex data 00000048, i.e., decimal 72


mem_word_0: mem_word
port map( sel => '1', WE => init or (active_mem(0) and MemWrite),
RE => '1',
Din => (cond and "00000000000000000000000001001000")
or ( (not cond) and WriteData ),
Dout => data_word(0), Q => D_word_0 );
-- We set RE = '1' for the purpose of
-- sending the memory content to D_word_0.
-- However, MemRead will then actually decide
-- if there will be an output.
-- data_word(1) initialized to hex data 000000D5, i.e., decimal 213
mem_word_1: mem_word
port map( sel => '1', WE => init or (active_mem(1) and MemWrite),
RE => '1',

11

Din => (cond and "00000000000000000000000011010101")


or ( (not cond) and WriteData ),
Dout => data_word(1), Q => D_word_1 );
-- data_word(2) initialized to 0
mem_word_2: mem_word
port map( sel => '1', WE => init or (active_mem(2) and MemWrite),
RE => '1',
Din => (cond and "00000000000000000000000000000000")
or ( (not cond) and WriteData ),
Dout => data_word(2), Q => D_word_2 );
-- data_word(3) initialized to 0
mem_word_3: mem_word
port map( sel => '1', WE => init or (active_mem(3) and MemWrite),
RE => '1',
Din => (cond and "00000000000000000000000000000000")
or ( (not cond) and WriteData ),
Dout => data_word(3), Q => D_word_3 );
-- data_word(4) initialized to 0
mem_word_4: mem_word
port map( sel => '1', WE => init or (active_mem(4) and MemWrite),
RE => '1',
Din => (cond and "00000000000000000000000000000000")
or ( (not cond) and WriteData ),
Dout => data_word(4), Q => D_word_4 );
-- data_word(5) initialized to 0
mem_word_5: mem_word
port map( sel => '1', WE => init or (active_mem(5) and MemWrite),
RE => '1',
Din => (cond and "00000000000000000000000000000000")
or ( (not cond) and WriteData ),
Dout => data_word(5), Q => D_word_5 );
-- data_word(6) initialized to 0
mem_word_6: mem_word
port map( sel => '1', WE => init or (active_mem(6) and MemWrite),
RE => '1',
Din => (cond and "00000000000000000000000000000000")
or ( (not cond) and WriteData ),
Dout => data_word(6), Q => D_word_6 );
-- data_word(7) initialized to 0
mem_word_7: mem_word
port map( sel => '1', WE => init or (active_mem(7) and MemWrite),
RE => '1',
Din => (cond and "00000000000000000000000000000000")
or ( (not cond) and WriteData ),
Dout => data_word(7), Q => D_word_7 );
-- use word address
with MemRead select
ReadData <= data_word(conv_integer(Addr(4 downto 2))) when '1',
( others => 'Z') when others;
end architecture data_mem_arch;

Step 8. Build the ALU Control Unit

12

Create a new project named alu_control to implement the ALU control unit. The inputs of
alu_control are: a 2-bit control input ALUOp; a 6-bit control input Funct. The output is a 4-bit
ALU control signal ALUCtrl. Use Table 4.12 in text to determine the input, output codes, and
their relationship. Complete the following VHDL code for the ALU control unit. Then use the
given waveform file alu_control.vwf (available on Blackboard) to simulate your alu_control
design. Submit your code and simulation result in your project report.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity alu_control is
port( ALUOp: in std_logic_vector(1 downto 0);
Funct: in std_logic_vector(5 downto 0);
ALUCtrl: out std_logic_vector(3 downto 0));
end entity alu_control;
---------------------------------------------------architecture alu_control_arch of alu_control is
begin
-- fill in your code here
end architecture alu_control_arch;

Step 9. Build the 16-bit to 32-bit Sign Extension Unit


Create a new project named sign_ext_16to32 to implement the sign extension circuit from 16 bit
to 32 bit. The input of sign_ext_16to32 is a 16-bit data input in_16bit. The output is a 32-bit data
output out_32bit. Complete the following VHDL code for the 16-bit to 32-bit sign extension unit.
Then use the given waveform file sign_ext_16to32.vwf (available on Blackboard) to simulate
your sign_ext_16to32 design. Submit your code and simulation result in your project report.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity sign_ext_16to32 is
port( in_16bit: in std_logic_vector(15 downto 0); -- 16 bit input
out_32bit: out std_logic_vector(31 downto 0) ); -- 32 bit output
end entity sign_ext_16to32;
---------------------------------------------------architecture sign_ext_16to32_arch of sign_ext_16to32 is
begin
-- fill in your code here
end architecture sign_ext_16to32_arch;

Step 10. Build the Control Unit

13

Create a new project named control to implement the control unit. The input of control is a 6-bit
control input Opcode. The outputs are: a 1-bit control output RegDst; a 1-bit control output
ALUSrc; a 1-bit control output MemtoReg; a 1-bit control output RegWrite; a 1-bit control output
MemRead; a 1-bit control output MemWrite; a 2-bit control output ALUOp. Use Table 4.18 in text
to determine the input-output relationship. Complete the following VHDL code for the control
unit. Then use the given waveform file control.vwf (available on Blackboard) to simulate your
control design. Submit your code and simulation result in your project report.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--------------------------------------------------entity control is
port(
Opcode:
RegDst:
ALUSrc:
MemtoReg:
RegWrite:
MemRead:
MemWrite:
ALUOp:
end entity control;

in std_logic_vector(5 downto 0);


out std_logic;
out std_logic;
out std_logic;
out std_logic;
out std_logic;
out std_logic;
out std_logic_vector(1 downto 0) );

---------------------------------------------------architecture control_arch of control is


begin
-- fill in your code here
end architecture control_arch;

Step 11. Build the CPU


Finally, create a new project named cpu to implement the CPU shown in Figure 1.
The inputs of cpu are: a clock signal clk; a 1-bit control input incH_ldL; a 32-bit data input
PCInput (for inputting an instruction address specified by the user for initialization purpose); a 1bit control input init (for initializing instructions and data at all memory locations). The outputs
are: eight 32-bit data outputs I_word_0 to I_word_7 corresponding to the content of the eight
instruction memory words (for testing and simulation purpose); eight 32-bit data outputs
Reg_word_0 to Reg_word_7 corresponding to the content of the eight register words (for testing
and simulation purpose); eight 32-bit data outputs D_word_0 to D_word_7 corresponding to the
content of the eight data memory words (for testing and simulation purpose). Complete the
following VHDL code for the CPU. Then use the given waveform file cpu.vwf (available on
Blackboard) to simulate your cpu design. Submit your code and simulation result in your project
report. Note that since the CPU design uses 804 I/O pins, it is suggested that you choose the chip
Stratix II: EP2S180F1508C3 (which has 1171 I/O pins) when you carry out the timing simulation.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
---------------------------------------------------

14

entity cpu is
port(
clk: in std_logic; -- clock input
MemWriteAllow: in std_logic; -- use this external input bit to and
-- with MemWrite signal to make sure
-- both Addr and WriteData have become
-- stable when write enable is asserted
-- for data memory. This signal is active
-- in the third fourth portion of each cycle.
-- the following signals are only used for
-- testing and simulation purpose
incH_ldL: in std_logic; -- increment PC = PC + 4 when high,
-- load PCInput when low
PCInput: in std_logic_vector (31 downto 0); -- external input for PC
init: in std_logic; -- initialization control signal
_word_0: out std_logic_vector(31 downto 0); -- instr word in
-- instruction memory location 0
I_word_1: out std_logic_vector(31 downto 0);
I_word_2: out std_logic_vector(31 downto 0);
I_word_3: out std_logic_vector(31 downto 0);
I_word_4: out std_logic_vector(31 downto 0);
I_word_5: out std_logic_vector(31 downto 0);
I_word_6: out std_logic_vector(31 downto 0);
I_word_7: out std_logic_vector(31 downto 0);
Reg_word_0: out std_logic_vector(31 downto 0); -- reg word 0
Reg_word_1: out std_logic_vector(31 downto 0);
Reg_word_2: out std_logic_vector(31 downto 0);
Reg_word_3: out std_logic_vector(31 downto 0);
Reg_word_4: out std_logic_vector(31 downto 0);
Reg_word_5: out std_logic_vector(31 downto 0);
Reg_word_6: out std_logic_vector(31 downto 0);
Reg_word_7: out std_logic_vector(31 downto 0);
D_word_0: out std_logic_vector(31 downto 0); -- data word in
-- data memory location 0
D_word_1: out std_logic_vector(31 downto 0);
D_word_2: out std_logic_vector(31 downto 0);
D_word_3: out std_logic_vector(31 downto 0);
D_word_4: out std_logic_vector(31 downto 0);
D_word_5: out std_logic_vector(31 downto 0);
D_word_6: out std_logic_vector(31 downto 0);
D_word_7: out std_logic_vector(31 downto 0) );
end entity cpu;
---------------------------------------------------architecture cpu_arch of cpu is
begin
-- fill in your code here
end architecture cpu_arch;

Additional Requirements and Hints


Formats
You should use appropriate formats (variable names, indentation, blank lines, etc.) in all your
programs.
Comments

15

The programs must be appropriate commented for readability.


Some Other Hints
If you introduce additional entities and use them as components, include their VHDL codes and
simulation results in your report. Make sure that all your simulation results correctly verify your
intended design. Also note that since the CPU design uses 804 I/O pins, it is suggested that you
choose the chip Stratix II: EP2S180F1508C3 (which has 1171 I/O pins) when you carry out the
timing simulation.
What to Turn in
Zip all the VHDL files (for the aforementioned 11 steps and any additional VHDL files you have
written) and the corresponding simulation results (you may choose File Save Current Report
Section As and save the simulation result as a .sim.cvwf file) into your_lastname_proj3.zip
and submit it on Blackboard under the assignment Content/Projects/Project 3: Single-Cycle CPU
Design Using VHDL, by midnight, Monday, December 8, 2014.

16

You might also like