package commonConstants is
constant wordSize: integer := 16;
constant adrLength: integer := 16;
end package commonConstants;
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use work.commonConstants.all;
entity ram is port (
reset, en, r_w: in STD_LOGIC;
aBus: in STD_LOGIC_VECTOR(adrLength-1 downto 0);
dBus: inout STD_LOGIC_VECTOR(wordSize-1 downto 0));
end ram;
architecture ramArch of ram is
constant resAdrLength: integer := 6; -- address length restricted within architecture
constant memSize: integer := 2**resAdrLength;
type ram_typ is array(0 to memSize-1) of STD_LOGIC_VECTOR(wordSize-1 downto 0);
signal ram: ram_typ;
begin
process(reset, en, r_w, aBus, dBus) begin
if reset = '1' then
-- basic instruction check
ram(0) <= x"1a0f"; -- immediate load
ram(1) <= x"2010"; -- direct load
ram(2) <= x"3030"; -- indirect load
ram(3) <= x"4034"; -- direct store
ram(4) <= x"0001"; -- negate
ram(5) <= x"2034"; -- direct load
ram(6) <= x"0001"; -- negate
ram(7) <= x"5032"; -- indirect store
ram(8) <= x"0001"; -- negate
ram(9) <= x"1fff"; -- immediate load
ram(10) <= x"a008"; -- add
ram(11) <= x"700d"; -- brZero
ram(12) <= x"0000"; -- halt
ram(13) <= x"1400"; -- immediate load
ram(14) <= x"8010"; -- brPos
ram(15) <= x"0000"; -- halt
ram(16) <= x"0001"; -- negate
ram(17) <= x"9013"; -- brNeg
ram(18) <= x"0000"; -- halt
ram(19) <= x"6015"; -- branch
ram(20) <= x"0000"; -- halt
ram(21) <= x"8014"; -- brPos
ram(22) <= x"7014"; -- brZero
ram(23) <= x"0001"; -- negate
ram(24) <= x"9014"; -- brNeg
ram(25) <= x"0000"; -- halt
ram(48) <= x"0031"; -- pointer for iload
ram(49) <= x"5af0"; -- target of iload
ram(50) <= x"0033"; -- pointer for istore
ram(51) <= x"0000"; -- target of istore
ram(52) <= x"f5af"; -- target of dstore
elsif en = '1' and r_w = '0' then
ram(conv_integer(unsigned(aBus(resAdrLength-1 downto 0)))) <= dBus;
end if;
end process;
dBus <= ram(conv_integer(unsigned(aBus(resAdrLength-1 downto 0))))
when reset = '0' and en = '1' and r_w = '1' else
(dbus'range => 'Z');
end ramArch;
---------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
use work.commonConstants.all;
entity cpu is port (
clk, reset : in std_logic;
m_en, m_rw : out std_logic;
aBus : out std_logic_vector(adrLength-1 downto 0);
dBus : inout std_logic_vector(wordSize-1 downto 0);
-- these signals "exported" so they can be monitored in post-P&R simulation
pcX, iarX : out std_logic_vector(adrLength-1 downto 0);
iregX, accX, aluX : out std_logic_vector(wordSize-1 downto 0));
end cpu;
architecture cpuArch of cpu is
type state_type is (
reset_state, fetch, halt, negate, mload, dload, iload,
dstore, istore, branch, brZero, brPos, brNeg, add
);
signal state: state_type;
type tick_type is (t0, t1, t2, t3, t4, t5, t6, t7);
signal tick: tick_type;
signal pc: std_logic_vector(adrLength-1 downto 0); -- program counter
signal iReg: std_logic_vector(wordSize-1 downto 0); -- instruction register
signal iar: std_logic_vector(adrLength-1 downto 0); -- indirect address register
signal acc: std_logic_vector(wordSize-1 downto 0); -- accumulator
signal alu: std_logic_vector(wordSize-1 downto 0); -- alu output
begin
alu <= (not acc) + x"0001" when state = negate else
acc + dbus when state = add else
(alu'range => '0');
pcX <= pc; iregX <= ireg; iarX <= iar; accX <= acc; aluX <= alu;
process(clk) -- perform actions that occur on rising clock edges
function nextTick(tick: tick_type) return tick_type is begin
-- return next logical value for tick
case tick is
when t0 => return t1; when t1 => return t2; when t2 => return t3;
when t3 => return t4; when t4 => return t5; when t5 => return t6;
when t6 => return t7; when others => return t0;
end case;
end function nextTick;
procedure decode is begin
-- Instruction decoding.
case iReg(15 downto 12) is
when x"0" =>
if iReg(11 downto 0) = x"000" then
state <= halt;
elsif iReg(11 downto 0) = x"001" then
state <= negate;
end if;
when x"1" => state <= mload;
when x"2" => state <= dload;
when x"3" => state <= iload;
when x"4" => state <= dstore;
when x"5" => state <= istore;
when x"6" => state <= branch;
when x"7" => state <= brZero;
when x"8" => state <= brPos;
when x"9" => state <= brNeg;
when x"a" => state <= add;
when others => state <= halt;
end case;
end procedure decode;
procedure wrapup is begin
-- Do this at end of every instruction
state <= fetch; tick <= t0;
end procedure wrapup;
begin
if clk'event and clk = '1' then
if reset = '1' then
state <= reset_state; tick <= t0;
pc <= (pc'range => '0'); iReg <= (iReg'range => '0');
acc <= (acc'range => '0'); iar <= (iar'range => '0');
else
tick <= nextTick(tick) ; -- advance time by default
case state is
when reset_state => state <= fetch; tick <= t0;
when fetch => if tick = t1 then iReg <= dBus; end if;
if tick = t2 then
decode; pc <= pc + '1'; tick <= t0;
end if;
when halt => tick <= t0; -- do nothing
when negate => acc <= alu; wrapup;
-- load instructions
when mload =>
if iReg(11) = '0' then -- sign extension
acc <= x"0" & ireg(11 downto 0);
else
acc <= x"f" & ireg(11 downto 0);
end if;
wrapup;
when dload =>
if tick = t1 then acc <= dBus; end if;
if tick = t2 then wrapup; end if;
when iload =>
if tick = t1 then iar <= dBus; end if;
if tick = t4 then acc <= dBus; end if;
if tick = t5 then wrapup; end if;
-- store instructions
when dstore =>
if tick = t4 then wrapup; end if;
when istore =>
if tick = t1 then iar <= dBus; end if;
if tick = t7 then wrapup; end if;
-- branch instructions
when branch =>
pc <= x"0" & iReg(11 downto 0);
wrapup;
when brZero =>
if acc = x"0000" then pc <= x"0" & iReg(11 downto 0); end if;
wrapup;
when brPos =>
if acc(15) = '0' and acc /= x"0000" then
pc <= x"0" & iReg(11 downto 0);
end if;
wrapup;
when brNeg =>
if acc(15) = '1' then pc <= x"0" & iReg(11 downto 0); end if;
wrapup;
-- arithmetic instructions
when add =>
if tick = t1 then acc <= alu; end if;
if tick = t2 then wrapup; end if;
when others => state <= halt;
end case;
end if;
end if;
end process;
process(clk) begin -- perform actions that occur on falling clock edges
if clk'event and clk ='0' then
if reset = '1' then
m_en <= '0'; m_rw <= '1';
aBus <= (aBus'range => '0'); dBus <= (dBus'range => 'Z');
else
case state is
when fetch =>
if tick = t0 then m_en <= '1'; aBus <= pc; end if;
if tick = t2 then m_en <= '0'; aBus <= (aBus'range => '0'); end if;
when dload =>
if tick = t0 then m_en <= '1'; aBus <= x"0" & iReg(11 downto 0); end if;
if tick = t2 then m_en <= '0'; aBus <= (aBus'range => '0'); end if;
when iload =>
if tick = t0 then m_en <= '1'; aBus <= x"0" & iReg(11 downto 0); end if;
if tick = t2 then m_en <= '0'; aBus <= (aBus'range => '0'); end if;
if tick = t3 then m_en <= '1'; aBus <= iar; end if;
if tick = t5 then m_en <= '0'; aBus <= (abus'range => '0'); end if;
when dstore =>
if tick = t0 then m_en <= '1'; aBus <= x"0" & iReg(11 downto 0); end if;
if tick = t1 then m_rw <= '0'; dBus <= acc; end if;
if tick = t3 then m_rw <= '1'; end if;
if tick = t4 then
m_en <= '0'; aBus <= (abus'range => '0'); dBus <= (dBus'range => 'Z');
end if;
when istore =>
if tick = t0 then m_en <= '1'; aBus <= x"0" & iReg(11 downto 0); end if;
if tick = t2 then m_en <= '0'; aBus <= (aBus'range => '0'); end if;
if tick = t3 then m_en <= '1'; aBus <= iar; end if;
if tick = t4 then m_rw <= '0'; dBus <= acc; end if;
if tick = t6 then m_rw <= '1'; end if;
if tick = t7 then
m_en <= '0'; aBus <= (abus'range => '0'); dBus <= (dBus'range => 'Z');
end if;
when add =>
if tick = t0 then m_en <= '1'; aBus <= x"0" & iReg(11 downto 0); end if;
if tick = t2 then m_en <= '0'; aBus <= (aBus'range => '0'); end if;
when others => -- do nothing
end case;
end if;
end if;
end process;
end cpuArch;
-------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use work.commonConstants.all;
entity top is port(
clk, reset: in STD_LOGIC;
mem_enX, mem_rwX : out std_logic;
aBusX : out std_logic_vector(adrLength-1 downto 0);
dBusX : out std_logic_vector(wordSize-1 downto 0);
pcX, iarX : out std_logic_vector(adrLength-1 downto 0);
iregX, accX, aluX : out std_logic_vector(wordSize-1 downto 0));
end top;
architecture topArch of top is
component ram port (
reset, en, r_w: in STD_LOGIC;
aBus: in STD_LOGIC_VECTOR(adrLength-1 downto 0);
dBus: inout STD_LOGIC_VECTOR(wordSize-1 downto 0));
end component;
component cpu port (
clk, reset: in STD_LOGIC;
m_en, m_rw: out STD_LOGIC;
aBus: out STD_LOGIC_VECTOR(adrLength-1 downto 0);
dBus: inout STD_LOGIC_VECTOR(wordSize-1 downto 0);
pcX, iarX : out std_logic_vector(wordSize-1 downto 0);
iregX, accX, aluX : out std_logic_vector(wordSize-1 downto 0));
end component;
signal mem_en, mem_rw: STD_LOGIC;
signal aBus, dBus: STD_LOGIC_VECTOR(15 downto 0);
signal pc, ireg, iar, acc, alu: std_logic_vector(15 downto 0);
begin
ramC: ram port map(reset, mem_en, mem_rw, aBus, dBus);
cpuC: cpu port map(clk, reset, mem_en, mem_rw, aBus, dBus,
pc, iar, ireg, acc, alu);
mem_enX <= mem_en; mem_rwX <= mem_rw;
aBusX <= aBus; dBusX <= dBus;
pcX <= pc; iregX <= ireg; iarX <= iar; accX <= acc; aluX <= alu;
end topArch;