From 9e61fd9456bb392db189045fb7368109e351b95b Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Sat, 6 Mar 2021 16:36:57 -0800 Subject: [PATCH] Add multi master sys bus --- sysbus/makefile | 18 +++ sysbus/sysbus.vhdl | 197 ++++++++++++++++++++++++++++++++ sysbus/sysbus_test.vhdl | 241 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 456 insertions(+) create mode 100644 sysbus/makefile create mode 100644 sysbus/sysbus.vhdl create mode 100644 sysbus/sysbus_test.vhdl diff --git a/sysbus/makefile b/sysbus/makefile new file mode 100644 index 0000000..b87aea6 --- /dev/null +++ b/sysbus/makefile @@ -0,0 +1,18 @@ +all: sim +sim: test.ghw + +sim_sources = sysbus_test.vhdl +sources = sysbus.vhdl +test_entity = sysbus_test + + +test.ghw: work-obj93.cf + ghdl -r $(test_entity) --wave=$@ + + +work-obj93.cf: $(sim_sources) $(sources) + ghdl -a $^ + +PHONY: sim + +.PRECIOUS: test.ghw diff --git a/sysbus/sysbus.vhdl b/sysbus/sysbus.vhdl new file mode 100644 index 0000000..dfa2a64 --- /dev/null +++ b/sysbus/sysbus.vhdl @@ -0,0 +1,197 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity sysbus is + port( + clk: in std_logic; + rst: in std_logic; + + -- master port 0 + m0_addr: in std_logic_vector(15 downto 0); + m0_wdata: in std_logic_vector(15 downto 0); + m0_rdata: out std_logic_vector(15 downto 0); + m0_re: in std_logic; + m0_we: in std_logic; + m0_busy: out std_logic; + + -- master port 1 + m1_addr: in std_logic_vector(15 downto 0); + m1_wdata: in std_logic_vector(15 downto 0); + m1_rdata: out std_logic_vector(15 downto 0); + m1_re: in std_logic; + m1_we: in std_logic; + m1_busy: out std_logic; + + -- actual bus + bus_addr: out std_logic_vector(15 downto 0); + bus_wdata: out std_logic_vector(15 downto 0); + bus_rdata: in std_logic_vector(15 downto 0); + bus_re: out std_logic; + bus_we: out std_logic + ); +end entity sysbus; + +architecture behavior of sysbus is + type bus_state is (IDLE, READING, PENDING); + + signal owner_next, owner: std_logic_vector(0 to 1); + signal state_next, state: bus_state; + + signal pend_addr, pend_addr_next: std_logic_vector(15 downto 0); + signal pend_wdata, pend_wdata_next: std_logic_vector(15 downto 0); + signal pend, pend_next: std_logic_vector(0 to 1); + + signal were: std_logic_vector(0 to 3); +begin + + were <= m0_we & m1_we & m0_re & m1_re; + + process(were, m0_addr, m0_wdata, m1_addr, m1_wdata, bus_rdata, state, owner, pend, pend_addr, pend_wdata) + begin + if pend = "00" then + m0_busy <= '0'; + m1_busy <= '0'; + else + m0_busy <= '1'; + m1_busy <= '1'; + end if; + + pend_next <= pend; + owner_next <= "00"; + + bus_we <= '0'; + bus_re <= '0'; + + -- some defaults + bus_addr <= x"0000"; + bus_wdata <= x"0000"; + + m0_rdata <= x"0000"; + m1_rdata <= x"0000"; + + case state is + when READING => + if owner = "10" then + m0_rdata <= bus_rdata; + m1_busy <= '1'; + else + m1_rdata <= bus_rdata; + m0_busy <= '1'; + end if; + if pend = "00" then + state_next <= IDLE; + else + state_next <= PENDING; + end if; + + when PENDING => + bus_addr <= pend_addr; + bus_we <= '1'; + bus_wdata <= pend_wdata; + pend_next <= "00"; + state_next <= IDLE; + + when IDLE => + case were is + when "0000" => + -- chill + when "1000" => + bus_addr <= m0_addr; + bus_wdata <= m0_wdata; + bus_we <= '1'; + bus_re <= '0'; + when "0100" => + bus_addr <= m1_addr; + bus_wdata <= m1_wdata; + bus_we <= '1'; + bus_re <= '0'; + when "1100" => + bus_addr <= m0_addr; + bus_wdata <= m0_wdata; + bus_we <= '1'; + bus_re <= '0'; + + pend_next <= "01"; + pend_addr_next <= m1_addr; + pend_wdata_next <= m1_wdata; + state_next <= PENDING; + + when "0010" => + state_next <= READING; + owner_next <= "10"; + + bus_addr <= m0_addr; + bus_we <= '0'; + bus_re <= '1'; + + when "0001" => + state_next <= READING; + owner_next <= "01"; + + bus_addr <= m1_addr; + bus_we <= '0'; + bus_re <= '1'; + + when "0011" => + state_next <= READING; + owner_next <= "10"; + + bus_addr <= m0_addr; + bus_we <= '0'; + bus_re <= '1'; + + m1_busy <= '1'; + + when "1001" => + state_next <= READING; + owner_next <= "01"; + + bus_addr <= m1_addr; + bus_we <= '0'; + bus_re <= '1'; + + pend_next <= "10"; + pend_addr_next <= m0_addr; + pend_wdata_next <= m0_wdata; + + m0_busy <= '1'; + + when "0110" => + state_next <= READING; + owner_next <= "10"; + + bus_addr <= m0_addr; + bus_we <= '0'; + bus_re <= '1'; + + pend_next <= "01"; + pend_addr_next <= m1_addr; + pend_wdata_next <= m1_wdata; + + m1_busy <= '1'; + + when others => + -- blarg + end case; + end case; + end process; + + process(clk, rst) + begin + if rst = '1' then + state <= IDLE; + owner <= "00"; + pend <= "00"; + pend_addr <= x"0000"; + pend_wdata <= x"0000"; + elsif rising_edge(clk) then + state <= state_next; + owner <= owner_next; + pend <= pend_next; + pend_addr <= pend_addr_next; + pend_wdata <= pend_wdata_next; + end if; + end process; + +end behavior; diff --git a/sysbus/sysbus_test.vhdl b/sysbus/sysbus_test.vhdl new file mode 100644 index 0000000..31e7b8c --- /dev/null +++ b/sysbus/sysbus_test.vhdl @@ -0,0 +1,241 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use std.textio.all; + +entity sysbus_test is +end sysbus_test; + +architecture rtl of sysbus_test is + + component sysbus is + port( + clk: in std_logic; + rst: in std_logic; + + -- master port 0 + m0_addr: in std_logic_vector(15 downto 0); + m0_wdata: in std_logic_vector(15 downto 0); + m0_rdata: out std_logic_vector(15 downto 0); + m0_re: in std_logic; + m0_we: in std_logic; + m0_busy: out std_logic; + + -- master port 1 + m1_addr: in std_logic_vector(15 downto 0); + m1_wdata: in std_logic_vector(15 downto 0); + m1_rdata: out std_logic_vector(15 downto 0); + m1_re: in std_logic; + m1_we: in std_logic; + m1_busy: out std_logic; + + -- actual bus + bus_addr: out std_logic_vector(15 downto 0); + bus_wdata: out std_logic_vector(15 downto 0); + bus_rdata: in std_logic_vector(15 downto 0); + bus_re: out std_logic; + bus_we: out std_logic + ); + end component; + + signal finished: std_logic := '0'; + signal clk, rst: std_logic := '0'; + + signal m0_addr, m0_wdata, m0_rdata: std_logic_vector(15 downto 0); + signal m0_re, m0_we, m0_busy: std_logic; + signal m1_addr, m1_wdata, m1_rdata: std_logic_vector(15 downto 0); + signal m1_re, m1_we, m1_busy: std_logic; + signal bus_addr, bus_wdata, bus_rdata: std_logic_vector(15 downto 0); + signal bus_re, bus_we : std_logic; + + signal bus_rdata_next: std_logic_vector(15 downto 0); + +begin + dut: sysbus port map(clk => clk, rst => rst, + m0_addr => m0_addr, m0_wdata => m0_wdata, m0_rdata => m0_rdata, + m0_re => m0_re, m0_we => m0_we, m0_busy => m0_busy, + m1_addr => m1_addr, m1_wdata => m1_wdata, m1_rdata => m1_rdata, + m1_re => m1_re, m1_we => m1_we, m1_busy => m1_busy, + bus_addr => bus_addr, bus_wdata => bus_wdata, bus_rdata => bus_rdata, + bus_re => bus_re, bus_we => bus_we + ); + + -- clock + process + begin + if finished = '0' then + clk <= not clk; + wait for 5 ns; + else + clk <= '0'; + wait; + end if; + end process; + + -- memory + process(bus_re, bus_addr) + begin + bus_rdata_next <= x"0000"; + if bus_re = '1' then + case bus_addr is + when x"feed" => + bus_rdata_next <= x"babe"; + when x"dead" => + bus_rdata_next <= x"beef"; + when others => + end case; + end if; + end process; + + process(clk, rst) + begin + if rst = '1' then + bus_rdata <= x"0000"; + elsif rising_edge(clk) then + bus_rdata <= bus_rdata_next; + end if; + end process; + + process + begin + rst <= '1'; + + m0_re <= '0'; + m0_we <= '0'; + m1_re <= '0'; + m1_we <= '0'; + + wait for 1 ns; + assert(m0_busy='0') report "Fail rst" severity error; + assert(m1_busy='0') report "Fail rst" severity error; + + rst <= '0'; + + wait for 10 ns; + assert(m0_busy='0') report "Should still be idle" severity error; + assert(m1_busy='0') report "Should still be idle" severity error; + + -- m0 write + + m0_addr <= x"feed"; + m0_wdata <= x"babe"; + m0_we <= '1'; + + wait for 10 ns; + assert(bus_addr=x"feed") report "Did not do write" severity error; + assert(bus_wdata=x"babe") report "Did not do write" severity error; + + m0_we <= '0'; + + -- read + m0_re <= '1'; + wait for 10 ns; + assert(m0_rdata=x"babe") report "Did not do read" severity error; + assert(m1_busy='1') report "Did not do block m1 for m0 read" severity error; + + m0_re <= '0'; + + wait for 10 ns; + assert(m0_busy='0') report "m0 was not idle" severity error; + assert(m1_busy='0') report "m1 was not idle" severity error; + + -- m1 write + + m1_addr <= x"dead"; + m1_wdata <= x"beef"; + m1_we <= '1'; + + wait for 10 ns; + assert(bus_addr=x"dead") report "Did not do write" severity error; + assert(bus_wdata=x"beef") report "Did not do write" severity error; + + m1_we <= '0'; + + -- read + m1_re <= '1'; + wait for 10 ns; + assert(m1_rdata=x"beef") report "Did not do read m1" severity error; + assert(m0_busy='1') report "Did not do block m0 for m1 read" severity error; + + m1_re <= '0'; + + wait for 10 ns; + assert(m0_busy='0') report "m0 was not idle" severity error; + assert(m1_busy='0') report "m1 was not idle" severity error; + + + -- serious shit below + -- concurent writes + + m0_addr <= x"feed"; + m0_wdata <= x"babe"; + m0_we <= '1'; + + m1_addr <= x"dead"; + m1_wdata <= x"beef"; + m1_we <= '1'; + + wait for 9 ns; + assert(bus_addr=x"feed") report "Did not do write m0" severity error; + assert(bus_wdata=x"babe") report "Did not do write m0" severity error; + wait for 1 ns; + assert(m1_busy='1') report "Did not do delay m1" severity error; + + m0_we <= '0'; + m1_we <= '0'; + + wait for 9 ns; + assert(bus_addr=x"dead") report "Did not do write m1" severity error; + assert(bus_wdata=x"beef") report "Did not do write m1" severity error; + wait for 1 ns; + + wait for 10 ns; + assert(m0_busy='0') report "m0 was not idle" severity error; + assert(m1_busy='0') report "m1 was not idle" severity error; + + -- concurrent reads (!!) + + m0_re <= '1'; + m1_re <= '1'; + wait for 10 ns; + assert(m0_rdata=x"babe") report "Did not do read m0" severity error; + assert(m1_busy='1') report "Did not do block m1 for m0 read" severity error; + + m0_re <= '0'; + + wait for 20 ns; + assert(m1_busy='0') report "m1 was not idle" severity error; + assert(m1_rdata=x"beef") report "Did not do read m1" severity error; + assert(m0_busy='1') report "Did not do block m0 for m1 read" severity error; + + m1_re <= '0'; + + wait for 10 ns; + assert(m0_busy='0') report "m0 was not idle" severity error; + assert(m1_busy='0') report "m1 was not idle" severity error; + + -- concurrent read & write (OMG) + m1_re <= '1'; + m0_we <= '1'; + + wait for 10 ns; + assert(m1_rdata=x"beef") report "Did not do read m1" severity error; + assert(m0_busy='1') report "Did not do block m0 for m1 read" severity error; + + m1_re <= '0'; + + wait for 10 ns; + assert(bus_addr=x"feed") report "Did not do write m0" severity error; + assert(bus_wdata=x"babe") report "Did not do write m0" severity error; + + m0_we <= '0'; + + wait for 10 ns; + assert(m0_busy='0') report "m0 was not idle" severity error; + assert(m1_busy='0') report "m1 was not idle" severity error; + + assert false report "Test done." severity note; + finished <= '1'; + wait; + end process; +end rtl;