Skip to content

Instantly share code, notes, and snippets.

@stone3311
Last active February 19, 2017 12:01
Show Gist options
  • Select an option

  • Save stone3311/12b6d7cf1cd614d184e47efcb038ed73 to your computer and use it in GitHub Desktop.

Select an option

Save stone3311/12b6d7cf1cd614d184e47efcb038ed73 to your computer and use it in GitHub Desktop.
A simple 4-bit processor, written in VHDL, moved to https://github.com/stone3311/f4001
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
ENTITY alu IS
PORT (
opcode : IN std_logic_vector (7 DOWNTO 0);
in_0, in_1 : IN std_logic_vector (3 DOWNTO 0);
output : OUT std_logic_vector (3 DOWNTO 0);
equal_zero : OUT std_logic;
nequal_zero: OUT std_logic;
clk: IN std_logic
);
END alu;
ARCHITECTURE Behaviour OF alu IS
-- SIGNAL mirror: std_logic_vector (3 DOWNTO 0) := "1111";
BEGIN
PROCESS(clk)
BEGIN
IF (rising_edge(clk)) THEN
IF opcode(7 DOWNTO 4) = "0001" THEN -- alu
CASE opcode(3 DOWNTO 0) IS
WHEN "0000" => output <= std_logic_vector(unsigned(in_0) + unsigned(in_1));
WHEN "0001" => output <= std_logic_vector(unsigned(in_0) - unsigned(in_1));
WHEN "0010" => output <= std_logic_vector(unsigned(in_0) and unsigned(in_1));
WHEN "0011" => output <= std_logic_vector(unsigned(in_0) or unsigned(in_1));
WHEN "0100" => output <= std_logic_vector(rotate_left(unsigned(in_0), to_integer(unsigned(in_1))));
WHEN "0101" => output <= std_logic_vector(rotate_right(unsigned(in_0), to_integer(unsigned(in_1))));
WHEN "0110" => output <= std_logic_vector(unsigned(in_0(1 DOWNTO 0)) * unsigned(in_1(1 DOWNTO 0)));
WHEN "0111" => output <= std_logic_vector(unsigned(in_0) / unsigned(in_1));
-- WHEN "1000" => output(1 DOWNTO 0) <= in_0 (3 DOWNTO 2); output(3 DOWNTO 2) <= in_0 (1 DOWNTO 0);
WHEN others => output <= (others => '0');
END CASE;
ELSIF opcode(7 DOWNTO 4) = "0111" THEN -- cmp
equal_zero <= '0';
nequal_zero <= '0';
IF in_0 = "0000" THEN
equal_zero <= '1';
ELSE
nequal_zero <= '1';
END IF;
END IF;
END IF;
END PROCESS;
END Behaviour;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
ENTITY clockdivider IS
PORT (
clk_in : IN std_logic;
clk_out: OUT std_logic;
clk_ena: IN std_logic := '1'
);
END clockdivider;
ARCHITECTURE Behaviour OF clockdivider IS
BEGIN
PROCESS (clk_in)
VARIABLE divider : std_logic_vector (23 DOWNTO 0) := (others => '0');
VARIABLE state : std_logic := '0';
BEGIN
IF rising_edge(clk_in) THEN
divider := std_logic_vector(unsigned(divider) + 1);
IF unsigned(divider) = 50000 THEN
divider := (others => '0');
state := not state;
IF clk_ena = '1' THEN
clk_out <= state;
END IF;
END IF;
END IF;
END PROCESS;
END Behaviour;
library ieee;
use ieee.std_logic_1164.all;
ENTITY f4001 IS
PORT(
input_0, input_1 : IN std_logic;
output_0, output_1: OUT std_logic;
global_clk : IN std_logic
);
END f4001;
ARCHITECTURE Behaviour OF f4001 IS
SIGNAL opcode_bus : std_logic_vector (7 DOWNTO 0) := (others => '1');
SIGNAL romaddr_bus: std_logic_vector (7 DOWNTO 0) := (others => '0');
SIGNAL reg_a, reg_d, reg_hi, reg_lo : std_logic_vector (3 DOWNTO 0);
SIGNAL regmemdata : std_logic_vector (3 DOWNTO 0);
SIGNAL regaludata : std_logic_vector (3 DOWNTO 0);
SIGNAL alu_eqz, alu_nqz : std_logic;
SIGNAL peripherals_out: std_logic_vector (1 DOWNTO 0);
SIGNAL peripherals_in : std_logic_vector (1 DOWNTO 0);
SIGNAL clock_enable: std_logic := '1';
SIGNAL clock : std_logic;
-- NOTE: Used for the "In-System Sources and Probes Editor" in Quartus II
SIGNAL probesignal : std_logic_vector (7 DOWNTO 0);
COMPONENT probes
PORT (
probe : in std_logic_vector(7 downto 0) := (others => '0') -- probes.probe
);
END COMPONENT;
COMPONENT clockdivider
PORT (
clk_in : IN std_logic;
clk_out: OUT std_logic;
clk_ena: IN std_logic := '1'
);
END COMPONENT;
COMPONENT rom
PORT(
address: IN std_logic_vector (7 DOWNTO 0);
opcode: OUT std_logic_vector (7 DOWNTO 0) := (others => '1');
clk: IN std_logic
);
END COMPONENT;
COMPONENT pc
PORT(
opcode : IN std_logic_vector (7 DOWNTO 0);
address: OUT std_logic_vector (7 DOWNTO 0) := (others => '0');
addr_hi: IN std_logic_vector (3 DOWNTO 0);
addr_lo: IN std_logic_vector (3 DOWNTO 0);
equal_zero : IN std_logic;
nequal_zero: IN std_logic;
clk_ena: OUT std_logic := '1';
clk: IN std_logic
);
END COMPONENT;
COMPONENT registers
PORT(
opcode : IN std_logic_vector (7 DOWNTO 0);
memdata : IN std_logic_vector (3 DOWNTO 0);
aludata : IN std_logic_vector (3 DOWNTO 0);
a, d, hi, lo : OUT std_logic_vector (3 DOWNTO 0);
clk: IN std_logic
);
END COMPONENT;
COMPONENT alu
PORT (
opcode : IN std_logic_vector (7 DOWNTO 0);
in_0, in_1 : IN std_logic_vector (3 DOWNTO 0);
output : OUT std_logic_vector (3 DOWNTO 0);
equal_zero : OUT std_logic;
nequal_zero: OUT std_logic;
clk: IN std_logic
);
END COMPONENT;
COMPONENT memory
PORT(
opcode : IN std_logic_vector (7 DOWNTO 0);
addr_hi : IN std_logic_vector (3 DOWNTO 0);
addr_lo : IN std_logic_vector (3 DOWNTO 0);
periph_out: OUT std_logic_vector (1 DOWNTO 0);
periph_in : IN std_logic_vector (1 DOWNTO 0);
data : OUT std_logic_vector (3 DOWNTO 0);
a,d,hi,lo : IN std_logic_vector (3 DOWNTO 0);
clk: IN std_logic
);
END COMPONENT;
BEGIN
mydiv : clockdivider PORT MAP (global_clk, clock, clock_enable);
myrom : rom PORT MAP (romaddr_bus, opcode_bus, clock);
mypc : pc PORT MAP (opcode_bus, romaddr_bus, reg_hi, reg_lo, alu_eqz, alu_nqz, clock_enable, clock);
myregs: registers PORT MAP (opcode_bus, regmemdata, regaludata, reg_a, reg_d, reg_hi, reg_lo, clock);
myalu : alu PORT MAP (opcode_bus, reg_a, reg_d, regaludata, alu_eqz, alu_nqz, clock);
mymem : memory PORT MAP (opcode_bus, reg_hi, reg_lo, peripherals_out, peripherals_in, regmemdata, reg_a, reg_d, reg_hi, reg_lo, clock);
probesignal(3 DOWNTO 0) <= reg_a;
probesignal(7 DOWNTO 4) <= regaludata;
myprobe: probes PORT MAP (opcode_bus);
output_0 <= peripherals_out(0);
output_1 <= peripherals_out(1);
peripherals_in(0) <= input_0;
peripherals_in(1) <= input_1;
END Behaviour;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
ENTITY memory IS
PORT(
opcode : IN std_logic_vector (7 DOWNTO 0);
addr_hi : IN std_logic_vector (3 DOWNTO 0);
addr_lo : IN std_logic_vector (3 DOWNTO 0);
periph_out: OUT std_logic_vector (1 DOWNTO 0);
periph_in : IN std_logic_vector (1 DOWNTO 0);
data : OUT std_logic_vector (3 DOWNTO 0);
a,d,hi,lo : IN std_logic_vector (3 DOWNTO 0);
clk: IN std_logic
);
END memory;
ARCHITECTURE Behaviour OF memory IS
PROCEDURE read_register (signal reg: in std_logic_vector(1 DOWNTO 0); signal rvalue: out std_logic_vector (3 DOWNTO 0)) IS
BEGIN
CASE reg IS
WHEN "00" => rvalue <= a;
WHEN "01" => rvalue <= d;
WHEN "10" => rvalue <= hi;
WHEN "11" => rvalue <= lo;
END CASE;
END read_register;
CONSTANT memsize: natural := 1; -- Size of the SRAM in bytes, beginning at address 1
TYPE sram4 IS ARRAY (1 TO memsize) OF std_logic_vector (3 DOWNTO 0);
SIGNAL mem : sram4;
SIGNAL addr: std_logic_vector (7 DOWNTO 0);
SIGNAL ioreg: std_logic_vector (3 DOWNTO 0);
BEGIN
PROCESS (clk)
VARIABLE sp : std_logic_vector (7 DOWNTO 0) := std_logic_vector(to_unsigned(memsize, 8));
BEGIN
IF rising_edge(clk) THEN
IF opcode(7 DOWNTO 4) = "0011" THEN -- push
read_register(opcode(1 DOWNTO 0), mem(to_integer(unsigned(sp))));
sp := std_logic_vector( unsigned(sp) - 1 );
ELSIF opcode(7 DOWNTO 4) = "0100" THEN -- pop
data <= mem(to_integer(unsigned(sp)));
sp := std_logic_vector( unsigned(sp) + 1 );
ELSIF opcode(7 DOWNTO 4) = "0101" THEN -- sto
addr(7 DOWNTO 4) <= addr_hi;
addr(3 DOWNTO 0) <= addr_lo;
IF addr = "00000000" THEN
read_register(opcode(1 DOWNTO 0), ioreg);
periph_out <= ioreg(1 DOWNTO 0);
ELSE
read_register(opcode(1 DOWNTO 0), mem(to_integer(unsigned(addr))));
END IF;
ELSIF opcode(7 DOWNTO 4) = "0110" THEN -- lod
addr(7 DOWNTO 4) <= addr_hi;
addr(3 DOWNTO 0) <= addr_lo;
IF addr = "00000000" THEN
ioreg(3 DOWNTO 2) <= periph_in;
data <= ioreg;
ELSE
data <= mem(to_integer(unsigned(addr)));
END IF;
END IF;
END IF;
END PROCESS;
END Behaviour;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
ENTITY pc IS
PORT(
opcode : IN std_logic_vector (7 DOWNTO 0);
address: OUT std_logic_vector (7 DOWNTO 0) := (others => '0');
addr_hi: IN std_logic_vector (3 DOWNTO 0);
addr_lo: IN std_logic_vector (3 DOWNTO 0);
equal_zero : IN std_logic;
nequal_zero: IN std_logic;
clk_ena: OUT std_logic := '1';
clk: IN std_logic
);
END pc;
ARCHITECTURE Behaviour OF pc IS
BEGIN
PROCESS (clk)
VARIABLE current_address : std_logic_vector (7 DOWNTO 0) := "00000000";
BEGIN
IF rising_edge(clk) THEN
IF opcode(7 DOWNTO 4) = "1010" THEN -- jmp
current_address(7 DOWNTO 4) := addr_hi;
current_address(3 DOWNTO 0) := addr_lo;
ELSIF opcode(7 DOWNTO 4) = "1000" AND equal_zero = '1' THEN -- jiz
current_address(7 DOWNTO 4) := addr_hi;
current_address(3 DOWNTO 0) := addr_lo;
ELSIF opcode(7 DOWNTO 4) = "1001" AND nequal_zero = '1' THEN -- jnz
current_address(7 DOWNTO 4) := addr_hi;
current_address(3 DOWNTO 0) := addr_lo;
ELSIF opcode(7 DOWNTO 4) = "1110" THEN -- hlt
clk_ena <= '0';
ELSE
current_address := std_logic_vector( unsigned(current_address) + 1 );
END IF;
address <= current_address;
END IF;
END PROCESS;
END Behaviour;
library ieee;
use ieee.std_logic_1164.all;
ENTITY registers IS
PORT(
opcode : IN std_logic_vector (7 DOWNTO 0);
memdata : IN std_logic_vector (3 DOWNTO 0);
aludata : IN std_logic_vector (3 DOWNTO 0);
a, d, hi, lo : OUT std_logic_vector (3 DOWNTO 0);
clk: IN std_logic
);
END registers;
ARCHITECTURE Behaviour OF registers IS
SHARED VARIABLE register_a : std_logic_vector (3 DOWNTO 0) := (others => '0');
SHARED VARIABLE register_d : std_logic_vector (3 DOWNTO 0) := (others => '0');
SHARED VARIABLE register_hi : std_logic_vector (3 DOWNTO 0) := (others => '0');
SHARED VARIABLE register_lo : std_logic_vector (3 DOWNTO 0) := (others => '0');
PROCEDURE write_register (signal reg: in std_logic_vector(1 DOWNTO 0); signal nvalue: in std_logic_vector (3 DOWNTO 0)) IS
BEGIN
CASE reg IS
WHEN "00" => register_a := nvalue;
WHEN "01" => register_d := nvalue;
WHEN "10" => register_hi := nvalue;
WHEN "11" => register_lo := nvalue;
END CASE;
END write_register;
PROCEDURE read_register (signal reg: in std_logic_vector(1 DOWNTO 0); signal rvalue: out std_logic_vector (3 DOWNTO 0)) IS
BEGIN
CASE reg IS
WHEN "00" => rvalue <= register_a;
WHEN "01" => rvalue <= register_d;
WHEN "10" => rvalue <= register_hi;
WHEN "11" => rvalue <= register_lo;
END CASE;
END read_register;
SIGNAL temp : std_logic_vector (3 DOWNTO 0) := (others => '0');
BEGIN
a <= register_a;
d <= register_d;
hi <= register_hi;
lo <= register_lo;
PROCESS (clk)
BEGIN
IF rising_edge(clk) THEN
IF opcode(7 DOWNTO 4) = "0000" THEN -- lda
register_a := opcode(3 DOWNTO 0);
ELSIF opcode(7 DOWNTO 4) = "1011" THEN -- ldd
register_d := opcode(3 DOWNTO 0);
ELSIF opcode(7 DOWNTO 4) = "1100" THEN -- ldh
register_hi := opcode(3 DOWNTO 0);
ELSIF opcode(7 DOWNTO 4) = "1101" THEN -- ldl
register_lo := opcode(3 DOWNTO 0);
ELSIF opcode(7 DOWNTO 4) = "0010" THEN -- mov
read_register(opcode(1 DOWNTO 0), temp);
write_register(opcode(3 DOWNTO 2), temp);
ELSIF opcode(7 DOWNTO 4) = "0001" THEN -- alu
register_a := aludata;
ELSIF opcode(7 DOWNTO 4) = "0100" THEN -- push
write_register(opcode(1 DOWNTO 0), memdata);
ELSIF opcode(7 DOWNTO 4) = "0110" THEN -- lod
write_register(opcode(1 DOWNTO 0), memdata);
END IF;
END IF;
end PROCESS;
END Behaviour;
00 C0 B1 D0 10 50 D3 A0
A0 A0 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
library ieee;
use ieee.std_logic_1164.all;
ENTITY rom IS
PORT(
address: IN std_logic_vector (7 DOWNTO 0);
opcode: OUT std_logic_vector (7 DOWNTO 0) := (others => '1');
clk: IN std_logic
);
END rom;
ARCHITECTURE Behaviour OF rom IS
SIGNAL myufm_addr, myufm_dataout : std_logic_vector (7 DOWNTO 0);
SIGNAL myufm_nread, myufm_nbusy, myufm_data_valid : std_logic;
COMPONENT ufm_parallel
PORT (
ufm_addr_addr : in std_logic_vector(7 downto 0) := (others => '0'); -- ufm_addr.addr
ufm_data_valid_data_valid : out std_logic; -- ufm_data_valid.data_valid
ufm_dataout_dataout : out std_logic_vector(7 downto 0); -- ufm_dataout.dataout
ufm_nbusy_nbusy : out std_logic; -- ufm_nbusy.nbusy
ufm_nread_nread : in std_logic := '0' -- ufm_nread.nread
);
END COMPONENT;
SHARED VARIABLE nextopcode: std_logic_vector (7 DOWNTO 0) := (others => '1');
BEGIN
ufm: ufm_parallel PORT MAP(myufm_addr, myufm_data_valid, myufm_dataout, myufm_nbusy, myufm_nread);
PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
opcode <= nextopcode;
myufm_addr <= address;
myufm_nread <= '0';
END IF;
END PROCESS;
PROCESS(myufm_data_valid)
BEGIN
IF rising_edge(myufm_data_valid) THEN
nextopcode := myufm_dataout;
END IF;
END PROCESS;
END Behaviour;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment