You are on page 1of 21

CONTENTS

1. Introduction 1

2. Objective 2

3. SYSTEM DESCRIPTION AND DESIGN 3

4. CODES 9

5. SIMULATION RESULTS 18

6. CONCLUSION 19

7. REFERENCES 20
1. INTRODUCTION

The processor is the primary element that carries out the functions of a
computer system. It performs the basic arithmetical, logical, and
input/output operations of the system. The term central processing unit
(CPU) is commonly used to describe a processor. The form, design and
implementation of CPUs have changed dramatically over the years, but their
fundamental operation remains much the same. Inside the processor, there
are some basic elements the work together to make the processor
functional. These are as follows:

1.1 Arithmetic Logic Unit (ALU): This is the main block in the processor and
the most important. The ALU is responsible for performing all the
computations. When the user, for example, enters numbers to be added or
multiplied, this unit does the computation and outputs the result to the
output devices. All the arithmetic operations such as adding, subtraction,
multiplying, or division is performed using this unit. Also, the logical
operations such as ANDing, ORing are done using this unit.

1.2 Control Unit: The control unit is another fundamental part of the CPU.
Essentially, it regulates the flow of information through the processor. The
functions that a control unit performs can vary based on what a particular
CPU was built to do. Mostly, this component receives, decodes, stores
results and manages execution of data that flows through the CPU.

1.3 Registers: These are very small memory locations that are responsible
for holding the data that is to be processed. The most important of these
registers is known as the instruction pointer, which directs the CPU to the
next memory location from where it is to receive information. Another type
of register is the accumulator, which is responsible for storing the results of
the various computations performed by the CPU. The data that is processed
by the CPU is also stored in some of the available registers.

1
2. OBJECTIVE

The scope of this project is to design an 8 bit processor using VHDL. The
processor fetches instructions from the external memory and executes
them. The control unit decodes the instructions and then causes the
appropriate signal interactions to make the processor unit execute the
instruction. The operations that the processor will be supporting are:

Addition of two 8 bit numbers (with or without carry)

Subtraction of two 8 bit numbers (with or without borrow)

Increment or decrement an 8 bit number by 1

Logical NOT of an 8-bit number

Logical OR of two 8-bit numbers

Logical AND of two 8-bit numbers

Logical XOR of two 8-bit numbers

Store an 8-bit number temporarily in the accumulator

Reset the accumulator value to ‘0’

These operations are to be implemented as functions and the packages


containing them are then used in the main code of the processor.

2
3. SYSTEM DESCRIPTION AND
DESIGN

As stated previously, the processor consists of an ALU, registers and a


control unit. The ALU performs the various arithmetic and logical operations,
the registers store data that is to be operated on and the control unit
regulates the working of the processor.

A simple block diagram of a processor is as shown below:

3
The primary function of the processor is to execute programs. Now, a
program can be considered to be a sequence of instructions. Thus, in other
words, the basic function of a processor is to execute instructions.

The steps involved in executing an instruction in a processor are as follows:

Instruction fetch
Firstly, the instruction to be executed has to be fetched from the memory. A
16-bit address bus is used to access the memory location where the
instruction is stored.

Instruction decode
The processor decodes the instruction to determine what actions are to be
performed. The opcode part of the instruction states what operation is to be
performed on specified operands.

Accept data
In this step, the operands are read and stored in the registers available in the
processor. The 16-bit address lines are used to specify the memory location
or the input device from where the operand is to be read. The operand
reaches the processor via the 8-bit data bus.

Execute instruction
Next, the desired operation is performed in the ALU. The operands, stored in
the registers, are accessed during execution. The final result generated by
the operation is stored in the accumulator.

Memory Write Back


In the final step, the result that is temporarily stored in the accumulator is
stored in the memory or is sent to an output device.

NOTE: An 8-bit CPU normally uses a 16-bit address bus and an 8-bit data bus.
However, this is not a law and there are exceptions.

4
A detailed illustration of how the other units interact with the processor is as
follows:

5
In our processor design, we have directly taken the opcode and the data as
inputs, irrespective of whether the data is being read from the memory or an
input device. The data is stored in temporary registers, B and C. Then, the
opcode is decoded and the operation that is to be performed is determined.
In the next clock cycle, the operation is performed and the result is stored in
the accumulator. The result is also made available as the output.

The opcodes and their corresponding instructions and operations are:

OPCODE INSTRUCTION OPERATION

0000 MV Accumulator = B

0001 INC Accumulator = B+1

0010 DRC Accumulator = B-1

0011 ADD Accumulator = B+C (carry is discarded)

0100 SUB Accumulator = B-C (borrow is discarded)

0101 ADC Accumulator = B+C (carry is added to


the accumulator value)

0110 SUBB Accumulator = B-C (borrow is


subtracted from the accumulator value)

0111 ANDL Accumulator = B AND C

1000 ORL Accumulator = B OR C

1001 XORL Accumulator = B XOR C

1010 NOTL Accumulator = NOT B

1011 RT Accumulator = 0

6
The following flowchart describes how an operation is performed in the
processor:

7
An illustration of implements the flowchart is as shown below. The
components in the area surrounded by dotted lines constitute the processor.

With this background, we know move on to the VHDL code that implements
the processor.

8
4. CODES
Package containing functions that perform addition (without carry) and
subtraction (without borrow)

library ieee;
use ieee.std_logic_1164.all;
package my_pack is
function add(L,R :std_logic_vector) return std_logic_vector;
function sub(L,R :std_logic_vector) return std_logic_vector;
end my_pack;
package body my_pack is
function add(L,R : std_logic_vector) return std_logic_vector is
variable lv,rv,resv : std_logic_vector(L'length-1 downto 0);
variable cbit: std_logic;
begin
lv := L;
rv := R;
cbit := '0';
for k in 0 to L'left loop
resv(k) := cbit XOR lv(k) XOR rv(k);
cbit := (cbit AND lv(k)) OR (cbit AND rv(k)) OR (lv(k) AND rv(k));
end loop;
return resv;
end add;
function sub(L,R : std_logic_vector) return std_logic_vector is
variable lv,rv,resv : std_logic_vector(L'length-1 downto 0);
variable cbit: std_logic;
begin
lv := L;
rv := not R;
cbit := '1';
for k in 0 to L'left loop
resv(k) := cbit XOR lv(k) XOR rv(k);
cbit := (cbit AND lv(k)) OR (cbit AND rv(k)) OR (lv(k) AND rv(k));
end loop;
return resv;
end sub;
end my_pack;

9
Package containing functions that perform addition (with carry) and subtraction
(with borrow)

library ieee;
use ieee.std_logic_1164.all;
use work.my_pack.all;
package my_pack_adc is
function addc(L,R :std_logic_vector) return std_logic_vector;
function subb(L,R :std_logic_vector) return std_logic_vector;
end my_pack_adc;
package body my_pack_adc is
function addc(L,R : std_logic_vector) return std_logic_vector is
variable lv,rv,resv,s : std_logic_vector(L'length-1 downto 0);
variable resf : std_logic_vector(L'length-1 downto 0);
variable cbit: std_logic;
begin
lv := L;
rv := R;
cbit := '0';
for k in 0 to L'left loop
resv(k) := cbit XOR lv(k) XOR rv(k);
cbit := (cbit AND lv(k)) OR (cbit AND rv(k)) OR (lv(k) AND
rv(k));
end loop;
if(cbit ='0') then s:= "00000000";
else s:="00000001";
end if;
resf:=add(resv,s);
return resf;
end addc;
function subb(L,R : std_logic_vector) return std_logic_vector is
variable lv,rv,resv,s : std_logic_vector(L'length-1 downto 0);
variable resf : std_logic_vector(L'length-1 downto 0);
variable cbit: std_logic;
begin
lv := L;
rv := not R;
cbit := '1';
for k in 0 to L'left loop
resv(k) := cbit XOR lv(k) XOR rv(k);
cbit := (cbit AND lv(k)) OR (cbit AND rv(k)) OR (lv(k) AND rv(k));

10
end loop;
if(cbit ='1') then s:="00000000";
else s:="00000001";
end if;
resf:=sub(resv,s);
return resf;
end subb;
end my_pack_adc;

Package containing functions that perform logical AND, OR, XOR and NOT

library ieee;
use ieee.std_logic_1164.all;
package my_pack02 is
function andl(L,R :std_logic_vector) return std_logic_vector;
function orl(L,R :std_logic_vector) return std_logic_vector;
function xorl(L,R :std_logic_vector) return std_logic_vector;
function notl(L,R :std_logic_vector) return std_logic_vector;
end my_pack02;
package body my_pack02 is
function xorl(L,R : std_logic_vector) return std_logic_vector is
variable lv,rv,resv : std_logic_vector(L'length-1 downto 0);
begin
lv := L;
rv := R;
for k in 0 to L'left loop
resv(k) := lv(k) XOR rv(k);
end loop;
return resv;
end xorl;
function notl(L,R : std_logic_vector) return std_logic_vector is
variable lv,rv,resv : std_logic_vector(L'length-1 downto 0);
begin
lv := L;
for k in 0 to L'left loop
resv(k) :=NOT lv(k);
end loop;
return resv;
end notl;

11
function orl(L,R : std_logic_vector) return std_logic_vector is
variable lv,rv,resv : std_logic_vector(L'length-1 downto 0);
begin
lv := L;
rv := R;
for k in 0 to L'left loop
resv(k) := lv(k) OR rv(k);
end loop;
return resv;
end orl;
function andl(L,R : std_logic_vector) return std_logic_vector is
variable lv,rv,resv : std_logic_vector(L'length-1 downto 0);
begin
lv := L;
rv := R;
for k in 0 to L'left loop
resv(k) := lv(k) AND rv(k);
end loop;
return resv;
end andl;
end my_pack02;

Package containing functions that perform increment and decrement operations

library ieee;
use ieee.std_logic_1164.all;
package my_pack03 is
function inc(L :std_logic_vector) return std_logic_vector;
function drc(L :std_logic_vector) return std_logic_vector;
end my_pack03;
package body my_pack03 is
function inc(L : std_logic_vector) return std_logic_vector is
variable lv,rv,resv : std_logic_vector(L'length-1 downto 0);
variable cbit: std_logic;
begin
lv := L;
rv := "00000001";
cbit := '0';
for k in 0 to L'left loop
resv(k) := cbit XOR lv(k) XOR rv(k);

12
cbit := (cbit AND lv(k)) OR (cbit AND rv(k)) OR (lv(k) AND rv(k));
end loop;
return resv;
end inc;
function drc(L : std_logic_vector) return std_logic_vector is
variable lv,rv,resv : std_logic_vector(L'length-1 downto 0);
variable cbit: std_logic;
begin
lv := L;
rv := not "00000001";
cbit := '1';
for k in 0 to L'left loop
resv(k) := cbit XOR lv(k) XOR rv(k);
cbit := (cbit AND lv(k)) OR (cbit AND rv(k)) OR (lv(k) AND rv(k));
end loop;
return resv;
end drc;
end my_pack03;
library work;
library ieee;
use ieee.std_logic_1164.all;
use work.my_pack03.all;
entity inc_8 is
port( P: in std_logic_vector (7 downto 0);
R: out std_logic_vector (7 downto 0));
end inc_8;
architecture DF of inc_8 is
begin
R <= drc(P);
end DF;

Package containing a function that moves an input to the accumulator

library ieee;
use ieee.std_logic_1164.all;
package my_pack04 is
function mov(L,R :std_logic_vector) return std_logic_vector;
end my_pack04;
package body my_pack04 is
function mov(L,R : std_logic_vector) return std_logic_vector is
variable resv : std_logic_vector(L'length-1 downto 0);

13
begin
resv := L;
return resv;
end mov;
end my_pack04;
library work;
library ieee;
use ieee.std_logic_1164.all;
use work.my_pack02.all;
entity mov_8 is
port( P,Q : in std_logic_vector (7 downto 0);
R: out std_logic_vector (7 downto 0));
end mov_8;
architecture DF of mov_8 is
begin
R <= mov(p);
end DF;

Main code that implements the processor, using the functions described
previously

library work;
library ieee;
use ieee.std_logic_1164.all;
use work.my_pack02.all;
use work.my_pack03.all;
use work.my_pack04.all;
use work.my_pack.all;
use work.my_pack_adc.all;

entity processor is
port (B,C :in std_logic_vector(7 downto 0);
op :in std_logic_vector(3 downto 0);
Rst,clk :in std_logic;
done :out std_logic;
acc :out std_logic_vector(7 downto 0));
end processor;

architecture behv of processor is


type t_state is (dt,mv,inc,drc,add,sub,adc,subb,andl,orl,xorl,notl,rt);

14
signal state : t_state;
begin
process(Rst,clk,op)
constant cnt:std_logic_vector(7 downto 0):=(others=>'0');
variable resl: std_logic_vector(7 downto 0);
variable temp1:std_logic_vector(7 downto 0);
variable temp2:std_logic_vector(7 downto 0);
variable k:natural;
begin
if (Rst = '1') then
state<=dt;
elsif (clk ='1' and clk'event) then
case state is
when dt =>
resl:= (others=>'0');
temp1 := B;
temp2 := C;
if (op="0000") then
state<=mv;
elsif(op="0001") then
state <=inc;
elsif(op="0010") then
state <=drc;
elsif(op="0011") then
state <=add;
elsif(op="0100") then
state <=sub;
elsif(op="0101") then
state <=adc;
elsif(op="0110") then
state <=subb;
elsif(op="0111") then
state <=andl;
elsif(op="1000") then
state <=orl;
elsif(op="1001") then
state <=xorl;
elsif(op="1010") then
state <=notl;
else
state<=dt;
end if;
15
when add=>
resl := add(temp1,temp2);
state<=dt;
acc<=resl;
done<='1';

when sub=>
resl := sub(temp1,temp2);
state<=dt;
acc<=resl;
done<='1';

when subb=>
resl := subb(temp1,temp2);
state<=dt;
acc<=resl;
done<='1';

when adc=>
resl := addc(temp1,temp2);
state<=dt;
acc<=resl;
done<='1';

when inc=>
resl := inc(temp1);
state<=dt;
acc<=resl;
done<='1';

when drc=>
resl := drc(temp1);
state<=dt;
acc<=resl;
done<='1';

when andl=>
resl := andl(temp1,temp2);
state<=dt;
acc<=resl;
done<='1';

16
when orl=>
resl := orl(temp1,temp2);
state<=dt;
acc<=resl;
done<='1';

when xorl=>
resl := xorl(temp1,temp2);
state<=dt;
acc<=resl;
done<='1';

when notl=>
resl := notl(temp1);
state<=dt;
acc<=resl;
done<='1';

when mv=>
acc<=temp1;
state<=dt;
done<='1';

when rt=>
acc<=(others=>'0');
done<='1';
state<=dt;

end case;
end if;
end process;
end behv;

17
5. SIMULATION RESULTS

NOTE: ‘W/O Carry’ and ‘W/O borrow’ stand for ‘Without Carry’ and ‘Without
Borrow’ respectively. ‘W Carry’ and ‘W borrow’ stand for ‘With Carry’ and
‘With Borrow’ respectively.

18
6. CONCLUSION

The code worked and generated results as expected. This can be verified
from the simulation results that have been obtained. Thus, we can say that
the objective has been successfully realised. The code can further be
extended to included additional functionalities such as comparing two 8-bit
numbers, right or left shifting, and so on.

19
7. REFERENCES

[1] E. Ayeh, K. Agbedanu, Y. Morita, O. Adamo, and P. Guturu, “FPGA


Implementation of an 8-bit Simple Processor”

[2] Douglas Perry, “VHDL Programming by Example”

[3] Jayaram Bhasker, “A VHDL Primer”

20

You might also like