1 |
22 |
leonardoar |
--! @file
|
2 |
|
|
--! @brief ControlUnit http://en.wikipedia.org/wiki/Control_unit
|
3 |
|
|
|
4 |
|
|
--! Use standard library and import the packages (std_logic_1164,std_logic_unsigned,std_logic_arith)
|
5 |
|
|
library IEEE;
|
6 |
|
|
use ieee.std_logic_1164.all;
|
7 |
|
|
use ieee.std_logic_unsigned.all;
|
8 |
|
|
use ieee.std_logic_arith.all;
|
9 |
|
|
|
10 |
|
|
--! Use CPU Definitions package
|
11 |
|
|
use work.pkgOpenCPU32.all;
|
12 |
|
|
|
13 |
|
|
--! The control unit coordinates the input and output devices of a computer system. It fetches the code of all of the instructions \n
|
14 |
|
|
--! in the microprograms. It directs the operation of the other units by providing timing and control signals. \n
|
15 |
|
|
--! all computer resources are managed by the Control Unit.It directs the flow of data between the cpu and the other devices.\n
|
16 |
|
|
--! The outputs of the control unit control the activity of the rest of the device. A control unit can be thought of as a finite-state machine.
|
17 |
|
|
|
18 |
|
|
--! The purpose of datapaths is to provide routes for data to travel between functional units.
|
19 |
|
|
entity ControlUnit is
|
20 |
24 |
leonardoar |
generic (n : integer := nBits - 1); --! Generic value (Used to easily change the size of the Alu on the package)
|
21 |
|
|
Port ( reset : in STD_LOGIC;
|
22 |
28 |
leonardoar |
clk : in STD_LOGIC; --! Main system clock
|
23 |
|
|
FlagsDp : in STD_LOGIC_VECTOR (n downto 0); --! Flags comming from the Datapath
|
24 |
|
|
DataDp : in STD_LOGIC_VECTOR (n downto 0); --! Data comming from the Datapath
|
25 |
|
|
MuxDp : out STD_LOGIC_VECTOR (2 downto 0); --! Select on datapath data from (Memory, Imediate, RegFileA, RegFileB, AluOut)
|
26 |
27 |
leonardoar |
MuxRegDp : out STD_LOGIC_VECTOR(1 downto 0); --! Select Alu InputA (Memory,Imediate,RegFileA)
|
27 |
28 |
leonardoar |
ImmDp : out STD_LOGIC_VECTOR (n downto 0); --! Imediate value passed to the Datapath
|
28 |
27 |
leonardoar |
DpAluOp : out aluOps; --! Alu operations
|
29 |
28 |
leonardoar |
DpRegFileWriteAddr : out generalRegisters; --! General register address to write
|
30 |
|
|
DpRegFileWriteEn : out STD_LOGIC; --! Enable register write
|
31 |
|
|
DpRegFileReadAddrA : out generalRegisters; --! General register address to read
|
32 |
|
|
DpRegFileReadAddrB : out generalRegisters; --! General register address to read
|
33 |
|
|
DpRegFileReadEnA : out STD_LOGIC; --! Enable register read (PortA)
|
34 |
|
|
DpRegFileReadEnB : out STD_LOGIC; --! Enable register read (PortB)
|
35 |
|
|
MemoryDataReadEn : out std_logic; --! Enable Main memory read
|
36 |
|
|
MemoryDataWriteEn: out std_logic; --! Enable Main memory write
|
37 |
|
|
MemoryDataInput : in STD_LOGIC_VECTOR (n downto 0); --! Incoming data from main memory
|
38 |
|
|
MemoryDataAddr : out STD_LOGIC_VECTOR (n downto 0); --! Main memory write address
|
39 |
|
|
MemoryDataOut : out STD_LOGIC_VECTOR (n downto 0)); --! Data to write on main memory
|
40 |
22 |
leonardoar |
end ControlUnit;
|
41 |
|
|
|
42 |
|
|
--! @brief ControlUnit http://en.wikipedia.org/wiki/Control_unit
|
43 |
|
|
--! @details The control unit receives external instructions or commands which it converts into a sequence of control signals that the control \n
|
44 |
|
|
--! unit applies to data path to implement a sequence of register-transfer level operations.
|
45 |
|
|
architecture Behavioral of ControlUnit is
|
46 |
26 |
leonardoar |
|
47 |
25 |
leonardoar |
signal currentCpuState : controlUnitStates; -- CPU states
|
48 |
|
|
signal nextCpuState : controlUnitStates; -- CPU states
|
49 |
26 |
leonardoar |
|
50 |
|
|
signal currentExState : executionStates; -- Execution states
|
51 |
|
|
signal nextExState : executionStates; -- Execution states
|
52 |
|
|
|
53 |
25 |
leonardoar |
signal PC : std_logic_vector(n downto 0); -- Program Counter
|
54 |
|
|
signal IR : std_logic_vector(n downto 0); -- Intruction register
|
55 |
|
|
signal currInstruction : std_logic_vector(n downto 0); -- Current Intruction
|
56 |
22 |
leonardoar |
begin
|
57 |
24 |
leonardoar |
|
58 |
26 |
leonardoar |
-- Next state logic (CPU, fetch, decode, execute states)
|
59 |
24 |
leonardoar |
process (clk, reset)
|
60 |
|
|
begin
|
61 |
|
|
if (reset = '1') then
|
62 |
26 |
leonardoar |
currentCpuState <= initial;
|
63 |
24 |
leonardoar |
elsif rising_edge(clk) then
|
64 |
|
|
currentCpuState <= nextCpuState;
|
65 |
|
|
end if;
|
66 |
|
|
end process;
|
67 |
|
|
|
68 |
26 |
leonardoar |
-- Next state logic (Execution states)
|
69 |
|
|
process (clk, currentCpuState)
|
70 |
|
|
begin
|
71 |
27 |
leonardoar |
if ( (currentCpuState /= execute) and (currentCpuState /= executing) ) then
|
72 |
|
|
currentExState <= initInstructionExecution;
|
73 |
26 |
leonardoar |
elsif rising_edge(clk) then
|
74 |
|
|
currentExState <= nextExState;
|
75 |
|
|
end if;
|
76 |
|
|
end process;
|
77 |
|
|
|
78 |
25 |
leonardoar |
-- States Fetch, decode, execute from the processor
|
79 |
24 |
leonardoar |
process (currentCpuState)
|
80 |
25 |
leonardoar |
variable cyclesExecute : integer range 0 to 20; -- Cycles to wait while executing instruction
|
81 |
26 |
leonardoar |
variable opcodeIR : std_logic_vector(5 downto 0);
|
82 |
24 |
leonardoar |
begin
|
83 |
26 |
leonardoar |
opcodeIR := IR((IR'HIGH) downto (IR'HIGH - 5));
|
84 |
24 |
leonardoar |
case currentCpuState is
|
85 |
|
|
-- Initial state left from reset ...
|
86 |
|
|
when initial =>
|
87 |
25 |
leonardoar |
cyclesExecute := 0;
|
88 |
24 |
leonardoar |
PC <= (others => '0');
|
89 |
25 |
leonardoar |
IR <= (others => '0');
|
90 |
24 |
leonardoar |
MemoryDataAddr <= (others => '0');
|
91 |
28 |
leonardoar |
MemoryDataReadEn <= '0';
|
92 |
|
|
MemoryDataWriteEn <= '0';
|
93 |
26 |
leonardoar |
MemoryDataAddr <= (others => '0');
|
94 |
24 |
leonardoar |
nextCpuState <= fetch;
|
95 |
|
|
|
96 |
|
|
-- Fetch state (Go to memory and get a instruction)
|
97 |
|
|
when fetch =>
|
98 |
|
|
-- Increment program counter (Remember that PC will be update only on the next cycle...
|
99 |
|
|
PC <= PC + conv_std_logic_vector(1, nBits);
|
100 |
|
|
MemoryDataAddr <= PC; -- Warning PC is not 1 yet...
|
101 |
|
|
IR <= MemoryDataInput;
|
102 |
28 |
leonardoar |
MemoryDataReadEn <= '1';
|
103 |
24 |
leonardoar |
nextCpuState <= decode;
|
104 |
|
|
|
105 |
25 |
leonardoar |
-- Detect with instruction came from memory, set the number of cycles to execute...
|
106 |
24 |
leonardoar |
when decode =>
|
107 |
28 |
leonardoar |
MemoryDataReadEn <= '0';
|
108 |
|
|
MemoryDataWriteEn <= '0';
|
109 |
25 |
leonardoar |
|
110 |
|
|
-- The high attribute points to the highes bit position
|
111 |
26 |
leonardoar |
case opcodeIR is
|
112 |
27 |
leonardoar |
when mov_reg | mov_val | add_reg | sub_reg | and_reg | or_reg | xor_reg =>
|
113 |
25 |
leonardoar |
nextCpuState <= execute;
|
114 |
27 |
leonardoar |
cyclesExecute := 3; -- Wait 3 cycles for mov operation
|
115 |
25 |
leonardoar |
currInstruction <= IR;
|
116 |
26 |
leonardoar |
-- Invalid instruction (Now will be ignored, but latter should raise a trap
|
117 |
25 |
leonardoar |
when others =>
|
118 |
|
|
end case;
|
119 |
24 |
leonardoar |
|
120 |
25 |
leonardoar |
-- Wait while the process that handles the execution works..
|
121 |
|
|
when execute =>
|
122 |
26 |
leonardoar |
if cyclesExecute = 0 then
|
123 |
|
|
-- Finish the instruction execution get next
|
124 |
25 |
leonardoar |
nextCpuState <= fetch;
|
125 |
26 |
leonardoar |
else
|
126 |
|
|
nextCpuState <= executing;
|
127 |
|
|
end if;
|
128 |
|
|
|
129 |
|
|
-- Just wait a cycle and back again to execute state which verify if still need to wait some cycles
|
130 |
|
|
when executing =>
|
131 |
|
|
cyclesExecute := cyclesExecute - 1;
|
132 |
|
|
nextCpuState <= execute;
|
133 |
|
|
|
134 |
24 |
leonardoar |
when others =>
|
135 |
|
|
null;
|
136 |
|
|
end case;
|
137 |
25 |
leonardoar |
end process;
|
138 |
|
|
|
139 |
|
|
-- Process that handles the execution of each instruction
|
140 |
26 |
leonardoar |
process (currentExState)
|
141 |
|
|
--variable operando1_reg : std_logic_vector(generalRegisters'range);
|
142 |
27 |
leonardoar |
variable opcodeIR : std_logic_vector(5 downto 0);
|
143 |
|
|
variable operand_reg1 : std_logic_vector(3 downto 0);
|
144 |
|
|
variable operand_reg2 : std_logic_vector(3 downto 0);
|
145 |
|
|
variable operand_imm : std_logic_vector(21 downto 0);
|
146 |
25 |
leonardoar |
begin
|
147 |
27 |
leonardoar |
-- Parse the common operands
|
148 |
|
|
opcodeIR := IR((IR'HIGH) downto (IR'HIGH - 5)); -- 6 Bits opcode (Max 64 instructions)
|
149 |
|
|
operand_reg1 := IR((IR'HIGH - 6) downto (IR'HIGH - 9)); -- 4 bits register operand1 (Max 16 registers)
|
150 |
|
|
operand_reg2 := IR((IR'HIGH - 10) downto (IR'HIGH - 13)); -- 4 bits register operand2 (Max 16 registers
|
151 |
|
|
operand_imm := IR((IR'HIGH - 10) downto (IR'LOW)); -- 22 bits imediate value (Max value 4194304)
|
152 |
|
|
|
153 |
|
|
-- Select the instruction and init it's execution
|
154 |
26 |
leonardoar |
case currentExState is
|
155 |
27 |
leonardoar |
when initInstructionExecution =>
|
156 |
|
|
case opcodeIR is
|
157 |
|
|
-- MOV r2,r1 (See the testDatapath to see how to drive the datapath for this function)
|
158 |
|
|
when mov_reg =>
|
159 |
|
|
MuxDp <= muxPos(fromRegFileB);
|
160 |
|
|
DpRegFileReadAddrB <= Num2reg(conv_integer(UNSIGNED(operand_reg2)));
|
161 |
|
|
DpRegFileWriteAddr <= Num2reg(conv_integer(UNSIGNED(operand_reg1)));
|
162 |
|
|
DpRegFileReadEnB <= '1';
|
163 |
|
|
nextExState <= writeRegister;
|
164 |
|
|
|
165 |
|
|
-- ADD r2,r0 (See the testDatapath to see how to drive the datapath for this function)
|
166 |
|
|
when add_reg | sub_reg | and_reg | or_reg | xor_reg =>
|
167 |
|
|
MuxDp <= muxPos(fromAlu);
|
168 |
|
|
MuxRegDp <= muxRegPos(fromRegFileA);
|
169 |
|
|
DpRegFileReadAddrA <= Num2reg(conv_integer(UNSIGNED(operand_reg1))); -- Read first operand
|
170 |
|
|
DpRegFileReadAddrB <= Num2reg(conv_integer(UNSIGNED(operand_reg2))); -- Read second operand
|
171 |
|
|
DpRegFileReadEnA <= '1';
|
172 |
|
|
DpRegFileReadEnB <= '1';
|
173 |
|
|
DpRegFileWriteAddr <= Num2reg(conv_integer(UNSIGNED(operand_reg1))); -- Point to write in first operand (pointing to register)
|
174 |
|
|
DpAluOp <= opcode2AluOp(opcodeIR); -- Select the alu operation from the operand
|
175 |
|
|
nextExState <= writeRegister;
|
176 |
|
|
|
177 |
|
|
-- MOV r0,10d (See the testDatapath to see how to drive the datapath for this function)
|
178 |
|
|
when mov_val =>
|
179 |
|
|
MuxDp <= muxPos(fromImediate);
|
180 |
|
|
DpRegFileWriteAddr <= Num2reg(conv_integer(UNSIGNED(operand_reg1)));
|
181 |
|
|
ImmDp <= "0000000000" & operand_imm; -- & is used to concatenate signals
|
182 |
|
|
nextExState <= writeRegister;
|
183 |
|
|
|
184 |
|
|
-- ADD r3,2 (r2 <= r2+2) (See the testDatapath to see how to drive the datapath for this function)
|
185 |
|
|
when add_val | sub_val | and_val | or_val | xor_val =>
|
186 |
|
|
MuxDp <= muxPos(fromAlu);
|
187 |
|
|
MuxRegDp <= muxRegPos(fromImediate);
|
188 |
|
|
DpRegFileWriteAddr <= Num2reg(conv_integer(UNSIGNED(operand_reg1)));
|
189 |
|
|
DpRegFileReadAddrB <= Num2reg(conv_integer(UNSIGNED(operand_reg1))); -- Read first operand
|
190 |
|
|
DpRegFileReadEnB <= '1';
|
191 |
|
|
ImmDp <= "0000000000" & operand_imm; -- & is used to concatenate signals
|
192 |
|
|
DpAluOp <= opcode2AluOp(opcodeIR); -- Select the alu operation from the operand
|
193 |
|
|
nextExState <= writeRegister;
|
194 |
|
|
|
195 |
26 |
leonardoar |
when others =>
|
196 |
|
|
null;
|
197 |
|
|
end case;
|
198 |
27 |
leonardoar |
|
199 |
|
|
-- Write something on the register files
|
200 |
|
|
when writeRegister =>
|
201 |
|
|
DpRegFileWriteEn <= '1';
|
202 |
|
|
nextExState <= releaseWriteRead;
|
203 |
|
|
|
204 |
|
|
-- Release lines (Reset Datapath lines to something that does nothing...)
|
205 |
|
|
when releaseWriteRead =>
|
206 |
|
|
DpRegFileReadEnB <= '0';
|
207 |
|
|
DpRegFileReadEnA <= '0';
|
208 |
|
|
DpRegFileWriteEn <= '0';
|
209 |
|
|
|
210 |
26 |
leonardoar |
when others =>
|
211 |
|
|
null;
|
212 |
|
|
end case;
|
213 |
24 |
leonardoar |
end process;
|
214 |
22 |
leonardoar |
|
215 |
|
|
end Behavioral;
|
216 |
|
|
|