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.