A Complete 8-Bit Microcontroller in VHDL
A Complete 8-Bit Microcontroller in VHDL
A Complete 8-Bit Microcontroller in VHDL
In this project, VHDL code for a microcontroller is presented. The 8-bit microcontroller is
designed, implemented, and operational as a full design which users can program the
microcontroller using assembly language. The instruction set and architecture of the 8-bit
microcontroller are from an example of a computer system in Chapter 13 of the book
"Introduction to Logic Circuits and Logic Design with VHDL" by Brock J. LaMeres.
The microcontroller has an 8-bit processor, a 128-byte program memory, a 96-byte RAM,
16x8-bit output ports, and 16x8-bit input ports. Users can program the microcontroller by
inserting opcodes and operands in the program memory.
After completing the design, the microcontroller is implemented on FPGA DE0-nano board
as shown in the figure below.
Below is the top level block diagram of the 8-bit
microcontroller:
The CPU as shown in the following figure has two 8-bit
registers (A and B), an Arithmetic Logical Unit (ALU) to
perform math and logic operations, and a control unit to
handle the operations of instructions.
Instruction Register (IR): contains the content of the
current instruction.
Memory Address Register (MAR): holds the current
address to access the memory. It can be from program
counter or from an operand of an instruction.
Program Counter (PC): holds the next location in
program memory for the next instruction.
A & B: two 8-bit registers being controlled by users.
Arithmetic Logical Unit (ALU): performs math and
logical operations such as addition, subtraction, logical
AND, logical OR, increments, and decrements. Inputs of
the ALU are from Bus1 and register B. The output of the
ALU goes to the multiplexer driving Bus2. The
functionality of the ALU is selected by the ALU_Sel lines
(3 bits) where "000" = ADD, "001" = SUB, "010" = AND,
"011" = OR, "100" = Increment, and "101" = Decrement.
Condition Code Register (CCR): holds the status
information of the results at the ALU. It contains a
negative flag (N), a zero flag (Z), a two's complement
overflow flag (V), and a carry flag (C).
The memory map of the CPU is as follows:
S_LOAD_AND_STORE_7,S_DATA_MAN_4,
S_BRANCH_4,S_BRANCH_5,S_BRANCH_6
);
signal current_state,next_state: FSM;
signal LOAD_STORE_OP,DATA_MAN_OP,BRANCH_OP: std_logic;
begin
-- FSM State FFs
process(clock,reset)
begin
if(reset='0') then
current_state <= S_FETCH_0;
elsif(rising_edge(clock)) then
current_state <= next_state;
end if;
end process;
--fpga4student.com FPGA projects, Verilog projects, VHDL projects
process(current_state,IR,CCR_Result,LOAD_STORE_OP,DATA_MAN_OP,BRANCH_OP)
begin
IR_Load <= '0';
MAR_Load <= '0';
PC_Load <= '0';
PC_Inc <= '0';
A_Load <= '0';
B_Load <= '0';
ALU_Sel <= "000";
CCR_Load <= '0';
Bus2_Sel <= "00";
Bus1_Sel <= "00";
write <= '0';
case(current_state) is
when S_FETCH_0 =>
Bus1_Sel <= "00"; -- PC
Bus2_Sel <= "01"; -- BUS1
MAR_Load <= '1';
next_state <= S_FETCH_1;
when S_FETCH_1 =>
PC_Inc <= '1';
next_state <= S_FETCH_2;
when S_FETCH_2 =>
Bus2_Sel <= "10";
IR_Load <= '1';
next_state <= S_DECODE_3;
when S_DECODE_3 =>
if(LOAD_STORE_OP='1') then
next_state <= S_LOAD_AND_STORE_4;
elsif(DATA_MAN_OP='1') then
next_state <= S_DATA_MAN_4;
elsif(BRANCH_OP='1') then
next_state <= S_BRANCH_4;
end if;
---- LOAD AND STORE INSTRUCTIONS:
when S_LOAD_AND_STORE_4 =>
if(IR >= x"86" and IR <= x"89")then -- LOAD IMMEDIATE
Bus1_Sel <= "00";
Bus2_Sel <= "01";
MAR_Load <= '1';
elsif(IR = x"96" or IR = x"97")then -- LOAD IMMEDIATE
Bus1_Sel <= "00";
Bus2_Sel <= "01";
MAR_Load <= '1';
end if;
next_state <= S_LOAD_AND_STORE_5;
when S_LOAD_AND_STORE_5 =>
if(IR >= x"86" and IR <= x"89")then -- LOAD IMMEDIATE
PC_Inc <= '1';
elsif(IR = x"96" or IR = x"97")then
PC_Inc <= '1';
end if;
next_state <= S_LOAD_AND_STORE_6;
when S_LOAD_AND_STORE_6 =>
if(IR=x"86")then -- LOAD IMMEDIATE A
Bus2_Sel <= "10";
A_Load <= '1';
next_state <= S_FETCH_0;
elsif(IR=x"87" or IR=x"89") then -- LOAD A DIRECT
Bus2_Sel <= "10";
MAR_Load <= '1';
next_state <= S_LOAD_AND_STORE_7;
elsif(IR=x"88")then -- LOAD IMMEDIATE B
Bus2_Sel <= "10";
B_Load <= '1';
next_state <= S_FETCH_0;
elsif(IR = x"96" or IR = x"97")then
Bus2_Sel <= "10";
MAR_Load <= '1';
next_state <= S_LOAD_AND_STORE_7;
end if;
when S_LOAD_AND_STORE_7 =>
if(IR=x"87") then
Bus2_Sel <= "10";
A_Load <= '1';
next_state <= S_FETCH_0;
elsif(IR=x"89") then
Bus2_Sel <= "10";
B_Load <= '1';
next_state <= S_FETCH_0;
elsif(IR=x"96") then
write <= '1';
Bus1_Sel <= "01";
next_state <= S_FETCH_0;
elsif(IR=x"97") then
write <= '1';
Bus1_Sel <= "10";
next_state <= S_FETCH_0;
end if;
---- DATA MANIPULATION INSTRUCTIONS:
when S_DATA_MAN_4 =>
CCR_Load <= '1';
if(IR=x"42") then
ALU_Sel <= "000";
Bus1_Sel <= "01";
Bus2_Sel <= "00";
A_Load <= '1';
elsif(IR=x"43") then
ALU_Sel <= "001";
Bus1_Sel <= "01";
Bus2_Sel <= "00";
A_Load <= '1';
elsif(IR=x"44") then
ALU_Sel <= "010";
Bus1_Sel <= "01";
Bus2_Sel <= "00";
A_Load <= '1';
elsif(IR=x"45") then
ALU_Sel <= "011";
Bus1_Sel <= "01";
Bus2_Sel <= "00";
A_Load <= '1';
elsif(IR=x"46") then
ALU_Sel <= "100";
Bus1_Sel <= "01";
Bus2_Sel <= "00";
A_Load <= '1';
elsif(IR=x"47") then
ALU_Sel <= "100";
Bus1_Sel <= "10";
Bus2_Sel <= "00";
B_Load <= '1';
elsif(IR=x"48") then
ALU_Sel <= "101";
Bus1_Sel <= "01";
Bus2_Sel <= "00";
A_Load <= '1';
elsif(IR=x"49") then
ALU_Sel <= "101";
Bus1_Sel <= "10";
Bus2_Sel <= "00";
B_Load <= '1';
end if;
next_state <= S_FETCH_0;
when S_BRANCH_4 =>
if(IR >= x"20" and IR <= x"28")then -- BRA
Bus1_Sel <= "00";
Bus2_Sel <= "01";
MAR_Load <= '1';
end if;
next_state <= S_BRANCH_5;
when S_BRANCH_5 =>
if(IR >= x"20" and IR <= x"28")then -- BRA
PC_Inc <= '1';
end if;
next_state <= S_BRANCH_6;
when S_BRANCH_6 =>
if(IR=x"20")then -- BRA
Bus2_Sel <= "10";
PC_Load <= '1';
elsif(IR=x"21")then -- BMI
Bus2_Sel <= "10";
if(CCR_Result(3)='1') then
PC_Load <= '1';
end if;
elsif(IR=x"22")then -- BPL
Bus2_Sel <= "10";
if(CCR_Result(3)='0') then
PC_Load <= '1';
end if;
elsif(IR=x"23")then -- BEQ
Bus2_Sel <= "10";
if(CCR_Result(2)='1') then-- Z = '1'?
PC_Load <= '1';
end if;
elsif(IR=x"24")then -- BNE
Bus2_Sel <= "10";
if(CCR_Result(2)='0') then-- Z = '0'?
PC_Load <= '1';
end if;
elsif(IR=x"25")then -- BVS
Bus2_Sel <= "10";
if(CCR_Result(1)='1') then-- V = '1'?
PC_Load <= '1';
end if;
elsif(IR=x"26")then -- BVC
Bus2_Sel <= "10";
if(CCR_Result(1)='0') then-- V = '0'?
PC_Load <= '1';
end if;
elsif(IR=x"27")then -- BCS
Bus2_Sel <= "10";
if(CCR_Result(0)='1') then-- C = '1'?
PC_Load <= '1';
end if;
elsif(IR=x"28")then -- BCC
Bus2_Sel <= "10";
if(CCR_Result(0)='0') then-- C = '0'?
PC_Load <= '1';
end if;
end if;
next_state <= S_FETCH_0;
when others =>
next_state <= S_FETCH_0;
end case;
end process;
LOAD_STORE_OP <= '1' when IR = x"86" else
'1' when IR = x"87" else
'1' when IR = x"88" else
'1' when IR = x"89" else
'1' when IR = x"96" else
'1' when IR = x"97" else
'0';
DATA_MAN_OP <= '1' when (IR >= x"42" and IR <=x"49") else
'0';
BRANCH_OP <= '1' when (IR >= x"20" and IR <= x"28") else
'0';
end Behavioral;
--fpga4student.com FPGA projects, Verilog projects, VHDL projects