LIBRARY ieee;
|
LIBRARY ieee;
|
USE ieee.std_logic_1164.ALL;
|
USE ieee.std_logic_1164.ALL;
|
USE ieee.numeric_std.ALL;
|
USE ieee.numeric_std.ALL;
|
use work.tinycpu.all;
|
use work.tinycpu.all;
|
|
|
ENTITY core_tb IS
|
ENTITY core_tb IS
|
END core_tb;
|
END core_tb;
|
|
|
ARCHITECTURE behavior OF core_tb IS
|
ARCHITECTURE behavior OF core_tb IS
|
|
|
-- Component Declaration for the Unit Under Test (UUT)
|
-- Component Declaration for the Unit Under Test (UUT)
|
|
|
component core is
|
component core is
|
port(
|
port(
|
--memory interface
|
--memory interface
|
MemAddr: out std_logic_vector(15 downto 0); --memory address (in bytes)
|
MemAddr: out std_logic_vector(15 downto 0); --memory address (in bytes)
|
MemWW: out std_logic; --memory writeword
|
MemWW: out std_logic; --memory writeword
|
MemWE: out std_logic; --memory writeenable
|
MemWE: out std_logic; --memory writeenable
|
MemIn: in std_logic_vector(15 downto 0);
|
MemIn: in std_logic_vector(15 downto 0);
|
MemOut: out std_logic_vector(15 downto 0);
|
MemOut: out std_logic_vector(15 downto 0);
|
--general interface
|
--general interface
|
Clock: in std_logic;
|
Clock: in std_logic;
|
Reset: in std_logic; --When this is high, CPU will reset within 1 clock cycles.
|
Reset: in std_logic; --When this is high, CPU will reset within 1 clock cycles.
|
--Enable: in std_logic; --When this is high, the CPU executes as normal, when low the CPU stops at the next clock cycle(maintaining all state)
|
--Enable: in std_logic; --When this is high, the CPU executes as normal, when low the CPU stops at the next clock cycle(maintaining all state)
|
Hold: in std_logic; --when high, CPU pauses execution and places Memory interfaces into high impendance state so the memory can be used by other components
|
Hold: in std_logic; --when high, CPU pauses execution and places Memory interfaces into high impendance state so the memory can be used by other components
|
HoldAck: out std_logic; --when high, CPU acknowledged hold and buses are in high Z
|
HoldAck: out std_logic; --when high, CPU acknowledged hold and buses are in high Z
|
--todo: port interface
|
--todo: port interface
|
|
|
--debug ports:
|
--debug ports:
|
DebugIR: out std_logic_vector(15 downto 0); --current instruction
|
DebugIR: out std_logic_vector(15 downto 0); --current instruction
|
DebugIP: out std_logic_vector(7 downto 0); --current IP
|
DebugIP: out std_logic_vector(7 downto 0); --current IP
|
DebugCS: out std_logic_vector(7 downto 0); --current code segment
|
DebugCS: out std_logic_vector(7 downto 0); --current code segment
|
DebugTR: out std_logic; --current value of TR
|
DebugTR: out std_logic; --current value of TR
|
DebugR0: out std_logic_vector(7 downto 0)
|
DebugR0: out std_logic_vector(7 downto 0)
|
);
|
);
|
end component;
|
end component;
|
|
|
|
|
--memory interface
|
--memory interface
|
signal MemAddr: std_logic_vector(15 downto 0); --memory address (in bytes)
|
signal MemAddr: std_logic_vector(15 downto 0); --memory address (in bytes)
|
signal MemWW: std_logic; --memory writeword
|
signal MemWW: std_logic; --memory writeword
|
signal MemWE: std_logic; --memory writeenable
|
signal MemWE: std_logic; --memory writeenable
|
signal MemOut: std_logic_vector(15 downto 0);
|
signal MemOut: std_logic_vector(15 downto 0);
|
signal MemIn: std_logic_vector(15 downto 0):=x"0000";
|
signal MemIn: std_logic_vector(15 downto 0):=x"0000";
|
--general interface
|
--general interface
|
signal Reset: std_logic:='0'; --When this is high, CPU will reset within 1 clock cycles.
|
signal Reset: std_logic:='0'; --When this is high, CPU will reset within 1 clock cycles.
|
--Enable: in std_logic; --When this is high, the CPU executes as normal, when low the CPU stops at the next clock cycle(maintaining all state)
|
--Enable: in std_logic; --When this is high, the CPU executes as normal, when low the CPU stops at the next clock cycle(maintaining all state)
|
signal Hold: std_logic:='0'; --when high, CPU pauses execution and places Memory interfaces into high impendance state so the memory can be used by other components
|
signal Hold: std_logic:='0'; --when high, CPU pauses execution and places Memory interfaces into high impendance state so the memory can be used by other components
|
signal HoldAck: std_logic; --when high, CPU acknowledged hold and buses are in high Z
|
signal HoldAck: std_logic; --when high, CPU acknowledged hold and buses are in high Z
|
--todo: port interface
|
--todo: port interface
|
|
|
--debug ports:
|
--debug ports:
|
signal DebugIR: std_logic_vector(15 downto 0); --current instruction
|
signal DebugIR: std_logic_vector(15 downto 0); --current instruction
|
signal DebugIP: std_logic_vector(7 downto 0); --current IP
|
signal DebugIP: std_logic_vector(7 downto 0); --current IP
|
signal DebugCS: std_logic_vector(7 downto 0); --current code segment
|
signal DebugCS: std_logic_vector(7 downto 0); --current code segment
|
signal DebugTR: std_logic; --current value of TR
|
signal DebugTR: std_logic; --current value of TR
|
signal DebugR0: std_logic_vector(7 downto 0);
|
signal DebugR0: std_logic_vector(7 downto 0);
|
|
|
signal Clock: std_logic;
|
signal Clock: std_logic;
|
constant clock_period : time := 10 ns;
|
constant clock_period : time := 10 ns;
|
|
|
BEGIN
|
BEGIN
|
|
|
-- Instantiate the Unit Under Test (UUT)
|
-- Instantiate the Unit Under Test (UUT)
|
uut: core PORT MAP (
|
uut: core PORT MAP (
|
MemAddr => MemAddr,
|
MemAddr => MemAddr,
|
MemWW => MemWW,
|
MemWW => MemWW,
|
MemWE => MemWE,
|
MemWE => MemWE,
|
MemOut => MemOut,
|
MemOut => MemOut,
|
MemIn => MemIn,
|
MemIn => MemIn,
|
--general interface
|
--general interface
|
Clock => Clock,
|
Clock => Clock,
|
Reset => Reset,
|
Reset => Reset,
|
--Enable: in std_logic; --When this is high, the CPU executes as normal, when low the CPU stops at the next clock cycle(maintaining all state)
|
--Enable: in std_logic; --When this is high, the CPU executes as normal, when low the CPU stops at the next clock cycle(maintaining all state)
|
Hold => Hold,
|
Hold => Hold,
|
HoldAck => HoldAck,
|
HoldAck => HoldAck,
|
DebugIR => DebugIR,
|
DebugIR => DebugIR,
|
DebugIP => DebugIP,
|
DebugIP => DebugIP,
|
DebugCS => DebugCS,
|
DebugCS => DebugCS,
|
DebugTR => DebugTR,
|
DebugTR => DebugTR,
|
DebugR0 => DebugR0
|
DebugR0 => DebugR0
|
);
|
);
|
|
|
|
|
-- Clock process definitions
|
-- Clock process definitions
|
clock_process :process
|
clock_process :process
|
begin
|
begin
|
Clock <= '0';
|
Clock <= '0';
|
wait for clock_period/2;
|
wait for clock_period/2;
|
Clock <= '1';
|
Clock <= '1';
|
wait for clock_period/2;
|
wait for clock_period/2;
|
end process;
|
end process;
|
|
|
|
|
-- Stimulus process
|
-- Stimulus process
|
stim_proc: process
|
stim_proc: process
|
variable err_cnt: integer :=0;
|
variable err_cnt: integer :=0;
|
begin
|
begin
|
Reset <= '1';
|
Reset <= '1';
|
wait for 20 ns;
|
wait for 20 ns;
|
|
|
--state tests:
|
--state tests:
|
Hold <= '1';
|
Hold <= '1';
|
wait for 10 ns;
|
wait for 10 ns;
|
assert(HoldAck = '1') report "hold state is not acknowledged" severity error;
|
assert(HoldAck = '1') report "hold state is not acknowledged" severity error;
|
--assert(MemAddr = "ZZZZZZZZZZZZZZZZ" and MemWW="Z" and MemWE="Z" and MemOut = "ZZZZZZZZZZZZZZZZZZZZ")
|
--assert(MemAddr = "ZZZZZZZZZZZZZZZZ" and MemWW="Z" and MemWE="Z" and MemOut = "ZZZZZZZZZZZZZZZZZZZZ")
|
-- report "hold state does not set high-Z" severity error;
|
-- report "hold state does not set high-Z" severity error;
|
Hold <= '0';
|
Hold <= '0';
|
wait for 10 ns;
|
wait for 10 ns;
|
assert(HoldAck = '0') report "hold state lasts longer than it should" severity error;
|
assert(HoldAck = '0') report "hold state lasts longer than it should" severity error;
|
|
|
Reset <= '0';
|
Reset <= '0';
|
MemIn <= x"0012"; --mov r0, 0xFF
|
MemIn <= x"0012"; --mov r0, 0xFF
|
wait for 20 ns; --fetcher needs two clock cycles to catch up
|
wait for 20 ns; --fetcher needs two clock cycles to catch up
|
assert(MemAddr = x"0100") report "Not fetching from correct start address" severity error;
|
assert(MemAddr = x"0100") report "Not fetching from correct start address" severity error;
|
MemIn <= x"00F1"; --mov r0, 0xF1
|
MemIn <= x"00F1"; --mov r0, 0xF1
|
wait for 10 ns;
|
wait for 10 ns;
|
assert(MemAddr = x"0102") report "fetcher is not incrementing address" severity error;
|
assert(MemAddr = x"0102") report "fetcher is not incrementing address" severity error;
|
assert(DebugIR = x"00F1" and DebugR0 /= x"12") report "IR is not correct. Execution occurs during first fetch";
|
assert(DebugIR = x"00F1" and DebugR0 /= x"12") report "IR is not correct. Execution occurs during first fetch";
|
MemIn <= x"0056";
|
MemIn <= x"0056";
|
wait for 10 ns;
|
wait for 10 ns;
|
assert(DebugR0 = x"56") report "loaded value of R0 is not correct" severity error;
|
assert(DebugR0 = x"56") report "loaded value of R0 is not correct" severity error;
|
MemIn <= x"0E50"; --mov IP, 0x50
|
MemIn <= x"0E50"; --mov IP, 0x50
|
wait for 10 ns;
|
wait for 10 ns;
|
assert( MemAddr = x"0150") report "mov to IP doesn't work" severity error; --DebugIP uses regOut, so it won't be updated until next clock cycle actually, but it's correct.
|
assert( MemAddr = x"0150") report "mov to IP doesn't work" severity error; --DebugIP uses regOut, so it won't be updated until next clock cycle actually, but it's correct.
|
MemIn <= x"0020"; --mov r0, 0x20
|
MemIn <= x"0020"; --mov r0, 0x20
|
wait for 10 ns;
|
wait for 10 ns;
|
assert (MemAddr = x"0152" and DebugIP=x"52") report "fetching is wrong after move to IP" severity error; --DebugIP uses regOut, Fetchaddress uses regIn, so this is correct
|
assert (MemAddr = x"0152" and DebugIP=x"52") report "fetching is wrong after move to IP" severity error; --DebugIP uses regOut, Fetchaddress uses regIn, so this is correct
|
MemIn <= x"0160"; --mov r0,0x60 if TR is set
|
MemIn <= x"0160"; --mov r0,0x60 if TR is set
|
wait for 10 ns; --wait until register write happens
|
wait for 10 ns; --wait until register write happens
|
assert(DebugR0 = x"20") report "mov to r0 is wrong after move to IP" severity error;
|
assert(DebugR0 = x"20") report "mov to r0 is wrong after move to IP" severity error;
|
MemIn <= x"1050"; --mov [r0], 0x50 (r0 is 0x20)
|
MemIn <= x"1050"; --mov [r0], 0x50 (r0 is 0x20)
|
wait for 10 ns;
|
wait for 10 ns;
|
MemIn <= x"0025"; --mov r0,0x25
|
MemIn <= x"0025"; --mov r0,0x25
|
assert(DebugR0 = x"20" and DebugTR='0') report "moved to r0 conditional thought TR is 0" severity error;
|
assert(DebugR0 = x"20" and DebugTR='0') report "moved to r0 conditional thought TR is 0" severity error;
|
assert(MemAddr = x"0020" and MemWE='1' and MemWW='0' and MemOut=x"0050") report "Write to memory doesn't work" severity error;
|
assert(MemAddr = x"0020" and MemWE='1' and MemWW='0' and MemOut=x"0050") report "Write to memory doesn't work" severity error;
|
wait for 20 ns; --wait an extra cycle because of WaitForMemory state
|
wait for 20 ns; --wait an extra cycle because of WaitForMemory state
|
MemIn <= x"0235"; --mov r1,0x35
|
MemIn <= x"0235"; --mov r1,0x35
|
wait for 10 ns;
|
wait for 10 ns;
|
MemIn <= "0011000000010000"; --compare greater than r0, r1 : TR=r0 > r1
|
MemIn <= "0011000000010000"; --compare greater than r0, r1 : TR=r0 > r1
|
wait for 10 ns;
|
wait for 10 ns;
|
assert(DebugTR ='0') report "ALU compare is not correct for greater than" severity error;
|
assert(DebugTR ='0') report "ALU compare is not correct for greater than" severity error;
|
MemIn <= "0011000000010010"; --TR=r0 < r1
|
MemIn <= "0011000000010010"; --TR=r0 < r1
|
wait for 10 ns;
|
wait for 10 ns;
|
MemIn <= x"0F20"; --jmp to 0x20 if TR=1
|
MemIn <= x"0F20"; --jmp to 0x20 if TR=1
|
assert(DebugTR='1') report "ALU compare is not correct for less than" severity error;
|
assert(DebugTR='1') report "ALU compare is not correct for less than" severity error;
|
wait for 10 ns;
|
wait for 10 ns;
|
assert(DebugIP=x"20") report "conditional TR is not correct after ALU compare" severity error;
|
assert(DebugIP=x"20") report "conditional TR is not correct after ALU compare" severity error;
|
|
|
--now test bitwise
|
--now test bitwise
|
MemIn <= x"0E50"; --mov IP, 0x50 -- do this just so we can count IP easily
|
MemIn <= x"0E50"; --mov IP, 0x50 -- do this just so we can count IP easily
|
wait for 10 ns;
|
wait for 10 ns;
|
MemIn <= x"00F0"; --mov r0, 0xFO
|
MemIn <= x"00F0"; --mov r0, 0xFO
|
wait for 10 ns;
|
wait for 10 ns;
|
MemIn <= x"0218"; --mov r1, 0x18
|
MemIn <= x"0218"; --mov r1, 0x18
|
wait for 10 ns;
|
wait for 10 ns;
|
MemIn <= "0100000000010001"; --or r0, r1 (r0 = r0 or r1)
|
MemIn <= "0100000000010001"; --or r0, r1 (r0 = r0 or r1)
|
wait for 10 ns;
|
wait for 10 ns;
|
wait for 10 ns; --wait for settling
|
wait for 10 ns; --wait for settling
|
assert(DebugR0 = x"F8") report "ALU OR is not correct" severity error;
|
assert(DebugR0 = x"F8") report "ALU OR is not correct" severity error;
|
assert( MemAddr=x"0156") report "Fetching is wrong after WaitForAlu" severity error;
|
assert( MemAddr=x"0156") report "Fetching is wrong after WaitForAlu" severity error;
|
MemIn <= x"0070"; --mov r0, 0x70 -- for debugging
|
MemIn <= x"0070"; --mov r0, 0x70 -- for debugging
|
wait for 10 ns;
|
wait for 10 ns;
|
assert( MemAddr=x"0158") report "IP increment is wrong after WaitForAlu" severity error;
|
assert( MemAddr=x"0158") report "IP increment is wrong after WaitForAlu" severity error;
|
|
MemIn <= "0101000000000000"; --push r0
|
|
wait for 10 ns;
|
|
assert(MemAddr=x"0200" and MemOut=x"0070") report "push is not correct" severity error;
|
|
wait for 10 ns;
|
|
|
|
MemIn <= "0101000000010000"; --pop r0
|
|
assert(MemAddr=x"015A") report "IP increment is wrong after push" severity error;
|
|
wait for 10 ns;
|
|
MemIn <= x"0020"; --the value to be popped into r0
|
|
assert(MemAddr=x"0200") report "Pop is not fetching from correct address" severity error;
|
|
wait for 10 ns;
|
|
assert(DebugR0=x"20") report "Pop is not assigning to R0 correct" severity error;
|
|
MemIn <= x"0040";
|
|
wait for 10 ns;
|
|
|
-- summary of testbench
|
-- summary of testbench
|
assert false
|
assert false
|
report "Testbench of core completed successfully!"
|
report "Testbench of core completed successfully!"
|
severity note;
|
severity note;
|
|
|
wait;
|
wait;
|
|
|
-- insert stimulus here
|
-- insert stimulus here
|
|
|
wait;
|
wait;
|
end process;
|
end process;
|
|
|
|
|
END;
|
END;
|
|
|