0% found this document useful (0 votes)
11 views14 pages

VHDL Components for ALU and Control Unit

The document describes a hardware design in VHDL for a processor architecture, including components like an ALU, register file, multiplexers, program counter, control unit, and various other units such as a counter and MAC unit. Each component is defined with its respective ports and architecture, detailing how they interact within the processor. The design also includes UART transmission components and a testbench for the processor.

Uploaded by

dn926900
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views14 pages

VHDL Components for ALU and Control Unit

The document describes a hardware design in VHDL for a processor architecture, including components like an ALU, register file, multiplexers, program counter, control unit, and various other units such as a counter and MAC unit. Each component is defined with its respective ports and architecture, detailing how they interact within the processor. The design also includes UART transmission components and a testbench for the processor.

Uploaded by

dn926900
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Alu

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity alu is
port(
A : in std_logic_vector(15 downto 0);
B : in std_logic_vector(15 downto 0);
Op : in std_logic_vector(2 downto 0); -- 3-bit op
Res : out std_logic_vector(15 downto 0);
Zero : out std_logic
);
end entity;

architecture rtl of alu is


signal a_i, b_i, r_i : signed(15 downto 0);
begin
a_i <= signed(A);
b_i <= signed(B);

process(a_i, b_i, Op)


begin
case Op is
when "000" => r_i <= a_i + b_i; -- ADD
when "001" => r_i <= a_i - b_i; -- SUB
when "010" => r_i <= a_i and b_i; -- AND (bitwise)
when "011" => r_i <= a_i or b_i; -- OR (bitwise)
when others => r_i <= (others => '0');
end case;
Res <= std_logic_vector(r_i);
if r_i = 0 then
Zero <= '1';
else
Zero <= '0';
end if;
end process;
end architecture;

Regfile.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity reg_file is
port(
clk : in std_logic;
we : in std_logic;
rd_addr: in std_logic_vector(2 downto 0);
rs_addr: in std_logic_vector(2 downto 0);
rt_addr: in std_logic_vector(2 downto 0);
wd : in std_logic_vector(15 downto 0);
rd_out : out std_logic_vector(15 downto 0);
rs_out : out std_logic_vector(15 downto 0);
rt_out : out std_logic_vector(15 downto 0)
);
end entity;
architecture beh of reg_file is
type regfile_t is array (0 to 7) of std_logic_vector(15 downto 0);
signal rf : regfile_t := (others => (others => '0'));
signal rs_i, rt_i, rd_i : std_logic_vector(15 downto 0);
signal rd_idx, rs_idx, rt_idx: integer range 0 to 7;
begin
rd_idx <= to_integer(unsigned(rd_addr));
rs_idx <= to_integer(unsigned(rs_addr));
rt_idx <= to_integer(unsigned(rt_addr));

rs_out <= rf(rs_idx);


rt_out <= rf(rt_idx);
rd_out <= rf(rd_idx);

process(clk)
begin
if rising_edge(clk) then
if we = '1' then
rf(rd_idx) <= wd;
end if;
end if;
end process;
end architecture;

Mux 2x1
library ieee;
use ieee.std_logic_1164.all;

entity mux_2x1 is
port(
a, b : in std_logic_vector(15 downto 0);
sel : in std_logic;
y : out std_logic_vector(15 downto 0)
);
end entity;

architecture rtl of mux_2x1 is


begin
y <= a when sel = '0' else b;
end architecture;

Mux 4x1
library ieee;
use ieee.std_logic_1164.all;

entity mux_4x1 is
port(
d0, d1, d2, d3: in std_logic_vector(15 downto 0);
sel : in std_logic_vector(1 downto 0);
y : out std_logic_vector(15 downto 0)
);
end entity;

architecture rtl of mux_4x1 is


begin
process(d0,d1,d2,d3,sel)
begin
case sel is
when "00" => y <= d0;
when "01" => y <= d1;
when "10" => y <= d2;
when "11" => y <= d3;
when others => y <= (others => '0');
end case;
end process;
end architecture;

Pc.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity pc is
port(
clk : in std_logic;
rst : in std_logic;
load : in std_logic;
din : in std_logic_vector(11 downto 0);
pc_out: out std_logic_vector(11 downto 0)
);
end entity;

architecture rtl of pc is
signal pc_r: unsigned(11 downto 0) := (others => '0');
begin
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
pc_r <= (others => '0');
elsif load = '1' then
pc_r <= unsigned(din);
else
pc_r <= pc_r + 1;
end if;
end if;
end process;
pc_out <= std_logic_vector(pc_r);
end architecture;

Control unit.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity control_unit is
port(
inst : in std_logic_vector(15 downto 0);
-- outputs
alu_op : out std_logic_vector(2 downto 0);
reg_write : out std_logic;
mem_read : out std_logic;
mem_write : out std_logic;
alu_src : out std_logic; -- 0: reg, 1: imm/addr
pc_load : out std_logic;
halt : out std_logic
);
end entity;

architecture rtl of control_unit is


signal opcode: std_logic_vector(3 downto 0);
begin
opcode <= inst(15 downto 12);

process(opcode)
begin
-- defaults
alu_op <= "000";
reg_write <= '0';
mem_read <= '0';
mem_write <= '0';
alu_src <= '0';
pc_load <= '0';
halt <= '0';

case opcode is
when "0000" => -- NOP
null;
when "0001" => -- ADD
alu_op <= "000"; reg_write <= '1';
when "0010" => -- SUB
alu_op <= "001"; reg_write <= '1';
when "0011" => -- AND
alu_op <= "010"; reg_write <= '1';
when "0100" => -- OR
alu_op <= "011"; reg_write <= '1';
when "0101" => -- LD rd,addr
alu_op <= "000"; reg_write <= '1'; mem_read <= '1'; alu_src <= '1';
when "0110" => -- ST rs,addr
mem_write <= '1'; alu_src <= '1';
when "0111" => -- JMP addr
pc_load <= '1';
when "1000" => -- BEQ (branch implemented in datapath using Zero)
-- control unit doesn't set pc_load directly here
null;
when "1111" => -- HALT
halt <= '1';
when others =>
null;
end case;
end process;
end architecture;

Processor.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity processor is
port(
clk : in std_logic;
rst : in std_logic;
-- optional debug ports
dbg_pc : out std_logic_vector(11 downto 0);
dbg_reg0: out std_logic_vector(15 downto 0)
);
end entity;

architecture top of processor is


signal pc : std_logic_vector(11 downto 0);
signal inst : std_logic_vector(15 downto 0);
signal alu_op, reg_write, mem_read, mem_write, alu_src, pc_load, halt_sig : std_logic_vector(2 downto 0);
signal cu_alu_op: std_logic_vector(2 downto 0);
signal cu_reg_write, cu_mem_read, cu_mem_write, cu_alu_src, cu_pc_load, cu_halt : std_logic;
signal mem_rdata: std_logic_vector(15 downto 0);
signal mem_addr: std_logic_vector(11 downto 0);
signal mem_wdata: std_logic_vector(15 downto 0);
begin
-- inst mem
IM: entity work.inst_mem
port map(addr => pc, inst => inst);

-- control
CU: entity work.control_unit
port map(inst => inst,
alu_op => cu_alu_op,
reg_write => cu_reg_write,
mem_read => cu_mem_read,
mem_write => cu_mem_write,
alu_src => cu_alu_src,
pc_load => cu_pc_load,
halt => cu_halt
);

-- data path
DP: entity work.data_path
port map(
clk => clk,
rst => rst,
inst => inst,
alu_op => cu_alu_op,
reg_write => cu_reg_write,
mem_read => cu_mem_read,
mem_write => cu_mem_write,
alu_src => cu_alu_src,
pc_load => cu_pc_load,
mem_addr => mem_addr,
mem_wdata => mem_wdata,
mem_we => open,
mem_rdata => mem_rdata,
pc_out => pc,
pc_in => pc,
halt => open
);

-- data memory
DM: entity work.data_mem
port map(
clk => clk,
we => cu_mem_write,
addr => mem_addr,
din => mem_wdata,
dout => mem_rdata
);

-- simple PC: increment or load (CU provides load; for branch you can extend)
PCU: entity [Link]
port map(clk => clk, rst => rst, load => cu_pc_load, din => inst(11 downto 0), pc_out => pc);

-- debug outputs
dbg_pc <= pc;
dbg_reg0 <= (others=>'0'); -- stub
end architecture;

Counter.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter is
port(clk: in std_logic; rst: in std_logic; cnt: out std_logic_vector(15 downto 0));
end entity;

architecture rtl of counter is


signal c: unsigned(15 downto 0) := (others => '0');
begin
process(clk)
begin
if rising_edge(clk) then
if rst='1' then c <= (others=>'0'); else c <= c + 1; end if;
end if;
end process;
cnt <= std_logic_vector(c);
end architecture;

Se unit.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity se_unit is
port(in6: in std_logic_vector(5 downto 0); out16: out std_logic_vector(15 downto 0));
end entity;

architecture rtl of se_unit is


begin
out16 <= (15 downto 6 => in6(5)) & in6; -- sign replicate
end architecture;

Status register
library ieee;
use ieee.std_logic_1164.all;
entity status_register is
port(clk: in std_logic; rst: in std_logic; z_in: in std_logic; z_out: out std_logic);
end entity;

architecture rtl of status_register is


signal z: std_logic := '0';
begin
process(clk)
begin
if rising_edge(clk) then
if rst='1' then z <= '0'; else z <= z_in; end if;
end if;
end process;
z_out <= z;
end architecture;

Temp storage
library ieee;
use ieee.std_logic_1164.all;

entity temp_storage is
port(clk: in std_logic; din: in std_logic_vector(15 downto 0); dout: out std_logic_vector(15 downto 0));
end entity;

architecture rtl of temp_storage is


signal r: std_logic_vector(15 downto 0) := (others => '0');
begin
process(clk)
begin
if rising_edge(clk) then
r <= din;
end if;
end process;
dout <= r;
end architecture;

Macunit:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity mac_unit is
port(a,b: in std_logic_vector(15 downto 0); clk: in std_logic; outp: out std_logic_vector(31 downto 0));
end entity;

architecture rtl of mac_unit is


signal r: signed(31 downto 0) := (others => '0');
begin
process(clk)
begin
if rising_edge(clk) then
r <= r + (signed(a) * signed(b));
end if;
end process;
outp <= std_logic_vector(r);
end architecture;

Dreg.v
library ieee;
use ieee.std_logic_1164.all;

entity dreg is
port(clk: in std_logic; din: in std_logic_vector(15 downto 0); dout: out std_logic_vector(15 downto 0));
end entity;
architecture rtl of dreg is
signal r: std_logic_vector(15 downto 0);
begin
process(clk) begin
if rising_edge(clk) then r <= din; end if;
end process;
dout <= r;
end architecture;

Pgen.v
library ieee;
use ieee.std_logic_1164.all;

entity pgen is
port(clk: in std_logic; pulse_out: out std_logic);
end entity;

architecture rtl of pgen is


signal cnt: integer := 0;
begin
process(clk) begin
if rising_edge(clk) then
if cnt = 9 then
cnt <= 0; pulse_out <= '1';
else
cnt <= cnt + 1; pulse_out <= '0';
end if;
end if;
end process;
end architecture;

Txreg.v
library ieee;
use ieee.std_logic_1164.all;

entity txreg is
port(clk: in std_logic; load: in std_logic; din: in std_logic_vector(7 downto 0); dout: out std_logic_vector(7
downto 0));
end entity;

architecture rtl of txreg is


signal r: std_logic_vector(7 downto 0);
begin
process(clk) begin
if rising_edge(clk) then
if load='1' then r <= din; end if;
end if;
end process;
dout <= r;
end architecture;

Cu uart
-- cu_uart_tx.vhd (control unit for uart tx) - minimal stub
library ieee; use ieee.std_logic_1164.all;
entity cu_uart_tx is port(clk: in std_logic; start: in std_logic; busy: out std_logic); end entity;
architecture rtl of cu_uart_tx is begin busy <= '0'; end architecture;

-- dp_uart.vhd (data path for uart) - minimal stub


library ieee; use ieee.std_logic_1164.all;
entity dp_uart is port(clk: in std_logic; tx_data: in std_logic_vector(7 downto 0); tx_ready: out std_logic); end
entity;
architecture rtl of dp_uart is begin tx_ready <= '1'; end architecture;

Dpuart
-- cu_uart_tx.vhd (control unit for uart tx) - minimal stub
library ieee; use ieee.std_logic_1164.all;
entity cu_uart_tx is port(clk: in std_logic; start: in std_logic; busy: out std_logic); end entity;
architecture rtl of cu_uart_tx is begin busy <= '0'; end architecture;

-- dp_uart.vhd (data path for uart) - minimal stub


library ieee; use ieee.std_logic_1164.all;
entity dp_uart is port(clk: in std_logic; tx_data: in std_logic_vector(7 downto 0); tx_ready: out std_logic); end
entity;
architecture rtl of dp_uart is begin tx_ready <= '1'; end architecture;

Uart tx.v
library ieee; use ieee.std_logic_1164.all;
entity uart_tx is port(clk: in std_logic; tx_byte: in std_logic_vector(7 downto 0); send: in std_logic; tx: out
std_logic); end entity;
architecture rtl of uart_tx is
begin
tx <= '1'; -- idle
end architecture;

Tb processor.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity tb_processor is
end entity;
architecture beh of tb_processor is
signal clk : std_logic := '0';
signal rst : std_logic := '1';
signal dbg_pc : std_logic_vector(11 downto 0);
signal dbg_r0 : std_logic_vector(15 downto 0);
begin
UUT: entity [Link]
port map(clk => clk, rst => rst, dbg_pc => dbg_pc, dbg_reg0 => dbg_r0);

-- clock 10ns
clk_proc: process
begin
while now < 1000 ns loop
clk <= '0'; wait for 5 ns;
clk <= '1'; wait for 5 ns;
end loop;
wait;
end process;

-- reset and stimulus


stim: process
begin
rst <= '1';
wait for 20 ns;
rst <= '0';
-- let it run
wait for 400 ns;
-- finish
report "Simulation finished. PC=" & integer'image(to_integer(unsigned(dbg_pc)));
wait;
end process;

end architecture;

Clock.v
library ieee;
use ieee.std_logic_1164.all;

entity clock_gen is
port(
clk : out std_logic
);
end entity;

architecture beh of clock_gen is


begin
process
begin
clk <= '0';
wait for 5 ns;
clk <= '1';
wait for 5 ns;
end process;
end architecture;
Datapath.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity data_path is
port(
clk : in std_logic;
rst : in std_logic;
inst : in std_logic_vector(15 downto 0);
-- control signals
alu_op : in std_logic_vector(2 downto 0);
reg_write: in std_logic;
mem_read : in std_logic;
mem_write: in std_logic;
alu_src : in std_logic;
pc_load : in std_logic;
-- memory interface
mem_addr : out std_logic_vector(11 downto 0);
mem_wdata: out std_logic_vector(15 downto 0);
mem_we : out std_logic;
mem_rdata: in std_logic_vector(15 downto 0);
-- PC interface
pc_out : out std_logic_vector(11 downto 0);
pc_in : in std_logic_vector(11 downto 0);
halt : out std_logic
);
end entity;

architecture rtl of data_path is


signal rd, rs, rt : std_logic_vector(2 downto 0);
signal imm6 : std_logic_vector(5 downto 0);
signal imm16 : std_logic_vector(15 downto 0);
signal rs_val, rt_val, rd_val, alu_b, alu_res : std_logic_vector(15 downto 0);
signal alu_zero: std_logic;
signal write_data: std_logic_vector(15 downto 0);
begin
rd <= inst(11 downto 9);
rs <= inst(8 downto 6);
rt <= inst(5 downto 3);
imm6 <= inst(5 downto 0);

-- sign-extend imm6 to 16 bits safely: replicate MSB imm6(5)


imm16 <= (15 downto 6 => imm6(5)) & imm6;

-- register file
RF: entity work.reg_file
port map(
clk => clk,
we => reg_write,
rd_addr => rd,
rs_addr => rs,
rt_addr => rt,
wd => write_data,
rd_out => rd_val,
rs_out => rs_val,
rt_out => rt_val
);
-- ALU B operand select: n?u alu_src='0' dùng rt_val, n?u '1' dùng imm16
alu_b <= rt_val when alu_src = '0' else imm16;

-- ALU
ALU: entity [Link]
port map(
A => rs_val,
B => alu_b,
Op => alu_op,
Res => alu_res,
Zero => alu_zero
);

-- Memory interface: dùng 12-bit address t? imm6 (b?ng cách gán cao bits 0)
mem_addr <= (11 downto 6 => '0') & imm6; -- "000" & imm6 v?i cùng kích th??c 12-bit

mem_we <= mem_write;


mem_wdata <= rs_val;

-- Writeback selection: t? mem ho?c ALU


write_data <= mem_rdata when mem_read = '1' else alu_res;

-- PC passthrough: datapath ch? xu?t pc_out = pc_in (PC ? module khác x? lý)
pc_out <= pc_in;

-- forward halt = '0' (control unit ?i?u khi?n)


halt <= '0';
end architecture;

Instmem_v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity inst_mem is
port(
addr : in std_logic_vector(11 downto 0);
inst : out std_logic_vector(15 downto 0)
);
end entity;

architecture rtl of inst_mem is


type rom_t is array(0 to 4095) of std_logic_vector(15 downto 0);
signal ROM : rom_t := (
-- Program:
-- LD R1,10 => 0x520A
0 => x"520A",

-- LD R2,11 => 0x540B


1 => x"540B",

-- ADD R3,R1,R2 => 0x1650


2 => x"1650",

-- ST R3,12 => 0x60CC


3 => x"60CC",
-- HALT => 0xF000
4 => x"F000",

others => (others => '0')


);
begin
inst <= ROM(to_integer(unsigned(addr)));
end architecture;

Datamem.v
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity data_mem is
port(
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector(11 downto 0);
din : in std_logic_vector(15 downto 0);
dout : out std_logic_vector(15 downto 0)
);
end entity;

architecture rtl of data_mem is


type ram_t is array(0 to 4095) of std_logic_vector(15 downto 0);
signal RAM : ram_t := (
10 => x"0005", -- s? 5
11 => x"0007", -- s? 7
others => (others => '0')
);
begin

process(clk)
begin
if rising_edge(clk) then
if we = '1' then
RAM(to_integer(unsigned(addr))) <= din;
end if;
end if;
end process;

dout <= RAM(to_integer(unsigned(addr)));

end architecture;
Fetch (Lấy lệnh)

Nói đơn giản: CPU đi lấy lệnh về đọc.

2️⃣Decode (Giải mã lệnh)

👉 Nói đơn giản: CPU hiểu lệnh đó yêu cầu làm gì.

3️⃣Execute (Thực thi)

👉 Nói đơn giản: CPU làm đúng việc mà lệnh yêu cầu.

You might also like