Compare commits
No commits in common. "eddbcf5f6f194bf64d7aa8adbf3b7f84e6ea87dd" and "db5a14a2f0878bd9da39fe42fe6bc2d1cdab1fc8" have entirely different histories.
eddbcf5f6f
...
db5a14a2f0
2
fpga/.gitignore
vendored
2
fpga/.gitignore
vendored
@ -1,4 +1,2 @@
|
|||||||
build/**
|
build/**
|
||||||
*.bak
|
*.bak
|
||||||
wave.fst
|
|
||||||
vunit_out
|
|
||||||
|
@ -13,7 +13,7 @@ VU_DIR=$(BUILD_DIR)/vunit_out
|
|||||||
VU_FLAG=$(VU_DIR)/flag
|
VU_FLAG=$(VU_DIR)/flag
|
||||||
|
|
||||||
# Collect VHDL sources using VUnit
|
# Collect VHDL sources using VUnit
|
||||||
SOURCES_VHDL=$(shell VUNIT_SIMULATOR=ghdl ./run_physical.py -o $(VU_DIR) -f 2>/dev/null | sed -n 's/^\w\+, \(.\+\)$$/\1/p')
|
SOURCES_VHDL=$(shell ./run.py -o $(VU_DIR) -f 2>/dev/null | sed -n 's/^\w\+, \(.\+\)$$/\1/p')
|
||||||
|
|
||||||
# Collect Verilog sources using bash
|
# Collect Verilog sources using bash
|
||||||
SERV_DIR=hdl/serv
|
SERV_DIR=hdl/serv
|
||||||
@ -39,7 +39,7 @@ PROGRAMMER=ft2232
|
|||||||
default: $(BUILD_DIR)/bitstream.bin
|
default: $(BUILD_DIR)/bitstream.bin
|
||||||
|
|
||||||
$(VU_FLAG): $(SOURCES_VHDL) $(SOURCES_MISC)
|
$(VU_FLAG): $(SOURCES_VHDL) $(SOURCES_MISC)
|
||||||
VUNIT_SIMULATOR=ghdl ./run_physical.py --compile -o $(VU_DIR)
|
./run.py --compile -o $(VU_DIR)
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(BUILD_DIR)/netlist-post-synthesis.json: $(VU_FLAG) $(SOURCES_VERILOG)
|
$(BUILD_DIR)/netlist-post-synthesis.json: $(VU_FLAG) $(SOURCES_VERILOG)
|
||||||
@ -60,16 +60,9 @@ flash: $(BUILD_DIR)/bitstream.bin
|
|||||||
openFPGALoader --unprotect-flash -f -c $(PROGRAMMER) -b ice40_generic $<
|
openFPGALoader --unprotect-flash -f -c $(PROGRAMMER) -b ice40_generic $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
# Build artifacts
|
rm -r $(BUILD_DIR)
|
||||||
rm -rf $(BUILD_DIR)
|
|
||||||
# Simulation artifacts
|
|
||||||
rm -rf vunit_out
|
|
||||||
rm -rf wave.fst*
|
|
||||||
|
|
||||||
simulation:
|
.phony: flash clean
|
||||||
./run.py
|
|
||||||
|
|
||||||
.phony: flash clean simulation
|
|
||||||
|
|
||||||
# Useful aliases
|
# Useful aliases
|
||||||
compile_vhdl: $(VU_FLAG)
|
compile_vhdl: $(VU_FLAG)
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- VUnit test bench for the aps6404l Wishbone IF
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- Author : Markus Koch <markus@notsyncing.net>
|
|
||||||
-- Contributors : None
|
|
||||||
-- License : Mozilla Public License (MPL) Version 2
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
|
|
||||||
library ieee;
|
|
||||||
use ieee.std_logic_1164.all;
|
|
||||||
use ieee.numeric_std.all;
|
|
||||||
|
|
||||||
library design;
|
|
||||||
use design.all;
|
|
||||||
|
|
||||||
library generics;
|
|
||||||
use generics.wishbone_pkg.all;
|
|
||||||
|
|
||||||
library device_models;
|
|
||||||
use device_models.all;
|
|
||||||
|
|
||||||
library vunit_lib;
|
|
||||||
context vunit_lib.vunit_context;
|
|
||||||
|
|
||||||
entity bench_aps6404l_wb is
|
|
||||||
generic(
|
|
||||||
runner_cfg : string := runner_cfg_default
|
|
||||||
);
|
|
||||||
end entity bench_aps6404l_wb;
|
|
||||||
|
|
||||||
architecture RTL of bench_aps6404l_wb is
|
|
||||||
signal wbi_o : wishbone_slave_out;
|
|
||||||
signal wbi_i : wishbone_slave_in;
|
|
||||||
signal wb_o : wishbone_slave_out;
|
|
||||||
signal wb_i : wishbone_slave_in;
|
|
||||||
|
|
||||||
signal clk : std_logic;
|
|
||||||
signal rst : std_logic;
|
|
||||||
|
|
||||||
signal psram_ce_n : std_logic;
|
|
||||||
signal psram_sclk : std_logic;
|
|
||||||
signal psram_sio : std_logic_vector(3 downto 0);
|
|
||||||
begin
|
|
||||||
aps6404l_wb_inst : entity design.aps6404l_wb
|
|
||||||
port map(
|
|
||||||
clk => clk,
|
|
||||||
rst => rst,
|
|
||||||
wbi_o => wbi_o,
|
|
||||||
wbi_i => wbi_i,
|
|
||||||
wb_o => wb_o,
|
|
||||||
wb_i => wb_i,
|
|
||||||
psram_ce_n => psram_ce_n,
|
|
||||||
psram_sclk => psram_sclk,
|
|
||||||
psram_sio => psram_sio
|
|
||||||
);
|
|
||||||
|
|
||||||
aps6404l_inst : entity device_models.aps6404l
|
|
||||||
port map(
|
|
||||||
ce_n => psram_ce_n,
|
|
||||||
sclk => psram_sclk,
|
|
||||||
sio => psram_sio
|
|
||||||
);
|
|
||||||
|
|
||||||
test : process is
|
|
||||||
procedure bus_write(
|
|
||||||
signal master_o : out wishbone_master_out;
|
|
||||||
signal master_i : in wishbone_master_in;
|
|
||||||
constant address : in wishbone_address;
|
|
||||||
constant data : in wishbone_data
|
|
||||||
) is
|
|
||||||
begin
|
|
||||||
info("Writing to address 0x" & to_hstring(address));
|
|
||||||
master_o.we <= '1';
|
|
||||||
master_o.adr <= address;
|
|
||||||
master_o.dat <= data;
|
|
||||||
master_o.sel <= (others => '1');
|
|
||||||
master_o.cyc <= '1';
|
|
||||||
master_o.stb <= '1';
|
|
||||||
loop
|
|
||||||
wait until rising_edge(clk);
|
|
||||||
exit when master_i.ack = '1';
|
|
||||||
end loop;
|
|
||||||
master_o.cyc <= '0';
|
|
||||||
master_o.stb <= '0';
|
|
||||||
end procedure bus_write;
|
|
||||||
|
|
||||||
procedure bus_read(
|
|
||||||
signal master_o : out wishbone_master_out;
|
|
||||||
signal master_i : in wishbone_master_in;
|
|
||||||
constant address : in wishbone_address;
|
|
||||||
variable data : out wishbone_data
|
|
||||||
) is
|
|
||||||
begin
|
|
||||||
info("Reading from address 0x" & to_hstring(address));
|
|
||||||
master_o.we <= '0';
|
|
||||||
master_o.adr <= address;
|
|
||||||
master_o.sel <= (others => '1');
|
|
||||||
master_o.cyc <= '1';
|
|
||||||
master_o.stb <= '1';
|
|
||||||
loop
|
|
||||||
wait until rising_edge(clk);
|
|
||||||
exit when master_i.ack = '1';
|
|
||||||
end loop;
|
|
||||||
data := master_i.dat;
|
|
||||||
master_o.cyc <= '0';
|
|
||||||
master_o.stb <= '0';
|
|
||||||
end procedure bus_read;
|
|
||||||
|
|
||||||
procedure readcheck(signal master_o : out wishbone_master_out;
|
|
||||||
signal master_i : in wishbone_master_in;
|
|
||||||
constant address : in wishbone_address;
|
|
||||||
constant expected : in wishbone_data) is
|
|
||||||
variable data : wishbone_data;
|
|
||||||
variable time_start : time;
|
|
||||||
begin
|
|
||||||
time_start := now;
|
|
||||||
bus_read(wbi_i, wbi_o, address, data);
|
|
||||||
info("Read data: 0x" & to_hstring(data) & " after " & time'image(now - time_start));
|
|
||||||
check(data = expected, "Data readback incorrect.");
|
|
||||||
end procedure readcheck;
|
|
||||||
|
|
||||||
variable data : wishbone_data;
|
|
||||||
begin
|
|
||||||
test_runner_setup(runner, runner_cfg);
|
|
||||||
|
|
||||||
wbi_i.sel <= (others => '1');
|
|
||||||
wbi_i.cyc <= '0';
|
|
||||||
wbi_i.stb <= '0';
|
|
||||||
wb_i.cyc <= '0';
|
|
||||||
wb_i.stb <= '0';
|
|
||||||
|
|
||||||
while test_suite loop
|
|
||||||
info("Resetting DUT");
|
|
||||||
rst <= '1';
|
|
||||||
wait for 30 ns;
|
|
||||||
rst <= '0';
|
|
||||||
|
|
||||||
if run("data") then
|
|
||||||
bus_write(wb_i, wb_o, x"00000000", x"12345678");
|
|
||||||
bus_read(wb_i, wb_o, x"00000000", data);
|
|
||||||
info("Read data: 0x" & to_hstring(data));
|
|
||||||
check(data = x"12345678", "Data readback incorrect.");
|
|
||||||
wait for 500 ns;
|
|
||||||
|
|
||||||
elsif run("instruction") then
|
|
||||||
bus_write(wb_i, wb_o, x"00000000", x"11223344");
|
|
||||||
bus_write(wb_i, wb_o, x"00000004", x"55667788");
|
|
||||||
bus_write(wb_i, wb_o, x"00000008", x"99aabbcc");
|
|
||||||
bus_write(wb_i, wb_o, x"0000000c", x"ddeeff00");
|
|
||||||
wait for 1 us;
|
|
||||||
readcheck(wbi_i, wbi_o, x"00000000", x"11223344");
|
|
||||||
wait for 1 us;
|
|
||||||
readcheck(wbi_i, wbi_o, x"00000004", x"55667788");
|
|
||||||
wait for 1 us;
|
|
||||||
readcheck(wbi_i, wbi_o, x"00000008", x"99aabbcc");
|
|
||||||
wait for 1 us;
|
|
||||||
readcheck(wbi_i, wbi_o, x"0000000c", x"ddeeff00");
|
|
||||||
wait for 1 us;
|
|
||||||
|
|
||||||
end if;
|
|
||||||
end loop;
|
|
||||||
test_runner_cleanup(runner);
|
|
||||||
end process test;
|
|
||||||
|
|
||||||
test_runner_watchdog(runner, 1 ms);
|
|
||||||
|
|
||||||
clock_driver : process
|
|
||||||
constant period : time := 20 ns;
|
|
||||||
begin
|
|
||||||
clk <= '0';
|
|
||||||
wait for period / 2;
|
|
||||||
clk <= '1';
|
|
||||||
wait for period / 2;
|
|
||||||
end process clock_driver;
|
|
||||||
end architecture RTL;
|
|
@ -13,9 +13,6 @@ use ieee.std_logic_1164.all;
|
|||||||
use ieee.numeric_std.all;
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
entity aps6404l_controller is
|
entity aps6404l_controller is
|
||||||
generic(
|
|
||||||
TOGGLE_WRAP_BOUNDARY : boolean := false
|
|
||||||
);
|
|
||||||
port(
|
port(
|
||||||
clk : in std_logic; -- Max clock 132 MHz -> 66 MHz SPI
|
clk : in std_logic; -- Max clock 132 MHz -> 66 MHz SPI
|
||||||
rst : in std_logic; --
|
rst : in std_logic; --
|
||||||
@ -207,14 +204,6 @@ begin
|
|||||||
opmode <= COMMAND;
|
opmode <= COMMAND;
|
||||||
end procedure qpi_stop;
|
end procedure qpi_stop;
|
||||||
|
|
||||||
impure function POST_QPI_STATE return state_t is
|
|
||||||
begin
|
|
||||||
if TOGGLE_WRAP_BOUNDARY then
|
|
||||||
return QPI_SET_BOUNDARY;
|
|
||||||
else
|
|
||||||
return IDLE;
|
|
||||||
end if;
|
|
||||||
end function POST_QPI_STATE;
|
|
||||||
begin
|
begin
|
||||||
if rst then
|
if rst then
|
||||||
state <= QPI_EXIT;
|
state <= QPI_EXIT;
|
||||||
@ -236,7 +225,7 @@ begin
|
|||||||
state <= SPI_ENABLE_QPI when qpi_xfer(qpi_to_spi((x"9", x"9")));
|
state <= SPI_ENABLE_QPI when qpi_xfer(qpi_to_spi((x"9", x"9")));
|
||||||
|
|
||||||
when SPI_ENABLE_QPI =>
|
when SPI_ENABLE_QPI =>
|
||||||
state <= POST_QPI_STATE when qpi_xfer(qpi_to_spi((x"3", x"5")));
|
state <= QPI_SET_BOUNDARY when qpi_xfer(qpi_to_spi((x"3", x"5")));
|
||||||
|
|
||||||
when QPI_SET_BOUNDARY =>
|
when QPI_SET_BOUNDARY =>
|
||||||
state <= IDLE when qpi_xfer((x"C", x"0"));
|
state <= IDLE when qpi_xfer((x"C", x"0"));
|
||||||
|
@ -8,9 +8,6 @@
|
|||||||
-- License : Mozilla Public License (MPL) Version 2
|
-- License : Mozilla Public License (MPL) Version 2
|
||||||
-- -------------------------------------------------------------------------- --
|
-- -------------------------------------------------------------------------- --
|
||||||
|
|
||||||
-- TODO: By default, some (random) value is placed in cached_address, which may corrupt data if this happens to be the
|
|
||||||
-- first address accessesd after reset.
|
|
||||||
|
|
||||||
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;
|
||||||
@ -23,10 +20,6 @@ entity aps6404l_wb is
|
|||||||
clk : in std_logic;
|
clk : in std_logic;
|
||||||
rst : in std_logic; --
|
rst : in std_logic; --
|
||||||
|
|
||||||
-- Instruction Wishbone IF (32b read access only, caches one instruction ahead)
|
|
||||||
wbi_o : out wishbone_slave_out; -- Instruction Wishbone bus (out)
|
|
||||||
wbi_i : in wishbone_slave_in; -- Instruction Wishbone bus (in)
|
|
||||||
|
|
||||||
-- Wishbone IF
|
-- Wishbone IF
|
||||||
wb_o : out wishbone_slave_out; -- Wishbone bus (out)
|
wb_o : out wishbone_slave_out; -- Wishbone bus (out)
|
||||||
wb_i : in wishbone_slave_in; -- Wishbone bus (in)
|
wb_i : in wishbone_slave_in; -- Wishbone bus (in)
|
||||||
@ -39,165 +32,49 @@ entity aps6404l_wb is
|
|||||||
end entity aps6404l_wb;
|
end entity aps6404l_wb;
|
||||||
|
|
||||||
architecture rtl of aps6404l_wb is
|
architecture rtl of aps6404l_wb is
|
||||||
type apsc_in is record
|
signal apsc_addr : std_logic_vector(23 downto 0);
|
||||||
addr : std_logic_vector(23 downto 0);
|
signal apsc_data_in : std_logic_vector(7 downto 0);
|
||||||
data_in : std_logic_vector(7 downto 0);
|
signal apsc_data_in_next : std_logic;
|
||||||
write_en : std_logic;
|
signal apsc_data_out : std_logic_vector(7 downto 0);
|
||||||
read_en : std_logic;
|
signal apsc_data_out_valid : std_logic;
|
||||||
end record apsc_in;
|
signal apsc_write_en : std_logic;
|
||||||
|
signal apsc_read_en : std_logic;
|
||||||
|
|
||||||
type apsc_out is record
|
|
||||||
data_in_next : std_logic;
|
|
||||||
data_out : std_logic_vector(7 downto 0);
|
|
||||||
data_out_valid : std_logic;
|
|
||||||
end record apsc_out;
|
|
||||||
|
|
||||||
signal apsc_i : apsc_in;
|
|
||||||
signal apsc_o : apsc_out;
|
|
||||||
|
|
||||||
signal cached_address : std_logic_vector(apsc_i.addr'range);
|
|
||||||
signal cached_data : wishbone_data;
|
|
||||||
signal api_i : apsc_in;
|
|
||||||
signal api_o : apsc_out;
|
|
||||||
signal api_request_count : integer range 0 to 2;
|
|
||||||
signal api_bit_cnt : integer range 0 to 3;
|
|
||||||
|
|
||||||
signal apd_i : apsc_in;
|
|
||||||
signal apd_o : apsc_out;
|
|
||||||
signal bit_cnt : integer range 0 to 4;
|
signal bit_cnt : integer range 0 to 4;
|
||||||
signal data : std_logic_vector(wb_i.dat'range);
|
signal data : std_logic_vector(wb_i.dat'range);
|
||||||
|
|
||||||
signal ap_sel : integer range 0 to 1;
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
aps6404l_controller_inst : entity work.aps6404l_controller
|
aps6404l_controller_inst : entity work.aps6404l_controller
|
||||||
port map(
|
port map(
|
||||||
clk => clk,
|
clk => clk,
|
||||||
rst => rst,
|
rst => rst,
|
||||||
addr => apsc_i.addr,
|
addr => apsc_addr,
|
||||||
data_in => apsc_i.data_in,
|
data_in => apsc_data_in,
|
||||||
data_in_next => apsc_o.data_in_next,
|
data_in_next => apsc_data_in_next,
|
||||||
data_out => apsc_o.data_out,
|
data_out => apsc_data_out,
|
||||||
data_out_valid => apsc_o.data_out_valid,
|
data_out_valid => apsc_data_out_valid,
|
||||||
write_en => apsc_i.write_en,
|
write_en => apsc_write_en,
|
||||||
read_en => apsc_i.read_en,
|
read_en => apsc_read_en,
|
||||||
psram_ce_n => psram_ce_n,
|
psram_ce_n => psram_ce_n,
|
||||||
psram_sclk => psram_sclk,
|
psram_sclk => psram_sclk,
|
||||||
psram_sio => psram_sio
|
psram_sio => psram_sio
|
||||||
);
|
);
|
||||||
|
|
||||||
ap_arb : process(clk, rst) is
|
|
||||||
begin
|
|
||||||
if rst then
|
|
||||||
ap_sel <= 0;
|
|
||||||
|
|
||||||
elsif rising_edge(clk) then
|
|
||||||
if ap_sel = 0 then
|
|
||||||
if not (api_i.read_en or api_i.read_en) and (apd_i.read_en or apd_i.write_en) then
|
|
||||||
ap_sel <= 1;
|
|
||||||
end if;
|
|
||||||
else
|
|
||||||
if (apd_i.read_en nor apd_i.write_en) then -- lock until APD releases
|
|
||||||
ap_sel <= 0;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end process ap_arb;
|
|
||||||
|
|
||||||
ap_mux : process(all) is
|
|
||||||
constant APSC_IN_DEFAULT : apsc_in := (
|
|
||||||
addr => (others => '-'),
|
|
||||||
data_in => (others => '-'),
|
|
||||||
write_en => '0',
|
|
||||||
read_en => '0'
|
|
||||||
);
|
|
||||||
constant APSC_OUT_DEFAULT : apsc_out := (
|
|
||||||
data_in_next => '0',
|
|
||||||
data_out => (others => '-'),
|
|
||||||
data_out_valid => '0'
|
|
||||||
);
|
|
||||||
begin
|
|
||||||
apsc_i <= APSC_IN_DEFAULT;
|
|
||||||
api_o <= APSC_OUT_DEFAULT;
|
|
||||||
apd_o <= APSC_OUT_DEFAULT;
|
|
||||||
|
|
||||||
if ap_sel = 0 then
|
|
||||||
api_o <= apsc_o;
|
|
||||||
apsc_i <= api_i;
|
|
||||||
else
|
|
||||||
apd_o <= apsc_o;
|
|
||||||
apsc_i <= apd_i;
|
|
||||||
end if;
|
|
||||||
end process ap_mux;
|
|
||||||
|
|
||||||
instruction_memory_p : process(clk, rst) is
|
|
||||||
begin
|
|
||||||
if rst then
|
|
||||||
wbi_o.ack <= '0';
|
|
||||||
cached_address <= (others => '1'); -- TODO: Set cached_address to 0xFFFFFF
|
|
||||||
api_request_count <= 0;
|
|
||||||
|
|
||||||
elsif rising_edge(clk) then
|
|
||||||
wbi_o.ack <= '0';
|
|
||||||
|
|
||||||
if wbi_i.cyc and wbi_i.stb then
|
|
||||||
if wbi_i.adr(cached_address'range) = cached_address then -- cache hit, return current immediately, retrieve next in meantime
|
|
||||||
wbi_o.dat <= cached_data;
|
|
||||||
wbi_o.ack <= '1';
|
|
||||||
|
|
||||||
api_i.addr <= std_logic_vector(unsigned(wbi_i.adr(apsc_i.addr'range)) + 4);
|
|
||||||
if not api_i.read_en then -- If we haven't yet triggered the retrieve from memory, start it now
|
|
||||||
api_request_count <= 1;
|
|
||||||
end if;
|
|
||||||
else -- cache miss, retrieve current (return asap) + next
|
|
||||||
if not api_i.read_en then -- If we haven't yet triggered the retrieve from memory, start it now
|
|
||||||
api_i.addr <= wbi_i.adr(apsc_i.addr'range);
|
|
||||||
api_request_count <= 2;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
if api_o.data_out_valid then
|
|
||||||
cached_data <= api_o.data_out & cached_data(cached_data'high downto 8); -- TODO: this assumes the CPU quickly processes the ACK (within one SPI byte)
|
|
||||||
|
|
||||||
if api_bit_cnt = 3 then
|
|
||||||
cached_address <= api_i.addr;
|
|
||||||
if api_request_count > 0 then
|
|
||||||
api_request_count <= api_request_count - 1;
|
|
||||||
end if;
|
|
||||||
api_bit_cnt <= 0;
|
|
||||||
else
|
|
||||||
api_bit_cnt <= api_bit_cnt + 1;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
if not api_i.read_en then
|
|
||||||
api_bit_cnt <= 0;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end process instruction_memory_p;
|
|
||||||
api_i.read_en <= '1' when api_request_count > 0 else '0';
|
|
||||||
api_i.write_en <= '0';
|
|
||||||
wbi_o.err <= '0';
|
|
||||||
wbi_o.rty <= '0';
|
|
||||||
wbi_o.stall <= not wbi_o.ack;
|
|
||||||
|
|
||||||
main : process(clk, rst) is
|
main : process(clk, rst) is
|
||||||
variable start_addr : integer range 0 to 3;
|
variable start_addr : integer range 0 to 3;
|
||||||
variable stop_addr : integer range 0 to 3;
|
variable stop_addr : integer range 0 to 3;
|
||||||
variable success : std_logic;
|
variable success : std_logic;
|
||||||
variable we : std_logic;
|
|
||||||
begin
|
begin
|
||||||
if rst then
|
if rst then
|
||||||
wb_o.ack <= '0';
|
wb_o.ack <= '0';
|
||||||
bit_cnt <= 0;
|
bit_cnt <= 0;
|
||||||
apd_i.read_en <= '0';
|
|
||||||
apd_i.write_en <= '0';
|
|
||||||
|
|
||||||
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
||||||
wb_o.ack <= '0';
|
wb_o.ack <= '0';
|
||||||
|
|
||||||
if bit_cnt = 0 then
|
if bit_cnt = 0 then
|
||||||
apd_i.read_en <= '0';
|
apsc_read_en <= '0';
|
||||||
apd_i.write_en <= '0';
|
apsc_write_en <= '0';
|
||||||
|
|
||||||
start_addr := 0;
|
start_addr := 0;
|
||||||
for i in 0 to 3 loop
|
for i in 0 to 3 loop
|
||||||
@ -214,39 +91,35 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
end loop;
|
end loop;
|
||||||
|
|
||||||
apd_i.addr <= wb_i.adr(apsc_i.addr'length - 1 downto 2) & std_logic_vector(to_unsigned(start_addr, 2));
|
apsc_addr <= wb_i.adr(apsc_addr'length - 1 downto 2) & std_logic_vector(to_unsigned(start_addr, 2));
|
||||||
data <= wb_i.dat;
|
data <= wb_i.dat;
|
||||||
|
|
||||||
we := wb_i.we;
|
|
||||||
if not wb_o.ack and wb_i.stb and wb_i.cyc then
|
if not wb_o.ack and wb_i.stb and wb_i.cyc then
|
||||||
bit_cnt <= 4;
|
bit_cnt <= 4;
|
||||||
if wb_i.we then
|
|
||||||
wb_o.ack <= '1'; -- We can ack a write immediately
|
|
||||||
end if;
|
|
||||||
end if;
|
end if;
|
||||||
else
|
else
|
||||||
success := '0';
|
success := '0';
|
||||||
|
|
||||||
if bit_cnt >= (4 - stop_addr) and bit_cnt <= (4 - start_addr) then
|
if bit_cnt >= (4 - stop_addr) and bit_cnt <= (4 - start_addr) then
|
||||||
apd_i.read_en <= not we;
|
apsc_read_en <= not wb_i.we;
|
||||||
apd_i.write_en <= we;
|
apsc_write_en <= wb_i.we;
|
||||||
else
|
else
|
||||||
apd_i.read_en <= '0';
|
apsc_read_en <= '0';
|
||||||
apd_i.write_en <= '0';
|
apsc_write_en <= '0';
|
||||||
success := '1';
|
success := '1';
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
if we and apd_o.data_in_next then
|
if wb_i.we and apsc_data_in_next then
|
||||||
success := '1';
|
success := '1';
|
||||||
elsif not we and apd_o.data_out_valid then
|
elsif not wb_i.we and apsc_data_out_valid then
|
||||||
success := '1';
|
success := '1';
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
if success then
|
if success then
|
||||||
bit_cnt <= bit_cnt - 1;
|
bit_cnt <= bit_cnt - 1;
|
||||||
wb_o.dat <= apd_o.data_out & wb_o.dat(wb_o.dat'high downto 8);
|
wb_o.dat <= apsc_data_out & wb_o.dat(wb_o.dat'high downto 8);
|
||||||
data <= x"--" & data(data'high downto 8);
|
data <= x"--" & data(data'high downto 8);
|
||||||
if (bit_cnt = 1) and (we = '0') then -- We only need to ack reads, writes were already acked in bit_cnt = 0
|
if bit_cnt = 1 then
|
||||||
wb_o.ack <= '1';
|
wb_o.ack <= '1';
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
@ -254,7 +127,7 @@ begin
|
|||||||
|
|
||||||
end if;
|
end if;
|
||||||
end process main;
|
end process main;
|
||||||
apd_i.data_in <= data(apsc_i.data_in'range);
|
apsc_data_in <= data(apsc_data_in'range);
|
||||||
|
|
||||||
wb_o.err <= '0';
|
wb_o.err <= '0';
|
||||||
wb_o.rty <= '0';
|
wb_o.rty <= '0';
|
||||||
|
@ -75,62 +75,42 @@ architecture rtl of top is
|
|||||||
-- System Timer
|
-- System Timer
|
||||||
signal irq_timer : std_logic;
|
signal irq_timer : std_logic;
|
||||||
|
|
||||||
-- # Instruction Bus
|
|
||||||
-- Wishbone interconnect (master)
|
-- Wishbone interconnect (master)
|
||||||
signal wbi_masters_o : wishbone_slave_in_vector(0 downto 0);
|
signal wb_masters_o : wishbone_slave_in_vector(1 downto 0);
|
||||||
signal wbi_masters_i : wishbone_slave_out_vector(wbi_masters_o'range);
|
signal wb_masters_i : wishbone_slave_out_vector(wb_masters_o'range);
|
||||||
alias wbi_o is wbi_masters_o(0);
|
alias wbi_o is wb_masters_o(0);
|
||||||
alias wbi_i is wbi_masters_i(0);
|
alias wbi_i is wb_masters_i(0);
|
||||||
|
alias wbd_o is wb_masters_o(1);
|
||||||
|
alias wbd_i is wb_masters_i(1);
|
||||||
|
|
||||||
-- Wishbone interconnect (slave)
|
-- Wishbone interconnect (slave)
|
||||||
signal wbi_slaves_o : wishbone_master_in_vector(1 downto 0);
|
signal wb_slaves_o : wishbone_master_in_vector(4 downto 0);
|
||||||
signal wbi_slaves_i : wishbone_master_out_vector(wbi_slaves_o'range);
|
signal wb_slaves_i : wishbone_master_out_vector(wb_slaves_o'range);
|
||||||
alias wbi_rom_o is wbi_slaves_o(0);
|
alias wb_rom_o is wb_slaves_o(0);
|
||||||
alias wbi_rom_i is wbi_slaves_i(0);
|
alias wb_rom_i is wb_slaves_i(0);
|
||||||
alias wbi_ram_o is wbi_slaves_o(1);
|
alias wb_ram_o is wb_slaves_o(1);
|
||||||
alias wbi_ram_i is wbi_slaves_i(1);
|
alias wb_ram_i is wb_slaves_i(1);
|
||||||
|
alias wb_timer_o is wb_slaves_o(2);
|
||||||
|
alias wb_timer_i is wb_slaves_i(2);
|
||||||
|
alias wb_uart_o is wb_slaves_o(3);
|
||||||
|
alias wb_uart_i is wb_slaves_i(3);
|
||||||
|
alias wb_eth_o is wb_slaves_o(4);
|
||||||
|
alias wb_eth_i is wb_slaves_i(4);
|
||||||
|
|
||||||
-- Slave address map
|
-- Slave address map
|
||||||
constant wishbone_instruction_addresses : wishbone_address_vector := (
|
constant wishbone_addresses : wishbone_address_vector := (
|
||||||
0 => x"00000000", -- Boot ROM
|
0 => x"00000000", -- Boot ROM
|
||||||
1 => x"40000000" -- RAM
|
1 => x"40000000", -- RAM
|
||||||
|
2 => x"80000000", -- Timer
|
||||||
|
3 => x"81000000", -- UART
|
||||||
|
4 => x"82000000" -- Eth
|
||||||
);
|
);
|
||||||
constant wishbone_instruction_masks : wishbone_address_vector := (
|
constant wishbone_masks : wishbone_address_vector := (
|
||||||
0 => x"C0000000", -- Boot ROM
|
0 => x"FF000000", -- Boot ROM: 256b
|
||||||
1 => x"C0000000" -- RAM
|
1 => x"FF000000", -- RAM: Max 16M
|
||||||
);
|
2 => x"FF000000", -- Timer
|
||||||
|
3 => x"FF000000", -- UART
|
||||||
-- # Data Bus
|
4 => x"FF000000" -- Eth
|
||||||
-- Wishbone interconnect (master)
|
|
||||||
signal wbd_masters_o : wishbone_slave_in_vector(0 downto 0);
|
|
||||||
signal wbd_masters_i : wishbone_slave_out_vector(wbd_masters_o'range);
|
|
||||||
alias wbd_o is wbd_masters_o(0);
|
|
||||||
alias wbd_i is wbd_masters_i(0);
|
|
||||||
|
|
||||||
-- Wishbone interconnect (slave)
|
|
||||||
signal wbd_slaves_o : wishbone_master_in_vector(3 downto 0);
|
|
||||||
signal wbd_slaves_i : wishbone_master_out_vector(wbd_slaves_o'range);
|
|
||||||
alias wb_ram_o is wbd_slaves_o(0);
|
|
||||||
alias wb_ram_i is wbd_slaves_i(0);
|
|
||||||
alias wb_timer_o is wbd_slaves_o(1);
|
|
||||||
alias wb_timer_i is wbd_slaves_i(1);
|
|
||||||
alias wb_uart_o is wbd_slaves_o(2);
|
|
||||||
alias wb_uart_i is wbd_slaves_i(2);
|
|
||||||
alias wb_eth_o is wbd_slaves_o(3);
|
|
||||||
alias wb_eth_i is wbd_slaves_i(3);
|
|
||||||
|
|
||||||
-- Slave address map
|
|
||||||
constant wishbone_data_addresses : wishbone_address_vector := (
|
|
||||||
0 => x"40000000", -- RAM
|
|
||||||
1 => x"80000000", -- Timer
|
|
||||||
2 => x"81000000", -- UART
|
|
||||||
3 => x"82000000" -- Eth
|
|
||||||
);
|
|
||||||
constant wishbone_data_masks : wishbone_address_vector := (
|
|
||||||
0 => x"FF000000", -- RAM: Max 16M
|
|
||||||
1 => x"FF000000", -- Timer
|
|
||||||
2 => x"FF000000", -- UART
|
|
||||||
3 => x"FF000000" -- Eth
|
|
||||||
);
|
);
|
||||||
|
|
||||||
constant IN_SIMULATION : boolean := false --
|
constant IN_SIMULATION : boolean := false --
|
||||||
@ -219,16 +199,14 @@ begin
|
|||||||
port map(
|
port map(
|
||||||
clk => clk,
|
clk => clk,
|
||||||
clr => clr,
|
clr => clr,
|
||||||
wb_o => wbi_rom_o,
|
wb_o => wb_rom_o,
|
||||||
wb_i => wbi_rom_i
|
wb_i => wb_rom_i
|
||||||
);
|
);
|
||||||
|
|
||||||
aps6404l_wb_inst : entity work.aps6404l_wb
|
aps6404l_wb_inst : entity work.aps6404l_wb
|
||||||
port map(
|
port map(
|
||||||
clk => clk,
|
clk => clk,
|
||||||
rst => rst,
|
rst => rst,
|
||||||
wbi_o => wbi_ram_o,
|
|
||||||
wbi_i => wbi_ram_i,
|
|
||||||
wb_o => wb_ram_o,
|
wb_o => wb_ram_o,
|
||||||
wb_i => wb_ram_i,
|
wb_i => wb_ram_i,
|
||||||
psram_ce_n => psram_ce_n,
|
psram_ce_n => psram_ce_n,
|
||||||
@ -279,28 +257,16 @@ begin
|
|||||||
eth_tx_p <= (others => eth_tx_p_i);
|
eth_tx_p <= (others => eth_tx_p_i);
|
||||||
eth_tx_n <= (others => eth_tx_n_i);
|
eth_tx_n <= (others => eth_tx_n_i);
|
||||||
|
|
||||||
wishbone_crossbar_data_inst : entity generics.wishbone_arbiter
|
wishbone_crossbar_inst : entity generics.wishbone_arbiter
|
||||||
port map(
|
port map(
|
||||||
clk => clk,
|
clk => clk,
|
||||||
rst => rst,
|
rst => rst,
|
||||||
masters_o => wbd_masters_o,
|
masters_o => wb_masters_o,
|
||||||
masters_i => wbd_masters_i,
|
masters_i => wb_masters_i,
|
||||||
slaves_o => wbd_slaves_o,
|
slaves_o => wb_slaves_o,
|
||||||
slaves_i => wbd_slaves_i,
|
slaves_i => wb_slaves_i,
|
||||||
address => wishbone_data_addresses,
|
address => wishbone_addresses,
|
||||||
mask => wishbone_data_masks
|
mask => wishbone_masks
|
||||||
);
|
|
||||||
|
|
||||||
wishbone_crossbar_instruction_inst : entity generics.wishbone_arbiter
|
|
||||||
port map(
|
|
||||||
clk => clk,
|
|
||||||
rst => rst,
|
|
||||||
masters_o => wbi_masters_o,
|
|
||||||
masters_i => wbi_masters_i,
|
|
||||||
slaves_o => wbi_slaves_o,
|
|
||||||
slaves_i => wbi_slaves_i,
|
|
||||||
address => wishbone_instruction_addresses,
|
|
||||||
mask => wishbone_instruction_masks
|
|
||||||
);
|
);
|
||||||
|
|
||||||
eth_led_green_n <= not eth_led_green;
|
eth_led_green_n <= not eth_led_green;
|
||||||
|
@ -220,42 +220,35 @@ begin
|
|||||||
x"000" & "0" & (not tx_fifo_empty) & (not rx_fifo_empty) & phy_out.carrier_detect);
|
x"000" & "0" & (not tx_fifo_empty) & (not rx_fifo_empty) & phy_out.carrier_detect);
|
||||||
|
|
||||||
ledstretch : process(clk) is
|
ledstretch : process(clk) is
|
||||||
constant CMAX : integer := integer(0.1 / (1.0 / real(F_CLK)));
|
constant CMAX : integer := integer(0.2 / (1.0 / real(F_CLK)));
|
||||||
constant CMIN : integer := -integer(0.1 / (1.0 / real(F_CLK)));
|
variable cnt : integer range 0 to CMAX;
|
||||||
variable cnt : integer range CMIN to CMAX;
|
|
||||||
begin
|
begin
|
||||||
if rising_edge(clk) then
|
if rising_edge(clk) then
|
||||||
if cnt = CMIN then
|
if cnt = 0 then
|
||||||
led_rx <= phy_out.carrier_detect;
|
led_rx <= phy_out.carrier_detect;
|
||||||
if phy_out.rx_active then
|
if phy_out.rx_active then
|
||||||
cnt := CMAX;
|
cnt := CMAX;
|
||||||
led_rx <= not phy_out.carrier_detect;
|
|
||||||
end if;
|
end if;
|
||||||
elsif cnt = 0 then
|
|
||||||
led_rx <= phy_out.carrier_detect;
|
|
||||||
cnt := cnt - 1;
|
|
||||||
else
|
else
|
||||||
cnt := cnt - 1;
|
led_rx <= '0';
|
||||||
|
cnt := cnt - 1;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
end process ledstretch;
|
end process ledstretch;
|
||||||
|
|
||||||
ledstretch2 : process(clk) is
|
ledstretch2 : process(clk) is
|
||||||
constant CMAX : integer := integer(0.1 / (1.0 / real(F_CLK)));
|
constant CMAX : integer := integer(0.2 / (1.0 / real(F_CLK)));
|
||||||
constant CMIN : integer := -integer(0.1 / (1.0 / real(F_CLK)));
|
variable cnt : integer range 0 to CMAX;
|
||||||
variable cnt : integer range CMIN to CMAX;
|
|
||||||
begin
|
begin
|
||||||
if rising_edge(clk) then
|
if rising_edge(clk) then
|
||||||
if cnt = CMIN then
|
if cnt = 0 then
|
||||||
if phy_out.tx_active then
|
|
||||||
cnt := CMAX;
|
|
||||||
led_tx <= '1';
|
|
||||||
end if;
|
|
||||||
elsif cnt = 0 then
|
|
||||||
led_tx <= '0';
|
led_tx <= '0';
|
||||||
cnt := cnt - 1;
|
if phy_out.tx_active then
|
||||||
|
cnt := CMAX;
|
||||||
|
end if;
|
||||||
else
|
else
|
||||||
cnt := cnt - 1;
|
led_tx <= '1';
|
||||||
|
cnt := cnt - 1;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
end process ledstretch2;
|
end process ledstretch2;
|
||||||
|
@ -23,7 +23,7 @@ project_dir=pathlib.Path(__file__).parent.resolve()
|
|||||||
libs = {}
|
libs = {}
|
||||||
|
|
||||||
vu = VUnit.from_argv(compile_builtins=False)
|
vu = VUnit.from_argv(compile_builtins=False)
|
||||||
vu.add_vhdl_builtins()
|
#vu.add_vhdl_builtins()
|
||||||
|
|
||||||
for base_path in libraries:
|
for base_path in libraries:
|
||||||
for library_name in libraries[base_path]:
|
for library_name in libraries[base_path]:
|
||||||
@ -47,12 +47,11 @@ for base_path in libraries:
|
|||||||
libs[library_name].add_source_files(path)
|
libs[library_name].add_source_files(path)
|
||||||
|
|
||||||
# If we don't already use our own OSVVM implementation, add the default one.
|
# If we don't already use our own OSVVM implementation, add the default one.
|
||||||
if not "osvvm" in libs:
|
#if not "osvvm" in libs:
|
||||||
vu.add_osvvm()
|
# vu.add_osvvm()
|
||||||
|
|
||||||
vu.add_compile_option("ghdl.a_flags", ["-frelaxed", "-fsynopsys"])
|
vu.add_compile_option("ghdl.a_flags", ["-frelaxed", "-fsynopsys"])
|
||||||
vu.add_compile_option("nvc.a_flags", ["--relaxed"])
|
vu.add_compile_option("nvc.a_flags", ["--relaxed"])
|
||||||
#vu.set_sim_option("nvc.elab_flags", ["-O3"])
|
#vu.set_sim_option("nvc.elab_flags", ["-O3"])
|
||||||
vu.set_sim_option("nvc.sim_flags", ["--format=fst", "--wave=wave.fst"])
|
|
||||||
|
|
||||||
vu.main()
|
vu.main()
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
from vunit import VUnit
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import subprocess
|
|
||||||
import pathlib
|
|
||||||
|
|
||||||
libraries = {
|
|
||||||
# Design files
|
|
||||||
os.path.realpath(os.path.join(__file__, "..")) : {
|
|
||||||
"design",
|
|
||||||
"device_models",
|
|
||||||
"generics",
|
|
||||||
"serv",
|
|
||||||
"trashernet"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
project_dir=pathlib.Path(__file__).parent.resolve()
|
|
||||||
|
|
||||||
libs = {}
|
|
||||||
|
|
||||||
vu = VUnit.from_argv(compile_builtins=False)
|
|
||||||
#vu.add_vhdl_builtins()
|
|
||||||
|
|
||||||
for base_path in libraries:
|
|
||||||
for library_name in libraries[base_path]:
|
|
||||||
libs[library_name] = vu.add_library(library_name)
|
|
||||||
|
|
||||||
if type(libraries[base_path]) is dict: # Manually specified files
|
|
||||||
print("direct")
|
|
||||||
for filename in libraries[base_path][library_name]:
|
|
||||||
libs[library_name].add_source_files(os.path.join(base_path, filename))
|
|
||||||
else: # Auto-detect files
|
|
||||||
print(f"Importing: {library_name}")
|
|
||||||
if library_name == "trashernet": # Special case: Trashernet submodule
|
|
||||||
path = os.path.join(base_path, "hdl", library_name, library_name, "*.vhd")
|
|
||||||
libs[library_name].add_source_files(path)
|
|
||||||
elif library_name == "serv": # Special case: SERV submodule
|
|
||||||
print("Skipping SERV. It's Verilog.")
|
|
||||||
else: # Normal lib
|
|
||||||
path = os.path.join(base_path, "hdl", library_name)
|
|
||||||
if os.path.exists(path):
|
|
||||||
path=os.path.join(path, "*.vhd")
|
|
||||||
libs[library_name].add_source_files(path)
|
|
||||||
|
|
||||||
# If we don't already use our own OSVVM implementation, add the default one.
|
|
||||||
#if not "osvvm" in libs:
|
|
||||||
# vu.add_osvvm()
|
|
||||||
|
|
||||||
vu.add_compile_option("ghdl.a_flags", ["-frelaxed", "-fsynopsys"])
|
|
||||||
vu.add_compile_option("nvc.a_flags", ["--relaxed"])
|
|
||||||
#vu.set_sim_option("nvc.elab_flags", ["-O3"])
|
|
||||||
|
|
||||||
vu.main()
|
|
Loading…
Reference in New Issue
Block a user