fpga: Implement basic SERV SoC
This commit is contained in:
parent
79c466ec50
commit
262a979ec3
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[submodule "fpga/hdl/serv"]
|
||||||
|
path = fpga/hdl/serv
|
||||||
|
url = https://github.com/olofk/serv.git
|
||||||
|
[submodule "fpga/hdl/trashernet"]
|
||||||
|
path = fpga/hdl/trashernet
|
||||||
|
url = https://git.notsyncing.net/fpga/trashernet.git
|
@ -12,7 +12,14 @@ You can find a copy of the full license in [LICENSE-CC-BY-SA-4.0.TXT](./LICENSE-
|
|||||||
|
|
||||||
### FPGA
|
### FPGA
|
||||||
|
|
||||||
TBD.
|
The FPGA Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||||
|
|
||||||
|
You can find a copy of the full license in [LICENSE-MPL-2.0.txt](./LICENSE-MPL-2.0.txt).
|
||||||
|
|
||||||
|
Note that this design incorporates code from third-party projects, which may come with further restrictions. For details, refer to the individual projects's licensing terms:
|
||||||
|
|
||||||
|
* [SERV](https://github.com/olofk/serv/blob/main/LICENSE): ISC License
|
||||||
|
* [Trashernet](https://git.notsyncing.net/fpga/trashernet/src/branch/master/README.MD#license): Mozilla Public License, v. 2.0.
|
||||||
|
|
||||||
### SW
|
### SW
|
||||||
|
|
||||||
|
2
fpga/.gitignore
vendored
Normal file
2
fpga/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build/**
|
||||||
|
*.bak
|
28
fpga/build.sh
Executable file
28
fpga/build.sh
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
../run.py --compile
|
||||||
|
|
||||||
|
BASEDIR=".."
|
||||||
|
DEVICE=--u4k # --up5k, --u4k
|
||||||
|
PACKAGE=sg48
|
||||||
|
|
||||||
|
# Collect pre-analyzed VHDL sources
|
||||||
|
GHDLINCDIRS=`find ./vunit_out/ghdl/libraries -maxdepth 1 -mindepth 1 -type d | sed "s/^/-P/" | tr '\n' ' '`
|
||||||
|
|
||||||
|
# Collect Verilog sources
|
||||||
|
SERV="$BASEDIR/hdl/serv"
|
||||||
|
VLOGS=`echo ../hdl/serv/rtl/*.v`
|
||||||
|
VLOGS="$VLOGS $SERV/servant/servant_ram.v $SERV/servant/servant_timer.v"
|
||||||
|
|
||||||
|
# Synthesize and PnR
|
||||||
|
# -device <hx | lp | u>
|
||||||
|
yosys -m ghdl -p "read_verilog $VLOGS; ghdl --std=08 $GHDLINCDIRS design.top; synth_ice40 -abc9 -device u -top top -json netlist.json"
|
||||||
|
nextpnr-ice40 $DEVICE --package $PACKAGE --freq 12 --asc netlist.asc --report report.json --detailed-timing-report --json netlist.json --pcf ../constraints.pcf
|
||||||
|
|
||||||
|
# Generate bitstream
|
||||||
|
icepack netlist.asc bitstream.bin
|
44
fpga/constraints.pcf
Normal file
44
fpga/constraints.pcf
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
set_io psram_ce_n 13
|
||||||
|
set_io psram_sclk 9
|
||||||
|
set_io psram_sio[0] 6
|
||||||
|
set_io psram_sio[1] 11
|
||||||
|
set_io psram_sio[2] 12
|
||||||
|
set_io psram_sio[3] 10
|
||||||
|
|
||||||
|
set_io flash_ce_n 16
|
||||||
|
set_io flash_sclk 15
|
||||||
|
set_io flash_sio[0] 14
|
||||||
|
set_io flash_sio[1] 17
|
||||||
|
set_io flash_sio[2] 18
|
||||||
|
set_io flash_sio[3] 19
|
||||||
|
|
||||||
|
set_io pmod[0] 20
|
||||||
|
set_io pmod[1] 21
|
||||||
|
set_io pmod[2] 23
|
||||||
|
set_io pmod[3] 25
|
||||||
|
set_io pmod[4] 26
|
||||||
|
set_io pmod[5] 27
|
||||||
|
set_io pmod[6] 28
|
||||||
|
set_io pmod[7] 31
|
||||||
|
|
||||||
|
set_io uart_rx 37
|
||||||
|
set_io uart_tx 36
|
||||||
|
set_io clk_12m 35
|
||||||
|
|
||||||
|
set_io eth_rx_n 38
|
||||||
|
set_io eth_rx_p 42
|
||||||
|
|
||||||
|
set_io eth_tx_n[0] 46
|
||||||
|
set_io eth_tx_n[1] 47
|
||||||
|
set_io eth_tx_n[2] 44
|
||||||
|
set_io eth_tx_n[3] 45
|
||||||
|
|
||||||
|
set_io eth_tx_p[0] 48
|
||||||
|
set_io eth_tx_p[1] 2
|
||||||
|
set_io eth_tx_p[2] 4
|
||||||
|
set_io eth_tx_p[3] 3
|
||||||
|
|
||||||
|
set_io eth_led_green 40
|
||||||
|
set_io eth_led_orange 41
|
||||||
|
|
||||||
|
set_io led_user 34
|
117
fpga/hdl/bench/bench_aps6404l_controller.vhd
Normal file
117
fpga/hdl/bench/bench_aps6404l_controller.vhd
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 device_models;
|
||||||
|
library design;
|
||||||
|
|
||||||
|
entity bench_aps6404l_controller is
|
||||||
|
end entity bench_aps6404l_controller;
|
||||||
|
|
||||||
|
architecture bench of bench_aps6404l_controller is
|
||||||
|
signal rst : std_logic;
|
||||||
|
signal clk : std_logic;
|
||||||
|
signal psram_ce_n : std_logic;
|
||||||
|
signal psram_sclk : std_logic;
|
||||||
|
signal psram_sio : std_logic_vector(3 downto 0);
|
||||||
|
signal addr : std_logic_vector(23 downto 0);
|
||||||
|
signal data_in : std_logic_vector(7 downto 0);
|
||||||
|
signal data_in_next : std_logic;
|
||||||
|
signal write_en : std_logic;
|
||||||
|
signal read_en : std_logic;
|
||||||
|
signal data_out : std_logic_vector(7 downto 0);
|
||||||
|
signal data_out_valid : std_logic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
aps6404l_controller_inst : entity design.aps6404l_controller
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst => rst,
|
||||||
|
addr => addr,
|
||||||
|
data_in => data_in,
|
||||||
|
data_in_next => data_in_next,
|
||||||
|
data_out => data_out,
|
||||||
|
data_out_valid => data_out_valid,
|
||||||
|
write_en => write_en,
|
||||||
|
read_en => read_en,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
test : process is
|
||||||
|
begin
|
||||||
|
rst <= '1';
|
||||||
|
data_in <= (others => '0');
|
||||||
|
read_en <= '0';
|
||||||
|
write_en <= '0';
|
||||||
|
|
||||||
|
wait for 1 ns;
|
||||||
|
rst <= '0';
|
||||||
|
|
||||||
|
wait for 3 us;
|
||||||
|
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
addr <= x"ABCDEF";
|
||||||
|
read_en <= '1';
|
||||||
|
|
||||||
|
wait for 2 us;
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
read_en <= '0';
|
||||||
|
|
||||||
|
wait for 1 us;
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
addr <= x"ABCDEF";
|
||||||
|
write_en <= '1';
|
||||||
|
|
||||||
|
for i in 10 to 15 loop
|
||||||
|
data_in <= std_logic_vector(to_unsigned(160 + i, 8));
|
||||||
|
loop
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
exit when data_in_next = '1';
|
||||||
|
end loop;
|
||||||
|
end loop;
|
||||||
|
write_en <= '0';
|
||||||
|
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
write_en <= '1';
|
||||||
|
|
||||||
|
for i in 10 to 15 loop
|
||||||
|
data_in <= std_logic_vector(to_unsigned(160 + i, 8));
|
||||||
|
loop
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
exit when data_in_next = '1';
|
||||||
|
end loop;
|
||||||
|
end loop;
|
||||||
|
write_en <= '0';
|
||||||
|
|
||||||
|
wait;
|
||||||
|
end process test;
|
||||||
|
|
||||||
|
end architecture bench;
|
121
fpga/hdl/bench/bench_fifo_block.vhd
Normal file
121
fpga/hdl/bench/bench_fifo_block.vhd
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 generics;
|
||||||
|
use generics.all;
|
||||||
|
|
||||||
|
entity bench_fifo_block is
|
||||||
|
end entity bench_fifo_block;
|
||||||
|
|
||||||
|
architecture RTL of bench_fifo_block is
|
||||||
|
signal clk : std_logic;
|
||||||
|
signal rst_a : std_logic;
|
||||||
|
signal clr : std_logic;
|
||||||
|
signal data_in : std_logic_vector(7 downto 0);
|
||||||
|
signal write : std_logic;
|
||||||
|
signal commit : std_logic;
|
||||||
|
signal abort : std_logic;
|
||||||
|
signal full : std_logic;
|
||||||
|
signal data_out : std_logic_vector(data_in'range);
|
||||||
|
signal data_first : std_logic;
|
||||||
|
signal empty : std_logic;
|
||||||
|
signal read : std_logic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
fifo_block_inst : entity generics.fifo_block
|
||||||
|
generic map(
|
||||||
|
SIZE => 15
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst_a => rst_a,
|
||||||
|
clr => clr,
|
||||||
|
data_in => data_in,
|
||||||
|
write => write,
|
||||||
|
commit => commit,
|
||||||
|
abort => abort,
|
||||||
|
full => full,
|
||||||
|
data_out => data_out,
|
||||||
|
data_first => data_first,
|
||||||
|
empty => empty,
|
||||||
|
read => read
|
||||||
|
);
|
||||||
|
|
||||||
|
clock_driver : process
|
||||||
|
constant period : time := 10 ns;
|
||||||
|
begin
|
||||||
|
clk <= '0';
|
||||||
|
wait for period / 2;
|
||||||
|
clk <= '1';
|
||||||
|
wait for period / 2;
|
||||||
|
end process clock_driver;
|
||||||
|
|
||||||
|
test : process is
|
||||||
|
procedure push(constant data : in std_logic_vector(7 downto 0)) is
|
||||||
|
begin
|
||||||
|
data_in <= data;
|
||||||
|
write <= '1';
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
write <= '0';
|
||||||
|
end procedure push;
|
||||||
|
|
||||||
|
procedure pop(expected : std_logic_vector(7 downto 0); first : boolean) is
|
||||||
|
begin
|
||||||
|
read <= '1';
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
report "Read data: " & to_hstring(data_out) & " - " & std_logic'image(data_first);
|
||||||
|
assert (data_first = '1') = first report "Data first was " & std_logic'image(data_first) & " instead of " & boolean'image(first);
|
||||||
|
assert data_out = expected report "Data is " & to_hstring(data_out) & ", should be " & to_hstring(expected) severity error;
|
||||||
|
read <= '0';
|
||||||
|
end procedure;
|
||||||
|
|
||||||
|
procedure commit_data is
|
||||||
|
begin
|
||||||
|
commit <= '1';
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
commit <= '0';
|
||||||
|
end procedure commit_data;
|
||||||
|
begin
|
||||||
|
rst_a <= '1';
|
||||||
|
clr <= '0';
|
||||||
|
write <= '0';
|
||||||
|
commit <= '0';
|
||||||
|
abort <= '0';
|
||||||
|
read <= '0';
|
||||||
|
|
||||||
|
wait for 10 ns;
|
||||||
|
rst_a <= '0';
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
|
||||||
|
report "Pushing 5 items into FIFO";
|
||||||
|
for i in 1 to 5 loop
|
||||||
|
push(std_logic_vector(to_unsigned(i, data_in'length)));
|
||||||
|
assert empty = '1' report "FIFO data present without commit";
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
report "Committing data";
|
||||||
|
commit_data;
|
||||||
|
wait until rising_edge(clk);
|
||||||
|
assert empty = '0' report "Commit did not validate data";
|
||||||
|
|
||||||
|
report "Reading data";
|
||||||
|
for i in 1 to 1 loop
|
||||||
|
pop(std_logic_vector(to_unsigned(i, data_in'length)), i = 1);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
std.env.stop(0);
|
||||||
|
wait;
|
||||||
|
end process test;
|
||||||
|
|
||||||
|
end architecture RTL;
|
221
fpga/hdl/bench/bench_top_manual.vhd
Normal file
221
fpga/hdl/bench/bench_top_manual.vhd
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
||||||
|
use std.textio.all;
|
||||||
|
|
||||||
|
library device_models;
|
||||||
|
|
||||||
|
entity bench_top_manual is
|
||||||
|
end entity bench_top_manual;
|
||||||
|
|
||||||
|
architecture bench of bench_top_manual is
|
||||||
|
constant UART_BAUD : real := 38400.0;
|
||||||
|
|
||||||
|
signal clk : std_logic;
|
||||||
|
signal rst_n_a : std_logic;
|
||||||
|
|
||||||
|
signal uart_txd : std_logic;
|
||||||
|
signal uart_rxd : std_logic;
|
||||||
|
|
||||||
|
signal psram_ce_n : std_logic;
|
||||||
|
signal psram_sclk : std_logic;
|
||||||
|
signal psram_sio : std_logic_vector(3 downto 0);
|
||||||
|
|
||||||
|
signal rx_p : std_logic := '0';
|
||||||
|
signal rx_n : std_logic := '1';
|
||||||
|
signal tx_p : std_logic_vector(3 downto 0);
|
||||||
|
signal tx_n : std_logic_vector(3 downto 0);
|
||||||
|
|
||||||
|
procedure print(text : string) is
|
||||||
|
variable lb : line;
|
||||||
|
begin
|
||||||
|
write(lb, text);
|
||||||
|
writeline(output, lb);
|
||||||
|
end procedure print;
|
||||||
|
|
||||||
|
procedure print(text : character) is
|
||||||
|
variable lb : line;
|
||||||
|
begin
|
||||||
|
write(lb, text);
|
||||||
|
write(output, lb.all);
|
||||||
|
flush(output);
|
||||||
|
end procedure print;
|
||||||
|
begin
|
||||||
|
clock_driver : process
|
||||||
|
constant period : time := 1 sec / 48000000;
|
||||||
|
begin
|
||||||
|
clk <= '0';
|
||||||
|
wait for period / 2;
|
||||||
|
clk <= '1';
|
||||||
|
wait for period / 2;
|
||||||
|
end process clock_driver;
|
||||||
|
|
||||||
|
reset_gen : process is
|
||||||
|
begin
|
||||||
|
rst_n_a <= '0';
|
||||||
|
wait for 40 ns;
|
||||||
|
rst_n_a <= '1';
|
||||||
|
wait;
|
||||||
|
end process reset_gen;
|
||||||
|
|
||||||
|
top_inst : entity design.top
|
||||||
|
port map(
|
||||||
|
clk_12m => clk,
|
||||||
|
uart_tx => uart_txd,
|
||||||
|
uart_rx => uart_rxd,
|
||||||
|
eth_rx_p => rx_p,
|
||||||
|
eth_rx_n => rx_n,
|
||||||
|
eth_tx_p => tx_p,
|
||||||
|
eth_tx_n => tx_n,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
uart_decoder : process is
|
||||||
|
constant DELAY : time := (1 sec / UART_BAUD);
|
||||||
|
variable d : std_logic_vector(7 downto 0);
|
||||||
|
begin
|
||||||
|
wait until falling_edge(uart_txd);
|
||||||
|
wait for 0.5 * DELAY;
|
||||||
|
for i in 0 to 7 loop
|
||||||
|
wait for DELAY;
|
||||||
|
d(i) := uart_txd;
|
||||||
|
end loop;
|
||||||
|
wait for 1.0 * DELAY;
|
||||||
|
print(character'val(to_integer(unsigned(d))));
|
||||||
|
end process uart_decoder;
|
||||||
|
|
||||||
|
loader : process is
|
||||||
|
procedure uart_tx(d : std_logic_vector(7 downto 0)) is
|
||||||
|
constant DELAY : time := (1 sec / UART_BAUD);
|
||||||
|
begin
|
||||||
|
uart_rxd <= '0';
|
||||||
|
wait for DELAY;
|
||||||
|
for i in d'low to d'high loop
|
||||||
|
uart_rxd <= d(i);
|
||||||
|
wait for DELAY;
|
||||||
|
end loop;
|
||||||
|
uart_rxd <= '1';
|
||||||
|
wait for DELAY;
|
||||||
|
end procedure uart_tx;
|
||||||
|
|
||||||
|
begin
|
||||||
|
uart_rxd <= '1';
|
||||||
|
wait for (1 sec / UART_BAUD) * 10;
|
||||||
|
|
||||||
|
report ("Writing ABCD+jalr0 to RAM...");
|
||||||
|
-- WRITE
|
||||||
|
uart_tx(x"01");
|
||||||
|
|
||||||
|
-- to RAM
|
||||||
|
uart_tx(x"40");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
|
||||||
|
-- 8 bytes
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"08");
|
||||||
|
|
||||||
|
-- with this data ("ABCD", jalr zero)
|
||||||
|
uart_tx(x"41");
|
||||||
|
uart_tx(x"42");
|
||||||
|
uart_tx(x"43");
|
||||||
|
uart_tx(x"44");
|
||||||
|
uart_tx(x"e7");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
|
||||||
|
report ("Reading back from RAM...");
|
||||||
|
-- READ
|
||||||
|
uart_tx(x"02");
|
||||||
|
|
||||||
|
-- from RAM
|
||||||
|
uart_tx(x"40");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
|
||||||
|
-- 4 bytes ("ABCD")
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"04");
|
||||||
|
|
||||||
|
print("RX Data: ");
|
||||||
|
wait for (1 sec / UART_BAUD) * 10 * 5;
|
||||||
|
print("");
|
||||||
|
|
||||||
|
report ("Jumping to RAM+4...");
|
||||||
|
-- JUMP
|
||||||
|
uart_tx(x"03");
|
||||||
|
|
||||||
|
-- to RAM (+4, jalr zero)
|
||||||
|
uart_tx(x"40");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"04");
|
||||||
|
|
||||||
|
-- The program will jump back to the loader, so we should be able to read again
|
||||||
|
wait for 100 us;
|
||||||
|
|
||||||
|
report ("Reading from RAM again...");
|
||||||
|
-- READ
|
||||||
|
uart_tx(x"02");
|
||||||
|
|
||||||
|
-- from RAM
|
||||||
|
uart_tx(x"40");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
|
||||||
|
-- 4 bytes
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"00");
|
||||||
|
uart_tx(x"04");
|
||||||
|
|
||||||
|
print("RX Data: ");
|
||||||
|
wait for (1 sec / UART_BAUD) * 10 * 5;
|
||||||
|
print("");
|
||||||
|
|
||||||
|
wait for 400 us;
|
||||||
|
|
||||||
|
report "Done.";
|
||||||
|
|
||||||
|
std.env.stop;
|
||||||
|
wait;
|
||||||
|
|
||||||
|
end process loader;
|
||||||
|
|
||||||
|
end architecture bench;
|
||||||
|
|
||||||
|
-- Commands to test on real HW
|
||||||
|
-- ---------------------------
|
||||||
|
-- Dump boot ROM : 02 00 00 00 00 00 00 00 FF
|
||||||
|
-- Write four bytes to RAM : 01 40 00 00 00 00 00 00 04 01 02 03 04
|
||||||
|
-- Dump these four bytes : 02 40 00 00 00 00 00 00 04
|
256
fpga/hdl/design/aps6404l_controller.vhd
Normal file
256
fpga/hdl/design/aps6404l_controller.vhd
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
entity aps6404l_controller is
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- Max clock 132 MHz -> 66 MHz SPI
|
||||||
|
rst : in std_logic; --
|
||||||
|
|
||||||
|
addr : in std_logic_vector(23 downto 0);
|
||||||
|
data_in : in std_logic_vector(7 downto 0);
|
||||||
|
data_in_next : out std_logic; -- Apply next data word at `data`
|
||||||
|
data_out : out std_logic_vector(7 downto 0);
|
||||||
|
data_out_valid : out std_logic;
|
||||||
|
write_en : in std_logic;
|
||||||
|
read_en : in std_logic; --
|
||||||
|
|
||||||
|
psram_ce_n : out std_logic;
|
||||||
|
psram_sclk : out std_logic; -- Max clock 66 MHz because of RW mode; Else max clock 90 MHz, else we might violate t_ACLK
|
||||||
|
psram_sio : inout std_logic_vector(3 downto 0) --
|
||||||
|
);
|
||||||
|
end entity aps6404l_controller;
|
||||||
|
|
||||||
|
architecture rtl of aps6404l_controller is
|
||||||
|
signal if_latch : std_logic;
|
||||||
|
signal if_write : std_logic;
|
||||||
|
signal if_output : std_logic; -- Actively drive sio
|
||||||
|
|
||||||
|
type opmode_t is (COMMAND, READ, WRITE);
|
||||||
|
signal opmode : opmode_t;
|
||||||
|
constant SR_SIZE : integer := 16;
|
||||||
|
type sr_element_vector is array (natural range <>) of std_logic_vector(psram_sio'range);
|
||||||
|
subtype sr_t is sr_element_vector(0 to SR_SIZE - 1);
|
||||||
|
subtype sr_cnt_t is integer range -SR_SIZE to SR_SIZE - 1;
|
||||||
|
signal sr : sr_t;
|
||||||
|
signal sr_preload : sr_t;
|
||||||
|
signal sr_preload_cnt : sr_cnt_t;
|
||||||
|
signal sr_load : std_logic;
|
||||||
|
signal sr_cnt : sr_cnt_t;
|
||||||
|
signal active : std_logic;
|
||||||
|
signal rd_second_nibble : std_logic;
|
||||||
|
constant RD_WAIT_CNT_MAX : integer := 3 - 1;
|
||||||
|
signal rd_wait_cnt : integer range 0 to RD_WAIT_CNT_MAX;
|
||||||
|
|
||||||
|
type state_t is (QPI_EXIT, SPI_RESET1, SPI_RESET2, SPI_ENABLE_QPI, QPI_SET_BOUNDARY, IDLE, READ, WRITE);
|
||||||
|
signal state : state_t;
|
||||||
|
signal requested : std_logic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
clkgen : process(clk, rst) is
|
||||||
|
begin
|
||||||
|
if rst then
|
||||||
|
psram_sclk <= '0';
|
||||||
|
if_latch <= '0';
|
||||||
|
if_write <= '0';
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
if_latch <= '0';
|
||||||
|
if_write <= '0';
|
||||||
|
|
||||||
|
if (active) then
|
||||||
|
psram_sclk <= not psram_sclk;
|
||||||
|
|
||||||
|
if psram_sclk then -- rising edge
|
||||||
|
if_latch <= '1'; -- is the latch edge for both
|
||||||
|
else -- falling edge
|
||||||
|
if_write <= '1'; -- is a write edge for both
|
||||||
|
end if;
|
||||||
|
|
||||||
|
else
|
||||||
|
psram_sclk <= '0';
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process clkgen;
|
||||||
|
|
||||||
|
sr_p : process(clk, rst) is
|
||||||
|
begin
|
||||||
|
if rst then
|
||||||
|
sr_cnt <= -1;
|
||||||
|
psram_ce_n <= '1';
|
||||||
|
if_output <= '0';
|
||||||
|
active <= '0';
|
||||||
|
rd_second_nibble <= '0';
|
||||||
|
data_out_valid <= '0';
|
||||||
|
data_in_next <= '0';
|
||||||
|
rd_wait_cnt <= RD_WAIT_CNT_MAX;
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
data_out_valid <= '0';
|
||||||
|
data_in_next <= '0';
|
||||||
|
|
||||||
|
if active then
|
||||||
|
if if_write then
|
||||||
|
sr <= sr(sr'low + 1 to sr'high) & x"-";
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if sr_cnt = 0 then
|
||||||
|
if if_latch then
|
||||||
|
rd_second_nibble <= not rd_second_nibble;
|
||||||
|
data_out <= data_out(3 downto 0) & psram_sio;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
case opmode is
|
||||||
|
when COMMAND =>
|
||||||
|
if if_write then -- Transaction end only allowed on write edge
|
||||||
|
active <= '0';
|
||||||
|
if_output <= '0';
|
||||||
|
psram_ce_n <= '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when READ =>
|
||||||
|
if_output <= '0'; -- Configure as input
|
||||||
|
if if_latch and rd_second_nibble then
|
||||||
|
if rd_wait_cnt = 0 then
|
||||||
|
data_out_valid <= '1';
|
||||||
|
else
|
||||||
|
rd_wait_cnt <= rd_wait_cnt - 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when WRITE =>
|
||||||
|
if if_write and not rd_second_nibble then
|
||||||
|
sr(sr'low to sr'low + 1) <= (data_in(7 downto 4), data_in(3 downto 0));
|
||||||
|
data_in_next <= '1';
|
||||||
|
end if;
|
||||||
|
end case;
|
||||||
|
else
|
||||||
|
if if_latch then
|
||||||
|
sr_cnt <= sr_cnt - 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
rd_wait_cnt <= RD_WAIT_CNT_MAX;
|
||||||
|
rd_second_nibble <= '0';
|
||||||
|
if_output <= '0';
|
||||||
|
if sr_load then
|
||||||
|
sr <= sr_preload;
|
||||||
|
sr_cnt <= sr_preload_cnt;
|
||||||
|
psram_ce_n <= '0';
|
||||||
|
if_output <= '1';
|
||||||
|
active <= '1';
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process sr_p;
|
||||||
|
|
||||||
|
psram_sio <= sr(sr'low) when if_output else (others => 'Z');
|
||||||
|
|
||||||
|
fsm : process(clk, rst) is
|
||||||
|
function qpi_to_spi(constant DATA : in sr_element_vector) return sr_element_vector is
|
||||||
|
variable vec : sr_element_vector(0 to DATA'length * 4 - 1);
|
||||||
|
begin
|
||||||
|
vec := (others => (others => '-'));
|
||||||
|
for i in DATA'range loop
|
||||||
|
for j in 0 to 3 loop
|
||||||
|
vec(i * 4 + j)(0) := DATA(i)(3 - j);
|
||||||
|
end loop;
|
||||||
|
end loop;
|
||||||
|
return vec;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
function addr_to_nibbles(constant ADDR : in std_logic_vector) return sr_element_vector is
|
||||||
|
variable vec : sr_element_vector(0 to ADDR'length / 4 - 1);
|
||||||
|
begin
|
||||||
|
for i in vec'range loop
|
||||||
|
vec(i) := ADDR(ADDR'length - (i * 4) - 1 downto ADDR'length - (i + 1) * 4);
|
||||||
|
end loop;
|
||||||
|
return vec;
|
||||||
|
end function addr_to_nibbles;
|
||||||
|
|
||||||
|
impure function qpi_xfer(NIBBLES : sr_element_vector; constant OPM : in opmode_t := COMMAND) return boolean is
|
||||||
|
begin
|
||||||
|
if (requested) then
|
||||||
|
if not active and not sr_load then
|
||||||
|
requested <= '0';
|
||||||
|
return true;
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
if not active then
|
||||||
|
sr_preload <= (others => x"-");
|
||||||
|
sr_preload(NIBBLES'range) <= NIBBLES;
|
||||||
|
sr_preload_cnt <= NIBBLES'length - 1;
|
||||||
|
sr_load <= '1';
|
||||||
|
opmode <= OPM;
|
||||||
|
requested <= '1';
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
return false;
|
||||||
|
end function qpi_xfer;
|
||||||
|
|
||||||
|
procedure qpi_stop is
|
||||||
|
begin
|
||||||
|
opmode <= COMMAND;
|
||||||
|
end procedure qpi_stop;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if rst then
|
||||||
|
state <= QPI_EXIT;
|
||||||
|
sr_load <= '0';
|
||||||
|
requested <= '0';
|
||||||
|
opmode <= COMMAND;
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
sr_load <= '0';
|
||||||
|
|
||||||
|
case state is
|
||||||
|
when QPI_EXIT =>
|
||||||
|
state <= SPI_RESET1 when qpi_xfer((x"F", x"5"));
|
||||||
|
|
||||||
|
when SPI_RESET1 =>
|
||||||
|
state <= SPI_RESET2 when qpi_xfer(qpi_to_spi((x"6", x"6")));
|
||||||
|
|
||||||
|
when SPI_RESET2 =>
|
||||||
|
state <= SPI_ENABLE_QPI when qpi_xfer(qpi_to_spi((x"9", x"9")));
|
||||||
|
|
||||||
|
when SPI_ENABLE_QPI =>
|
||||||
|
state <= QPI_SET_BOUNDARY when qpi_xfer(qpi_to_spi((x"3", x"5")));
|
||||||
|
|
||||||
|
when QPI_SET_BOUNDARY =>
|
||||||
|
state <= IDLE when qpi_xfer((x"C", x"0"));
|
||||||
|
|
||||||
|
when IDLE =>
|
||||||
|
if read_en then
|
||||||
|
state <= READ;
|
||||||
|
elsif write_en then
|
||||||
|
state <= WRITE;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when READ =>
|
||||||
|
state <= IDLE when qpi_xfer(sr_element_vector'(x"0", x"B") & addr_to_nibbles(addr), READ);
|
||||||
|
if not read_en then
|
||||||
|
qpi_stop;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when WRITE =>
|
||||||
|
state <= IDLE when qpi_xfer(sr_element_vector'(x"0", x"2") & addr_to_nibbles(addr), WRITE);
|
||||||
|
if not write_en then
|
||||||
|
qpi_stop;
|
||||||
|
end if;
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
end process fsm;
|
||||||
|
|
||||||
|
end architecture rtl;
|
||||||
|
|
136
fpga/hdl/design/aps6404l_wb.vhd
Normal file
136
fpga/hdl/design/aps6404l_wb.vhd
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 generics;
|
||||||
|
use generics.wishbone_pkg.all;
|
||||||
|
|
||||||
|
entity aps6404l_wb is
|
||||||
|
port(
|
||||||
|
clk : in std_logic;
|
||||||
|
rst : in std_logic; --
|
||||||
|
|
||||||
|
-- Wishbone IF
|
||||||
|
wb_o : out wishbone_slave_out; -- Wishbone bus (out)
|
||||||
|
wb_i : in wishbone_slave_in; -- Wishbone bus (in)
|
||||||
|
|
||||||
|
-- PSRAM IF
|
||||||
|
psram_ce_n : out std_logic;
|
||||||
|
psram_sclk : out std_logic;
|
||||||
|
psram_sio : inout std_logic_vector(3 downto 0) --
|
||||||
|
);
|
||||||
|
end entity aps6404l_wb;
|
||||||
|
|
||||||
|
architecture rtl of aps6404l_wb is
|
||||||
|
signal apsc_addr : std_logic_vector(23 downto 0);
|
||||||
|
signal apsc_data_in : std_logic_vector(7 downto 0);
|
||||||
|
signal apsc_data_in_next : std_logic;
|
||||||
|
signal apsc_data_out : std_logic_vector(7 downto 0);
|
||||||
|
signal apsc_data_out_valid : std_logic;
|
||||||
|
signal apsc_write_en : std_logic;
|
||||||
|
signal apsc_read_en : std_logic;
|
||||||
|
|
||||||
|
signal bit_cnt : integer range 0 to 4;
|
||||||
|
signal data : std_logic_vector(wb_i.dat'range);
|
||||||
|
|
||||||
|
begin
|
||||||
|
aps6404l_controller_inst : entity work.aps6404l_controller
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst => rst,
|
||||||
|
addr => apsc_addr,
|
||||||
|
data_in => apsc_data_in,
|
||||||
|
data_in_next => apsc_data_in_next,
|
||||||
|
data_out => apsc_data_out,
|
||||||
|
data_out_valid => apsc_data_out_valid,
|
||||||
|
write_en => apsc_write_en,
|
||||||
|
read_en => apsc_read_en,
|
||||||
|
psram_ce_n => psram_ce_n,
|
||||||
|
psram_sclk => psram_sclk,
|
||||||
|
psram_sio => psram_sio
|
||||||
|
);
|
||||||
|
|
||||||
|
main : process(clk, rst) is
|
||||||
|
variable start_addr : integer range 0 to 3;
|
||||||
|
variable stop_addr : integer range 0 to 3;
|
||||||
|
variable success : std_logic;
|
||||||
|
begin
|
||||||
|
if rst then
|
||||||
|
wb_o.ack <= '0';
|
||||||
|
bit_cnt <= 0;
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
wb_o.ack <= '0';
|
||||||
|
|
||||||
|
if bit_cnt = 0 then
|
||||||
|
apsc_read_en <= '0';
|
||||||
|
apsc_write_en <= '0';
|
||||||
|
|
||||||
|
start_addr := 0;
|
||||||
|
for i in 0 to 3 loop
|
||||||
|
if wb_i.sel(i) = '1' then
|
||||||
|
start_addr := i;
|
||||||
|
exit;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
stop_addr := 0;
|
||||||
|
for i in 3 downto 0 loop
|
||||||
|
if wb_i.sel(i) = '1' then
|
||||||
|
stop_addr := i;
|
||||||
|
exit;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
apsc_addr <= wb_i.adr(apsc_addr'length - 1 downto 2) & std_logic_vector(to_unsigned(start_addr, 2));
|
||||||
|
data <= wb_i.dat;
|
||||||
|
|
||||||
|
if not wb_o.ack and wb_i.stb and wb_i.cyc then
|
||||||
|
bit_cnt <= 4;
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
success := '0';
|
||||||
|
|
||||||
|
if bit_cnt >= (4 - stop_addr) and bit_cnt <= (4 - start_addr) then
|
||||||
|
apsc_read_en <= not wb_i.we;
|
||||||
|
apsc_write_en <= wb_i.we;
|
||||||
|
else
|
||||||
|
apsc_read_en <= '0';
|
||||||
|
apsc_write_en <= '0';
|
||||||
|
success := '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if wb_i.we and apsc_data_in_next then
|
||||||
|
success := '1';
|
||||||
|
elsif not wb_i.we and apsc_data_out_valid then
|
||||||
|
success := '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if success then
|
||||||
|
bit_cnt <= bit_cnt - 1;
|
||||||
|
wb_o.dat <= apsc_data_out & wb_o.dat(wb_o.dat'high downto 8);
|
||||||
|
data <= x"--" & data(data'high downto 8);
|
||||||
|
if bit_cnt = 1 then
|
||||||
|
wb_o.ack <= '1';
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end if;
|
||||||
|
end process main;
|
||||||
|
apsc_data_in <= data(apsc_data_in'range);
|
||||||
|
|
||||||
|
wb_o.err <= '0';
|
||||||
|
wb_o.rty <= '0';
|
||||||
|
wb_o.stall <= not wb_o.ack;
|
||||||
|
|
||||||
|
end architecture rtl;
|
25
fpga/hdl/design/pll0.vhd
Normal file
25
fpga/hdl/design/pll0.vhd
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- Author : Markus Koch <markus@notsyncing.net>
|
||||||
|
-- Contributors : None
|
||||||
|
-- License : Mozilla Public License (MPL) Version 2
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
|
||||||
|
library IEEE;
|
||||||
|
use IEEE.std_logic_1164.all;
|
||||||
|
|
||||||
|
entity pll0 is
|
||||||
|
port(
|
||||||
|
CLKI : in std_logic;
|
||||||
|
CLKOP : out std_logic;
|
||||||
|
LOCK : out std_logic);
|
||||||
|
end pll0;
|
||||||
|
|
||||||
|
architecture Structure of pll0 is
|
||||||
|
begin
|
||||||
|
CLKOP <= CLKI;
|
||||||
|
LOCK <= '1';
|
||||||
|
end Structure;
|
91
fpga/hdl/design/serv_top_vhdl.vhd
Normal file
91
fpga/hdl/design/serv_top_vhdl.vhd
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 generics;
|
||||||
|
use generics.wishbone_pkg.all;
|
||||||
|
|
||||||
|
entity serv_top_vhdl is
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- CPU and bus clock
|
||||||
|
clr : in std_logic; -- Synchronous clear (CPU reset)
|
||||||
|
wbi_o : out wishbone_master_out; -- Instruction Wishbone bus (out)
|
||||||
|
wbi_i : in wishbone_master_in; -- Instruction Wishbone bus (in)
|
||||||
|
wbd_o : out wishbone_master_out; -- Data Wishbone bus (out)
|
||||||
|
wbd_i : in wishbone_master_in; -- Data Wishbone bus (in)
|
||||||
|
irq_timer : in std_logic -- System timer interrupt
|
||||||
|
);
|
||||||
|
end entity serv_top_vhdl;
|
||||||
|
|
||||||
|
architecture rtl of serv_top_vhdl is
|
||||||
|
component serv_rf_top
|
||||||
|
port(
|
||||||
|
clk : in std_logic;
|
||||||
|
i_rst : in std_logic;
|
||||||
|
i_timer_irq : in std_logic;
|
||||||
|
o_ibus_adr : out std_logic_vector(31 downto 0);
|
||||||
|
o_ibus_cyc : out std_logic;
|
||||||
|
i_ibus_rdt : in std_logic_vector(31 downto 0);
|
||||||
|
i_ibus_ack : in std_logic;
|
||||||
|
o_dbus_adr : out std_logic_vector(31 downto 0);
|
||||||
|
o_dbus_dat : out std_logic_vector(31 downto 0);
|
||||||
|
o_dbus_sel : out std_logic_vector(3 downto 0);
|
||||||
|
o_dbus_we : out std_logic;
|
||||||
|
o_dbus_cyc : out std_logic;
|
||||||
|
i_dbus_rdt : in std_logic_vector(31 downto 0);
|
||||||
|
i_dbus_ack : in std_logic;
|
||||||
|
o_ext_rs1 : out std_logic_vector(31 downto 0);
|
||||||
|
o_ext_rs2 : out std_logic_vector(31 downto 0);
|
||||||
|
o_ext_funct3 : out std_logic_vector(2 downto 0);
|
||||||
|
i_ext_rd : in std_logic_vector(31 downto 0);
|
||||||
|
i_ext_ready : in std_logic;
|
||||||
|
o_mdu_valid : out std_logic
|
||||||
|
);
|
||||||
|
end component serv_rf_top;
|
||||||
|
|
||||||
|
signal wbd_o_dat_bv : bit_vector(31 downto 0);
|
||||||
|
begin
|
||||||
|
serv_top : serv_rf_top
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
i_rst => clr,
|
||||||
|
i_timer_irq => irq_timer,
|
||||||
|
o_ibus_adr => wbi_o.adr,
|
||||||
|
o_ibus_cyc => wbi_o.cyc,
|
||||||
|
i_ibus_rdt => wbi_i.dat,
|
||||||
|
i_ibus_ack => wbi_i.ack,
|
||||||
|
o_dbus_adr => wbd_o.adr,
|
||||||
|
o_dbus_dat => wbd_o.dat,
|
||||||
|
o_dbus_sel => wbd_o.sel,
|
||||||
|
o_dbus_we => wbd_o.we,
|
||||||
|
o_dbus_cyc => wbd_o.cyc,
|
||||||
|
i_dbus_rdt => wbd_i.dat,
|
||||||
|
i_dbus_ack => wbd_i.ack,
|
||||||
|
o_ext_rs1 => open,
|
||||||
|
o_ext_rs2 => open,
|
||||||
|
o_ext_funct3 => open,
|
||||||
|
i_ext_rd => (others => '0'),
|
||||||
|
i_ext_ready => '0',
|
||||||
|
o_mdu_valid => open
|
||||||
|
);
|
||||||
|
|
||||||
|
--wbd_o.dat <= to_std_logic_vector(wbd_o_dat_bv);
|
||||||
|
|
||||||
|
wbi_o.stb <= wbi_o.cyc;
|
||||||
|
wbi_o.sel <= (others => '1');
|
||||||
|
wbi_o.we <= '0';
|
||||||
|
wbi_o.dat <= (others => '0');
|
||||||
|
|
||||||
|
wbd_o.stb <= wbd_o.cyc;
|
||||||
|
|
||||||
|
end architecture rtl;
|
58
fpga/hdl/design/servant_gpio_vhdl.vhd
Normal file
58
fpga/hdl/design/servant_gpio_vhdl.vhd
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 generics;
|
||||||
|
use generics.wishbone_pkg.all;
|
||||||
|
|
||||||
|
entity servant_gpio_vhdl is
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- CPU and bus clock
|
||||||
|
clr : in std_logic; -- Synchronous clear (CPU reset)
|
||||||
|
|
||||||
|
wb_o : out wishbone_slave_out; -- Instruction Wishbone bus (out)
|
||||||
|
wb_i : in wishbone_slave_in; -- Instruction Wishbone bus (in)
|
||||||
|
|
||||||
|
output : out std_logic -- System Timer Interrupt
|
||||||
|
);
|
||||||
|
end entity servant_gpio_vhdl;
|
||||||
|
|
||||||
|
architecture rtl of servant_gpio_vhdl is
|
||||||
|
component servant_gpio
|
||||||
|
port(
|
||||||
|
i_wb_clk : in std_logic;
|
||||||
|
i_wb_dat : in std_logic;
|
||||||
|
i_wb_we : in std_logic;
|
||||||
|
i_wb_cyc : in std_logic;
|
||||||
|
o_wb_rdt : out std_logic;
|
||||||
|
o_gpio : out std_logic
|
||||||
|
);
|
||||||
|
end component servant_gpio;
|
||||||
|
|
||||||
|
begin
|
||||||
|
servant_gpio_inst : component servant_gpio
|
||||||
|
port map(
|
||||||
|
i_wb_clk => clk,
|
||||||
|
i_wb_dat => wb_i.dat(0),
|
||||||
|
i_wb_we => wb_i.we,
|
||||||
|
i_wb_cyc => wb_i.cyc and wb_i.stb,
|
||||||
|
o_wb_rdt => wb_o.dat(0),
|
||||||
|
o_gpio => output
|
||||||
|
);
|
||||||
|
|
||||||
|
wb_o.ack <= '1';
|
||||||
|
wb_o.rty <= '0';
|
||||||
|
wb_o.err <= '0';
|
||||||
|
wb_o.stall <= '0';
|
||||||
|
wb_o.dat(31 downto 1) <= (others => '0');
|
||||||
|
end architecture rtl;
|
90
fpga/hdl/design/servant_ram.vhd
Normal file
90
fpga/hdl/design/servant_ram.vhd
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 generics;
|
||||||
|
use generics.wishbone_pkg.all;
|
||||||
|
|
||||||
|
entity servant_ram_vhdl is
|
||||||
|
generic(
|
||||||
|
memfile : string := "data/empty.hex";
|
||||||
|
read_only : boolean := false;
|
||||||
|
adr_width : integer := 16
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- CPU and bus clock
|
||||||
|
clr : in std_logic; -- Synchronous reset
|
||||||
|
|
||||||
|
wb_o : out wishbone_slave_out; -- Wishbone bus (out)
|
||||||
|
wb_i : in wishbone_slave_in -- Wishbone bus (in)
|
||||||
|
);
|
||||||
|
end entity servant_ram_vhdl;
|
||||||
|
|
||||||
|
architecture rtl of servant_ram_vhdl is
|
||||||
|
component servant_ram
|
||||||
|
generic(
|
||||||
|
depth : integer;
|
||||||
|
aw : integer;
|
||||||
|
memfile : string
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
i_wb_clk : in std_logic;
|
||||||
|
i_wb_rst : in std_logic;
|
||||||
|
i_wb_adr : in std_logic_vector;
|
||||||
|
i_wb_dat : in std_logic_vector;
|
||||||
|
i_wb_sel : in std_logic_vector;
|
||||||
|
i_wb_we : in std_logic;
|
||||||
|
i_wb_cyc : in std_logic;
|
||||||
|
o_wb_rdt : out std_logic_vector;
|
||||||
|
o_wb_ack : out std_logic
|
||||||
|
);
|
||||||
|
end component servant_ram;
|
||||||
|
|
||||||
|
begin
|
||||||
|
servant_ram_inst : component servant_ram
|
||||||
|
generic map(
|
||||||
|
depth => 2 ** adr_width,
|
||||||
|
aw => adr_width,
|
||||||
|
memfile => memfile
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
i_wb_clk => clk,
|
||||||
|
i_wb_rst => clr,
|
||||||
|
i_wb_adr => wb_i.adr(adr_width - 1 downto 2),
|
||||||
|
i_wb_dat => wb_i.dat,
|
||||||
|
i_wb_sel => wb_i.sel,
|
||||||
|
i_wb_we => wb_i.we,
|
||||||
|
i_wb_cyc => wb_i.cyc and wb_i.stb,
|
||||||
|
o_wb_rdt => wb_o.dat,
|
||||||
|
o_wb_ack => wb_o.ack
|
||||||
|
);
|
||||||
|
|
||||||
|
wb_o.rty <= '0';
|
||||||
|
wb_o.err <= '0';
|
||||||
|
wb_o.stall <= '0';
|
||||||
|
|
||||||
|
rowarn : process(clk) is
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
if wb_i.cyc and wb_i.stb then
|
||||||
|
if (unsigned(wb_i.adr) > 2 ** adr_width - 1) then
|
||||||
|
report "ERROR: Out of bounds for " & servant_ram_vhdl'path_name & " @0x" & to_hstring(wb_i.adr) severity error;
|
||||||
|
end if;
|
||||||
|
if (wb_i.we = '1' and read_only) then
|
||||||
|
report "ERROR: Write access to ROM @0x" & to_hstring(wb_i.adr) severity warning;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process rowarn;
|
||||||
|
|
||||||
|
end architecture rtl;
|
65
fpga/hdl/design/servant_timer_vhdl.vhd
Normal file
65
fpga/hdl/design/servant_timer_vhdl.vhd
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 generics;
|
||||||
|
use generics.wishbone_pkg.all;
|
||||||
|
|
||||||
|
entity servant_timer_vhdl is
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- CPU and bus clock
|
||||||
|
clr : in std_logic; -- Synchronous clear (CPU reset)
|
||||||
|
|
||||||
|
wb_o : out wishbone_slave_out; -- Wishbone bus (out)
|
||||||
|
wb_i : in wishbone_slave_in; -- Wishbone bus (in)
|
||||||
|
|
||||||
|
irq : out std_logic -- System Timer Interrupt
|
||||||
|
);
|
||||||
|
end entity servant_timer_vhdl;
|
||||||
|
|
||||||
|
architecture rtl of servant_timer_vhdl is
|
||||||
|
component servant_timer
|
||||||
|
generic(
|
||||||
|
WIDTH : integer
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
i_clk : in std_logic;
|
||||||
|
i_rst : in std_logic;
|
||||||
|
o_irq : out std_logic;
|
||||||
|
i_wb_dat : in std_logic_vector;
|
||||||
|
i_wb_we : in std_logic;
|
||||||
|
i_wb_cyc : in std_logic;
|
||||||
|
o_wb_dat : out std_logic_vector
|
||||||
|
);
|
||||||
|
end component servant_timer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
servant_timer_inst : component servant_timer
|
||||||
|
generic map(
|
||||||
|
WIDTH => 32
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
i_clk => clk,
|
||||||
|
i_rst => clr,
|
||||||
|
o_irq => irq,
|
||||||
|
i_wb_dat => wb_i.dat,
|
||||||
|
i_wb_we => wb_i.we,
|
||||||
|
i_wb_cyc => wb_i.cyc and wb_i.stb,
|
||||||
|
o_wb_dat => wb_o.dat
|
||||||
|
);
|
||||||
|
|
||||||
|
wb_o.ack <= '1';
|
||||||
|
wb_o.rty <= '0';
|
||||||
|
wb_o.err <= '0';
|
||||||
|
wb_o.stall <= '0';
|
||||||
|
end architecture rtl;
|
247
fpga/hdl/design/top.vhd
Normal file
247
fpga/hdl/design/top.vhd
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 generics;
|
||||||
|
use generics.all;
|
||||||
|
use generics.wishbone_pkg.all;
|
||||||
|
|
||||||
|
library trashernet;
|
||||||
|
use trashernet.all;
|
||||||
|
|
||||||
|
entity top is
|
||||||
|
generic(
|
||||||
|
-- System configuration
|
||||||
|
F_CLK : integer := 12000000;
|
||||||
|
F_CLK_PHY : integer := 48000000;
|
||||||
|
UART_BAUD : integer := 9600
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
clk_12m : in std_logic; -- System clock
|
||||||
|
|
||||||
|
-- UART
|
||||||
|
uart_tx : out std_logic; -- UART TX
|
||||||
|
uart_rx : in std_logic; -- UART RX
|
||||||
|
|
||||||
|
-- Trashernet
|
||||||
|
eth_rx_p : in std_logic; -- Ethernet RX+
|
||||||
|
eth_rx_n : in std_logic; -- Ethernet RX-
|
||||||
|
eth_tx_p : out std_logic_vector(3 downto 0); -- Ethernet TX+
|
||||||
|
eth_tx_n : out std_logic_vector(3 downto 0); -- Ethernet TX-
|
||||||
|
|
||||||
|
-- LEDs
|
||||||
|
eth_led_green : out std_logic;
|
||||||
|
eth_led_orange : out std_logic;
|
||||||
|
led_user : out std_logic;
|
||||||
|
-- PSRAM IF
|
||||||
|
psram_ce_n : out std_logic;
|
||||||
|
psram_sclk : out std_logic;
|
||||||
|
psram_sio : inout std_logic_vector(3 downto 0);
|
||||||
|
-- Config Flash
|
||||||
|
flash_ce_n : out std_logic;
|
||||||
|
flash_sclk : out std_logic;
|
||||||
|
flash_sio : inout std_logic_vector(3 downto 0);
|
||||||
|
-- PMOD
|
||||||
|
pmod : inout std_logic_vector(7 downto 0)
|
||||||
|
);
|
||||||
|
end entity top;
|
||||||
|
|
||||||
|
architecture rtl of top is
|
||||||
|
component pll0
|
||||||
|
port(
|
||||||
|
CLKI : in std_logic;
|
||||||
|
CLKOP : out std_logic;
|
||||||
|
LOCK : out std_logic
|
||||||
|
);
|
||||||
|
end component pll0;
|
||||||
|
|
||||||
|
-- System
|
||||||
|
signal pll_locked : std_logic;
|
||||||
|
signal clk : std_logic;
|
||||||
|
signal rst : std_logic := '1'; -- Asynchronous assert, synchronous release reset
|
||||||
|
signal clr : std_logic := '1'; -- Fully synchronous reset
|
||||||
|
|
||||||
|
signal eth_tx_p_i : std_logic;
|
||||||
|
signal eth_tx_n_i : std_logic;
|
||||||
|
|
||||||
|
-- System Timer
|
||||||
|
signal irq_timer : std_logic;
|
||||||
|
|
||||||
|
-- Wishbone interconnect (master)
|
||||||
|
signal wb_masters_o : wishbone_slave_in_vector(1 downto 0);
|
||||||
|
signal wb_masters_i : wishbone_slave_out_vector(wb_masters_o'range);
|
||||||
|
alias wbi_o is wb_masters_o(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)
|
||||||
|
signal wb_slaves_o : wishbone_master_in_vector(4 downto 0);
|
||||||
|
signal wb_slaves_i : wishbone_master_out_vector(wb_slaves_o'range);
|
||||||
|
alias wb_rom_o is wb_slaves_o(0);
|
||||||
|
alias wb_rom_i is wb_slaves_i(0);
|
||||||
|
alias wb_ram_o is wb_slaves_o(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
|
||||||
|
constant wishbone_addresses : wishbone_address_vector := (
|
||||||
|
0 => x"00000000", -- Boot ROM
|
||||||
|
1 => x"40000000", -- RAM
|
||||||
|
2 => x"80000000", -- Timer
|
||||||
|
3 => x"81000000", -- UART
|
||||||
|
4 => x"82000000" -- Eth
|
||||||
|
);
|
||||||
|
constant wishbone_masks : wishbone_address_vector := (
|
||||||
|
0 => x"FF000000", -- Boot ROM: 256b
|
||||||
|
1 => x"FF000000", -- RAM: Max 16M
|
||||||
|
2 => x"FF000000", -- Timer
|
||||||
|
3 => x"FF000000", -- UART
|
||||||
|
4 => x"FF000000" -- Eth
|
||||||
|
);
|
||||||
|
|
||||||
|
constant IN_SIMULATION : boolean := false --
|
||||||
|
-- pragma translate_off
|
||||||
|
or true --
|
||||||
|
-- pragma translate_on
|
||||||
|
;
|
||||||
|
|
||||||
|
begin
|
||||||
|
clockgen : if IN_SIMULATION generate
|
||||||
|
clock_driver : process
|
||||||
|
constant period : time := 1 sec / real(F_CLK);
|
||||||
|
begin
|
||||||
|
clk <= '0';
|
||||||
|
wait for period / 2;
|
||||||
|
clk <= '1';
|
||||||
|
wait for period / 2;
|
||||||
|
end process clock_driver;
|
||||||
|
|
||||||
|
pll_locked <= '1';
|
||||||
|
|
||||||
|
else generate
|
||||||
|
pll_inst : pll0
|
||||||
|
port map(
|
||||||
|
CLKI => clk_12m,
|
||||||
|
CLKOP => clk,
|
||||||
|
LOCK => pll_locked
|
||||||
|
);
|
||||||
|
end generate clockgen;
|
||||||
|
|
||||||
|
por : process(clk) is
|
||||||
|
variable reset_done : std_logic := '0';
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
rst <= not reset_done;
|
||||||
|
clr <= not reset_done;
|
||||||
|
reset_done := '1';
|
||||||
|
end if;
|
||||||
|
end process por;
|
||||||
|
|
||||||
|
serv_top_vhdl_inst : entity work.serv_top_vhdl
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
clr => clr,
|
||||||
|
wbi_o => wbi_o,
|
||||||
|
wbi_i => wbi_i,
|
||||||
|
wbd_o => wbd_o,
|
||||||
|
wbd_i => wbd_i,
|
||||||
|
irq_timer => irq_timer
|
||||||
|
);
|
||||||
|
|
||||||
|
servant_rom_vhdl_inst : entity work.servant_ram_vhdl
|
||||||
|
generic map(
|
||||||
|
memfile => "../../sw/bootrom/bootrom.vhex",
|
||||||
|
read_only => true,
|
||||||
|
adr_width => 9
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
clr => clr,
|
||||||
|
wb_o => wb_rom_o,
|
||||||
|
wb_i => wb_rom_i
|
||||||
|
);
|
||||||
|
|
||||||
|
aps6404l_wb_inst : entity work.aps6404l_wb
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst => rst,
|
||||||
|
wb_o => wb_ram_o,
|
||||||
|
wb_i => wb_ram_i,
|
||||||
|
psram_ce_n => psram_ce_n,
|
||||||
|
psram_sclk => psram_sclk,
|
||||||
|
psram_sio => psram_sio
|
||||||
|
);
|
||||||
|
|
||||||
|
servant_timer_vhdl_inst : entity work.servant_timer_vhdl
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
clr => clr,
|
||||||
|
wb_o => wb_timer_o,
|
||||||
|
wb_i => wb_timer_i,
|
||||||
|
irq => irq_timer
|
||||||
|
);
|
||||||
|
|
||||||
|
uart_wb_inst : entity work.uart_wb
|
||||||
|
generic map(
|
||||||
|
F_CLK => F_CLK,
|
||||||
|
BAUD_RATE => 9600
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst => rst,
|
||||||
|
wb_o => wb_uart_o,
|
||||||
|
wb_i => wb_uart_i,
|
||||||
|
serial_out => uart_tx,
|
||||||
|
serial_in => uart_rx
|
||||||
|
);
|
||||||
|
|
||||||
|
trashernet_phy_wb_inst : entity work.trashernet_phy_wb
|
||||||
|
generic map(
|
||||||
|
F_CLK => F_CLK,
|
||||||
|
F_CLK_PHY => F_CLK_PHY
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
phy_clk => clk,
|
||||||
|
rst => rst,
|
||||||
|
wb_o => wb_eth_o,
|
||||||
|
wb_i => wb_eth_i,
|
||||||
|
rx_p => eth_rx_p,
|
||||||
|
tx_p => eth_tx_p_i,
|
||||||
|
tx_n => eth_tx_n_i
|
||||||
|
);
|
||||||
|
eth_tx_p <= (others => eth_tx_p_i);
|
||||||
|
eth_tx_n <= (others => eth_tx_n_i);
|
||||||
|
|
||||||
|
wishbone_crossbar_inst : entity generics.wishbone_arbiter
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst => rst,
|
||||||
|
masters_o => wb_masters_o,
|
||||||
|
masters_i => wb_masters_i,
|
||||||
|
slaves_o => wb_slaves_o,
|
||||||
|
slaves_i => wb_slaves_i,
|
||||||
|
address => wishbone_addresses,
|
||||||
|
mask => wishbone_masks
|
||||||
|
);
|
||||||
|
|
||||||
|
eth_led_green <= '0';
|
||||||
|
eth_led_orange <= '1';
|
||||||
|
led_user <= '1';
|
||||||
|
end architecture rtl;
|
97
fpga/hdl/design/trashernet_phy_wb.vhd
Normal file
97
fpga/hdl/design/trashernet_phy_wb.vhd
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 trashernet;
|
||||||
|
use trashernet.trashernet_pkg.all;
|
||||||
|
|
||||||
|
library generics;
|
||||||
|
use generics.wishbone_pkg.all;
|
||||||
|
|
||||||
|
entity trashernet_phy_wb is
|
||||||
|
generic(
|
||||||
|
F_CLK : in integer; -- Clock frequency in Hz
|
||||||
|
F_CLK_PHY : in integer
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
-- Global
|
||||||
|
clk : in std_logic; -- Global clock
|
||||||
|
phy_clk : in std_logic; -- PHY clock
|
||||||
|
rst : in std_logic; -- Asynchronous reset
|
||||||
|
|
||||||
|
-- Wishbone IF
|
||||||
|
wb_o : out wishbone_slave_out; -- Wishbone bus (out)
|
||||||
|
wb_i : in wishbone_slave_in; -- Wishbone bus (in)
|
||||||
|
|
||||||
|
-- Ethernet physical signals
|
||||||
|
rx_p : in std_logic;
|
||||||
|
tx_p : out std_logic;
|
||||||
|
tx_n : out std_logic
|
||||||
|
);
|
||||||
|
end entity trashernet_phy_wb;
|
||||||
|
|
||||||
|
architecture RTL of trashernet_phy_wb is
|
||||||
|
-- PHY application interface
|
||||||
|
signal phy_out : phy_out_t; -- PHY application IF (out)
|
||||||
|
signal phy_in : phy_in_t; -- PHY application IF (in)
|
||||||
|
|
||||||
|
signal wb_adr : unsigned(2 downto 0);
|
||||||
|
|
||||||
|
signal status_register : std_logic_vector(31 downto 0);
|
||||||
|
begin
|
||||||
|
trashernet_phy_inst : entity trashernet.trashernet_phy_cdc
|
||||||
|
generic map(
|
||||||
|
F_CLK => F_CLK,
|
||||||
|
F_CLK_PHY => F_CLK_PHY
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
phy_clk => phy_clk,
|
||||||
|
rst => rst,
|
||||||
|
phy_out => phy_out,
|
||||||
|
phy_in => phy_in,
|
||||||
|
rx_p => rx_p,
|
||||||
|
tx_p => tx_p,
|
||||||
|
tx_n => tx_n
|
||||||
|
);
|
||||||
|
|
||||||
|
wb_adr <= unsigned(wb_i.adr(wb_adr'range));
|
||||||
|
wbif : process(clk, rst) is
|
||||||
|
begin
|
||||||
|
if rst then
|
||||||
|
wb_o.ack <= '0';
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
wb_o.ack <= '0';
|
||||||
|
|
||||||
|
if (wb_i.cyc and wb_i.stb) then
|
||||||
|
wb_o.ack <= '1';
|
||||||
|
if wb_adr = 0 then
|
||||||
|
wb_o.dat <= status_register;
|
||||||
|
else
|
||||||
|
wb_o.dat <= (others => '0');
|
||||||
|
wb_o.dat(7 downto 0) <= phy_out.rx_data; -- TODO: data
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process wbif;
|
||||||
|
|
||||||
|
wb_o.err <= '0';
|
||||||
|
wb_o.rty <= '1';
|
||||||
|
wb_o.stall <= '0';
|
||||||
|
|
||||||
|
phy_in.tx_data_en <= '0';
|
||||||
|
phy_in.tx_data <= (others => '0');
|
||||||
|
|
||||||
|
status_register <= (x"0000000" & "000" & phy_out.carrier_detect);
|
||||||
|
end architecture RTL;
|
123
fpga/hdl/design/uart_wb.vhd
Normal file
123
fpga/hdl/design/uart_wb.vhd
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- Author : Markus Koch <markus@notsyncing.net>
|
||||||
|
-- Contributors : None
|
||||||
|
-- License : Mozilla Public License (MPL) Version 2
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
|
||||||
|
-- ADDR0: RD: [...] TX_BUSY TX_DATA_FULL RX_DATA_EMPTY
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
library generics;
|
||||||
|
use generics.all;
|
||||||
|
use generics.wishbone_pkg.all;
|
||||||
|
|
||||||
|
entity uart_wb is
|
||||||
|
generic(
|
||||||
|
F_CLK : integer;
|
||||||
|
BAUD_RATE : integer := 115200
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
clk : in std_logic;
|
||||||
|
rst : in std_logic;
|
||||||
|
-- Wishbone IF
|
||||||
|
wb_o : out wishbone_slave_out; -- Wishbone bus (out)
|
||||||
|
wb_i : in wishbone_slave_in; -- Wishbone bus (in)
|
||||||
|
|
||||||
|
serial_out : out std_logic;
|
||||||
|
serial_in : in std_logic
|
||||||
|
);
|
||||||
|
end entity uart_wb;
|
||||||
|
|
||||||
|
architecture rtl of uart_wb is
|
||||||
|
signal wb_adr : unsigned(2 downto 0);
|
||||||
|
|
||||||
|
signal status_register : std_logic_vector(31 downto 0);
|
||||||
|
|
||||||
|
signal in_data : std_logic_vector(7 downto 0);
|
||||||
|
signal in_data_valid : std_logic;
|
||||||
|
signal in_data_available : std_logic;
|
||||||
|
|
||||||
|
signal out_data : std_logic_vector(in_data'range);
|
||||||
|
signal out_data_valid : std_logic;
|
||||||
|
signal out_data_latched : std_logic;
|
||||||
|
signal out_busy : std_logic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
uart_tx_inst : entity generics.uart_tx
|
||||||
|
generic map(
|
||||||
|
F_CLK => F_CLK,
|
||||||
|
BAUD_RATE => BAUD_RATE
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst_a => rst,
|
||||||
|
data => out_data,
|
||||||
|
data_valid => out_data_valid,
|
||||||
|
data_latched => out_data_latched,
|
||||||
|
busy => out_busy,
|
||||||
|
serial_out => serial_out
|
||||||
|
);
|
||||||
|
|
||||||
|
uart_rx_inst : entity generics.uart_rx
|
||||||
|
generic map(
|
||||||
|
F_CLK => F_CLK,
|
||||||
|
BAUD_RATE => BAUD_RATE
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst_a => rst,
|
||||||
|
data => in_data,
|
||||||
|
data_valid => in_data_valid,
|
||||||
|
serial_in_a => serial_in
|
||||||
|
);
|
||||||
|
|
||||||
|
wb_adr <= unsigned(wb_i.adr(wb_adr'range));
|
||||||
|
status_register <= x"000000" & "00000" & out_busy & out_data_valid & (not in_data_available);
|
||||||
|
|
||||||
|
wb_if : process(clk, rst) is
|
||||||
|
begin
|
||||||
|
if rst then
|
||||||
|
in_data_available <= '0';
|
||||||
|
out_data_valid <= '0';
|
||||||
|
wb_o.ack <= '0';
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
wb_o.ack <= '0';
|
||||||
|
|
||||||
|
if out_data_latched then
|
||||||
|
out_data_valid <= '0';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if (wb_i.CYC and wb_i.STB) then
|
||||||
|
wb_o.ack <= '1';
|
||||||
|
if wb_adr = 0 then -- status reg
|
||||||
|
wb_o.dat <= status_register;
|
||||||
|
else -- data reg (write to transmit, read to retrieve)
|
||||||
|
if wb_i.we then
|
||||||
|
out_data <= wb_i.dat(out_data'range);
|
||||||
|
out_data_valid <= '1';
|
||||||
|
else
|
||||||
|
wb_o.dat <= x"000000" & in_data;
|
||||||
|
in_data_available <= '0';
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if in_data_valid then
|
||||||
|
in_data_available <= '1';
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process wb_if;
|
||||||
|
|
||||||
|
wb_o.err <= '0';
|
||||||
|
wb_o.stall <= '0';
|
||||||
|
wb_o.rty <= '0';
|
||||||
|
|
||||||
|
end architecture rtl;
|
178
fpga/hdl/device_models/aps6404l.vhd
Normal file
178
fpga/hdl/device_models/aps6404l.vhd
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
use std.textio.all;
|
||||||
|
|
||||||
|
entity aps6404l is
|
||||||
|
generic(
|
||||||
|
LOG_EN : boolean := true
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
ce_n : in std_logic;
|
||||||
|
sclk : in std_logic;
|
||||||
|
sio : inout std_logic_vector(3 downto 0)
|
||||||
|
);
|
||||||
|
end entity aps6404l;
|
||||||
|
|
||||||
|
architecture bench of aps6404l is
|
||||||
|
procedure print(text : string) is
|
||||||
|
variable buf : line;
|
||||||
|
begin
|
||||||
|
if not LOG_EN then
|
||||||
|
return;
|
||||||
|
end if;
|
||||||
|
write(buf, string'("aps6404l: "));
|
||||||
|
write(buf, text);
|
||||||
|
WriteLine(OUTPUT, buf);
|
||||||
|
end procedure print;
|
||||||
|
|
||||||
|
begin
|
||||||
|
test : process is
|
||||||
|
type rx_state_t is (COMMAND, READ, WRITE, COMPLETE);
|
||||||
|
type byte_vector is array (natural range <>) of std_logic_vector(7 downto 0);
|
||||||
|
variable mem : byte_vector(0 to 1023);
|
||||||
|
variable bytes : byte_vector(0 to 32);
|
||||||
|
variable cnt, bytecnt : integer;
|
||||||
|
variable state : rx_state_t;
|
||||||
|
|
||||||
|
variable mode : integer := 0;
|
||||||
|
variable wrap_boundary : boolean := false;
|
||||||
|
|
||||||
|
variable dout : std_logic_vector(7 downto 0);
|
||||||
|
variable addr : integer;
|
||||||
|
|
||||||
|
variable sio_temp : std_logic_vector(sio'range);
|
||||||
|
|
||||||
|
procedure handle(command_edge : boolean) is
|
||||||
|
begin
|
||||||
|
if command_edge then
|
||||||
|
case state is
|
||||||
|
when COMMAND =>
|
||||||
|
case bytes(0) is
|
||||||
|
when x"66" =>
|
||||||
|
print(" SPI reset enter");
|
||||||
|
state := COMPLETE;
|
||||||
|
|
||||||
|
when x"99" =>
|
||||||
|
print(" SPI reset execute");
|
||||||
|
mode := 0;
|
||||||
|
wrap_boundary := false;
|
||||||
|
state := COMPLETE;
|
||||||
|
|
||||||
|
when x"35" =>
|
||||||
|
print(" QPI enter");
|
||||||
|
mode := 1;
|
||||||
|
state := COMPLETE;
|
||||||
|
|
||||||
|
when x"F5" =>
|
||||||
|
print(" QPI exit");
|
||||||
|
mode := 0;
|
||||||
|
state := COMPLETE;
|
||||||
|
|
||||||
|
when x"C0" =>
|
||||||
|
print(" Wrap Boundary Toggle");
|
||||||
|
wrap_boundary := not wrap_boundary;
|
||||||
|
state := COMPLETE;
|
||||||
|
|
||||||
|
when x"0B" =>
|
||||||
|
print(" QPI Read Slow");
|
||||||
|
state := READ;
|
||||||
|
|
||||||
|
when x"EB" =>
|
||||||
|
print(" QPI Read Fast");
|
||||||
|
state := READ;
|
||||||
|
|
||||||
|
when x"02" =>
|
||||||
|
print(" QPI Write (1)");
|
||||||
|
state := WRITE;
|
||||||
|
|
||||||
|
when x"38" =>
|
||||||
|
print(" QPI Write (2)");
|
||||||
|
state := WRITE;
|
||||||
|
|
||||||
|
when others =>
|
||||||
|
print(" Unknown command: 0x" & to_hstring(bytes(0)));
|
||||||
|
state := COMPLETE;
|
||||||
|
end case;
|
||||||
|
|
||||||
|
when READ =>
|
||||||
|
if bytecnt = 3 then
|
||||||
|
print(" Addr: " & to_hstring(bytes(1)) & to_hstring(bytes(2)) & to_hstring(bytes(3)));
|
||||||
|
addr := to_integer(unsigned(std_logic_vector'(bytes(1), bytes(2), bytes(3))));
|
||||||
|
elsif bytecnt > 4 then
|
||||||
|
dout := mem(addr);
|
||||||
|
print(" Read " & integer'image(addr) & ": " & to_hstring(mem(addr)));
|
||||||
|
addr := addr + 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when WRITE =>
|
||||||
|
if bytecnt = 3 then
|
||||||
|
print(" Addr: " & to_hstring(bytes(1)) & to_hstring(bytes(2)) & to_hstring(bytes(3)));
|
||||||
|
addr := to_integer(unsigned(std_logic_vector'(bytes(1), bytes(2), bytes(3))));
|
||||||
|
elsif bytecnt > 3 then
|
||||||
|
print(" Write " & integer'image(addr) & ": " & to_hstring(bytes(bytecnt)));
|
||||||
|
mem(addr) := bytes(bytecnt);
|
||||||
|
addr := addr + 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when COMPLETE =>
|
||||||
|
null;
|
||||||
|
end case;
|
||||||
|
|
||||||
|
bytecnt := bytecnt + 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if state = READ and bytecnt > 4 then
|
||||||
|
sio_temp := dout(7 downto 4) when command_edge else dout(3 downto 0);
|
||||||
|
sio <= sio_temp after 5 ns;
|
||||||
|
end if;
|
||||||
|
end procedure handle;
|
||||||
|
|
||||||
|
begin
|
||||||
|
sio <= (others => 'Z');
|
||||||
|
wait until ce_n = '0';
|
||||||
|
print("Selected.");
|
||||||
|
bytes := (others => (others => 'U'));
|
||||||
|
cnt := 0;
|
||||||
|
bytecnt := 0;
|
||||||
|
state := COMMAND;
|
||||||
|
loop
|
||||||
|
wait on sclk, ce_n;
|
||||||
|
|
||||||
|
if mode = 0 then -- SPI
|
||||||
|
if falling_edge(sclk) then
|
||||||
|
bytes(cnt / 8)(7 - (cnt mod 8)) := sio(0);
|
||||||
|
cnt := cnt + 1;
|
||||||
|
if cnt mod 4 = 0 then
|
||||||
|
handle(cnt mod 8 = 0);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
else -- QPI
|
||||||
|
if falling_edge(sclk) then
|
||||||
|
bytes(cnt / 2)((1 - (cnt mod 2) + 1) * 4 - 1 downto (1 - (cnt mod 2)) * 4) := sio;
|
||||||
|
cnt := cnt + 1;
|
||||||
|
end if;
|
||||||
|
if falling_edge(sclk) then
|
||||||
|
|
||||||
|
handle(cnt mod 2 = 0);
|
||||||
|
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
exit when ce_n = '1';
|
||||||
|
end loop;
|
||||||
|
print("Deselected.");
|
||||||
|
end process test;
|
||||||
|
|
||||||
|
end architecture bench;
|
125
fpga/hdl/generics/fifo_block.vhd
Normal file
125
fpga/hdl/generics/fifo_block.vhd
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- Author : Markus Koch <markus@notsyncing.net>
|
||||||
|
-- Contributors : None
|
||||||
|
-- License : Mozilla Public License (MPL) Version 2
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
|
||||||
|
-- Tech hint: Width of FIFO will be width of `data_in` + 1.
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
use ieee.math_real.all;
|
||||||
|
|
||||||
|
entity fifo_block is
|
||||||
|
generic(
|
||||||
|
SIZE : integer := 15 -- Entries in the FIFO (of size data), SIZE=(n^2)-1 recommended
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
-- generic ports
|
||||||
|
clk : in std_logic; -- System clock
|
||||||
|
rst_a : in std_logic; -- Asynchronous reset
|
||||||
|
clr : in std_logic; -- Remove all entries
|
||||||
|
|
||||||
|
-- FIFO in
|
||||||
|
data_in : in std_logic_vector; -- Data input into FIFO
|
||||||
|
write : in std_logic; -- Data is latched when `data_in_valid and not full`
|
||||||
|
commit : in std_logic; -- Finalize block
|
||||||
|
abort : in std_logic; -- Abort current block
|
||||||
|
full : out std_logic; -- FIFO is full
|
||||||
|
|
||||||
|
-- FIFO out
|
||||||
|
data_out : out std_logic_vector; -- Data output from FIFO
|
||||||
|
data_first : out std_logic; -- Currently visible word is first in packet
|
||||||
|
empty : out std_logic; -- FIFO is empty. '0' means "data is available".
|
||||||
|
read : in std_logic; -- Acknowledge that `data_out` was read. The word is removed and next one shifted from FIFO when `read and not empty`.
|
||||||
|
|
||||||
|
-- FIFO meta
|
||||||
|
usage : out integer -- Usage counter
|
||||||
|
);
|
||||||
|
end fifo_block;
|
||||||
|
|
||||||
|
architecture rtl of fifo_block is
|
||||||
|
constant MEMORY_WIDTH : integer := data_in'length + 1;
|
||||||
|
subtype pointer_t is integer range 0 to SIZE - 1;
|
||||||
|
type memory_t is array (pointer_t) of std_logic_vector(MEMORY_WIDTH - 1 downto 0);
|
||||||
|
|
||||||
|
signal memory : memory_t;
|
||||||
|
signal read_pointer : pointer_t;
|
||||||
|
signal write_pointer : pointer_t;
|
||||||
|
signal read_pointer_last : pointer_t;
|
||||||
|
signal write_pointer_committed : pointer_t;
|
||||||
|
signal current_is_first : std_logic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
fifo : process(rst_a, clk) is
|
||||||
|
variable succesful_read : std_logic;
|
||||||
|
variable succesful_write : std_logic;
|
||||||
|
variable write_pointer_next : pointer_t;
|
||||||
|
variable read_pointer_next : pointer_t;
|
||||||
|
begin
|
||||||
|
if rst_a then
|
||||||
|
read_pointer <= 0;
|
||||||
|
write_pointer <= 0;
|
||||||
|
read_pointer_last <= SIZE - 1;
|
||||||
|
write_pointer_committed <= 0;
|
||||||
|
current_is_first <= '1';
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
succesful_read := read and not empty;
|
||||||
|
succesful_write := write and (not full or succesful_read);
|
||||||
|
|
||||||
|
write_pointer_next := write_pointer;
|
||||||
|
read_pointer_next := read_pointer;
|
||||||
|
|
||||||
|
if succesful_read then
|
||||||
|
read_pointer_next := (read_pointer_next + 1) mod SIZE;
|
||||||
|
read_pointer_last <= read_pointer;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if succesful_write then
|
||||||
|
memory(write_pointer) <= current_is_first & data_in;
|
||||||
|
write_pointer_next := (write_pointer_next + 1) mod SIZE;
|
||||||
|
current_is_first <= '0';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if succesful_write xor succesful_read then
|
||||||
|
if succesful_write then
|
||||||
|
usage <= usage + 1;
|
||||||
|
else
|
||||||
|
usage <= usage - 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if commit then
|
||||||
|
write_pointer_committed <= write_pointer;
|
||||||
|
current_is_first <= '1';
|
||||||
|
elsif abort then
|
||||||
|
write_pointer_next := write_pointer_committed;
|
||||||
|
current_is_first <= '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
read_pointer <= read_pointer_next;
|
||||||
|
write_pointer <= write_pointer_next;
|
||||||
|
|
||||||
|
if clr then
|
||||||
|
read_pointer <= 0;
|
||||||
|
write_pointer <= 0;
|
||||||
|
write_pointer_committed <= 0;
|
||||||
|
current_is_first <= '1';
|
||||||
|
usage <= 0;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process fifo;
|
||||||
|
|
||||||
|
full <= '1' when read_pointer_last = write_pointer else '0';
|
||||||
|
empty <= '1' when (read_pointer = write_pointer_committed) else '0';
|
||||||
|
|
||||||
|
data_out <= memory(read_pointer)(data_out'range);
|
||||||
|
data_first <= memory(read_pointer)(MEMORY_WIDTH - 1);
|
||||||
|
|
||||||
|
end rtl;
|
55
fpga/hdl/generics/synchronizer.vhd
Normal file
55
fpga/hdl/generics/synchronizer.vhd
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
entity synchronizer is
|
||||||
|
generic(
|
||||||
|
init_value : std_logic := '0'; -- Default value of all synchronized signals after reset (ignored when `init_value_v` is set)
|
||||||
|
init_value_v : std_logic_vector := ""; -- Set this reset the bits of the vector individually, leave "" to use `init_value` for all.
|
||||||
|
stages : natural := 2 -- Number of synchronizer flip flops per channel
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- Synchronizer clock
|
||||||
|
rst : in std_logic; -- Asynchronous reset
|
||||||
|
|
||||||
|
data_in_a : in std_logic_vector; -- Asynchronous signal input
|
||||||
|
data_out : out std_logic_vector -- Synchronized signal output
|
||||||
|
);
|
||||||
|
end entity synchronizer;
|
||||||
|
|
||||||
|
architecture rtl of synchronizer is
|
||||||
|
type synchronizer_chain_t is array (stages - 1 downto 0) of std_logic_vector(data_in_a'range);
|
||||||
|
signal synchronizer_chain : synchronizer_chain_t;
|
||||||
|
|
||||||
|
begin
|
||||||
|
assert ((init_value_v'length = 0) or (init_value_v'length = data_in_a'length)) report "init_value_v must have the same width as data_in_a when used" severity error;
|
||||||
|
|
||||||
|
sync_p : process(clk, rst) is
|
||||||
|
begin
|
||||||
|
if (rst = '1') then
|
||||||
|
if (init_value_v'length = 0) then
|
||||||
|
synchronizer_chain <= (others => (others => init_value));
|
||||||
|
else
|
||||||
|
synchronizer_chain <= (others => init_value_v);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
elsif (rising_edge(clk)) then
|
||||||
|
for i in synchronizer_chain'high - 1 downto synchronizer_chain'low loop
|
||||||
|
synchronizer_chain(i + 1) <= synchronizer_chain(i);
|
||||||
|
end loop;
|
||||||
|
synchronizer_chain(0) <= data_in_a;
|
||||||
|
end if;
|
||||||
|
end process sync_p;
|
||||||
|
|
||||||
|
data_out <= synchronizer_chain(synchronizer_chain'high);
|
||||||
|
end architecture rtl;
|
99
fpga/hdl/generics/uart_rx.vhd
Normal file
99
fpga/hdl/generics/uart_rx.vhd
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
||||||
|
use ieee.math_real.all;
|
||||||
|
|
||||||
|
entity uart_rx is
|
||||||
|
generic(
|
||||||
|
F_CLK : natural := 50_000_000; -- System clock speed
|
||||||
|
BAUD_RATE : natural := 115_200 -- Desired baudrate
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- System clock @ F_CLK
|
||||||
|
rst_a : in std_logic; -- Asynchronous reset
|
||||||
|
|
||||||
|
data : out std_logic_vector; -- Receive payload word (width determines width of UART payload)
|
||||||
|
data_valid : out std_logic; -- Data is valid
|
||||||
|
|
||||||
|
serial_in_a : in std_logic -- UART RX line (asynchronous) @ BAUDRATE
|
||||||
|
);
|
||||||
|
end entity uart_rx;
|
||||||
|
|
||||||
|
architecture rtl of uart_rx is
|
||||||
|
signal serial_in : std_logic;
|
||||||
|
|
||||||
|
constant BITCLK_MAX : integer := integer(real(F_CLK) / real(BAUD_RATE));
|
||||||
|
constant BITCLK_START : integer := BITCLK_MAX / 2;
|
||||||
|
signal bitclk_cnt : integer range 0 to BITCLK_MAX;
|
||||||
|
signal bit_stb : std_logic;
|
||||||
|
|
||||||
|
constant BITCNT_MAX : integer := 10;
|
||||||
|
signal cnt : integer range 0 to BITCNT_MAX;
|
||||||
|
signal busy : std_logic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
synchronizer_rx_inst : entity work.synchronizer
|
||||||
|
generic map(
|
||||||
|
init_value => '1'
|
||||||
|
)
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
rst => rst_a,
|
||||||
|
data_in_a(0) => serial_in_a,
|
||||||
|
data_out(0) => serial_in
|
||||||
|
);
|
||||||
|
|
||||||
|
rx : process(clk, rst_a) is
|
||||||
|
begin
|
||||||
|
if rst_a then
|
||||||
|
cnt <= 0;
|
||||||
|
data_valid <= '0';
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
data_valid <= '0';
|
||||||
|
|
||||||
|
if (cnt = 0 and serial_in = '0') or bit_stb = '1' then
|
||||||
|
if cnt = BITCNT_MAX then
|
||||||
|
cnt <= 0;
|
||||||
|
data_valid <= '1';
|
||||||
|
else
|
||||||
|
data <= serial_in & data(7 downto 1);
|
||||||
|
cnt <= cnt + 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process rx;
|
||||||
|
busy <= '1' when cnt /= 0 else '0';
|
||||||
|
|
||||||
|
bitclk : process(clk, rst_a) is
|
||||||
|
begin
|
||||||
|
if rst_a then
|
||||||
|
bit_stb <= '0';
|
||||||
|
bitclk_cnt <= 0;
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
bit_stb <= '0';
|
||||||
|
|
||||||
|
if not busy then
|
||||||
|
bitclk_cnt <= BITCLK_START;
|
||||||
|
else
|
||||||
|
if bitclk_cnt = 0 then
|
||||||
|
bitclk_cnt <= BITCLK_MAX;
|
||||||
|
bit_stb <= '1';
|
||||||
|
else
|
||||||
|
bitclk_cnt <= bitclk_cnt - 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process bitclk;
|
||||||
|
end architecture rtl;
|
96
fpga/hdl/generics/uart_tx.vhd
Normal file
96
fpga/hdl/generics/uart_tx.vhd
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
||||||
|
use ieee.math_real.round;
|
||||||
|
|
||||||
|
entity uart_tx is
|
||||||
|
generic(
|
||||||
|
F_CLK : integer := 50_000_000; -- System clock speed
|
||||||
|
BAUD_RATE : integer := 115_200 -- Desired baudrate
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- System clock @ F_CLK
|
||||||
|
rst_a : in std_logic; -- Asynchronous reset
|
||||||
|
|
||||||
|
data : in std_logic_vector; -- Data to send (width determines width of UART payload)
|
||||||
|
data_valid : in std_logic; -- Data is valid, TX at next opportunity
|
||||||
|
|
||||||
|
data_latched : out std_logic; -- The data word has been latched, go ahead and apply the next one, or negate data_valid to end the transaction after the current word
|
||||||
|
busy : out std_logic; -- The core is busy transmitting a data word
|
||||||
|
serial_out : out std_logic -- UART TX line
|
||||||
|
);
|
||||||
|
end entity uart_tx;
|
||||||
|
|
||||||
|
architecture rtl of uart_tx is
|
||||||
|
constant COUNTER_MAX : natural := 10;
|
||||||
|
|
||||||
|
signal sr : std_logic_vector((data'length + 1) - 1 downto 0);
|
||||||
|
|
||||||
|
signal bit_cnt : integer range 0 to COUNTER_MAX;
|
||||||
|
|
||||||
|
constant BITCLK_MAX : integer := integer(real(F_CLK) / real(BAUD_RATE));
|
||||||
|
signal bitclk_cnt : integer range 0 to BITCLK_MAX;
|
||||||
|
signal bit_stb : std_logic;
|
||||||
|
|
||||||
|
begin
|
||||||
|
tx_fsm : process(clk, rst_a) is
|
||||||
|
begin
|
||||||
|
if (rst_a = '1') then
|
||||||
|
sr <= (others => '1');
|
||||||
|
bit_cnt <= 0;
|
||||||
|
data_latched <= '0';
|
||||||
|
|
||||||
|
elsif (rising_edge(clk)) then
|
||||||
|
data_latched <= '0';
|
||||||
|
|
||||||
|
if ((bit_stb = '1') or (bit_cnt = 0)) then
|
||||||
|
sr <= '1' & sr(sr'high downto 1);
|
||||||
|
if (bit_cnt = 0) then
|
||||||
|
if (data_valid = '1') then
|
||||||
|
data_latched <= '1';
|
||||||
|
sr <= data & '0';
|
||||||
|
bit_cnt <= COUNTER_MAX;
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
bit_cnt <= bit_cnt - 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process tx_fsm;
|
||||||
|
serial_out <= sr(0); -- @suppress PID1: Not a readback signal
|
||||||
|
|
||||||
|
busy <= '1' when (bit_cnt /= 0) or (data_valid = '1') else '0';
|
||||||
|
|
||||||
|
bitclk : process(clk, rst_a) is
|
||||||
|
begin
|
||||||
|
if rst_a then
|
||||||
|
bit_stb <= '0';
|
||||||
|
bitclk_cnt <= BITCLK_MAX;
|
||||||
|
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
bit_stb <= '0';
|
||||||
|
|
||||||
|
if not busy then
|
||||||
|
bitclk_cnt <= BITCLK_MAX;
|
||||||
|
else
|
||||||
|
if bitclk_cnt = 0 then
|
||||||
|
bitclk_cnt <= BITCLK_MAX;
|
||||||
|
bit_stb <= '1';
|
||||||
|
else
|
||||||
|
bitclk_cnt <= bitclk_cnt - 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process bitclk;
|
||||||
|
|
||||||
|
end architecture rtl;
|
136
fpga/hdl/generics/wishbone_arbiter.vhd
Normal file
136
fpga/hdl/generics/wishbone_arbiter.vhd
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
||||||
|
use work.wishbone_pkg.all;
|
||||||
|
|
||||||
|
entity wishbone_arbiter is
|
||||||
|
generic(
|
||||||
|
ASYNC : boolean := true; -- Generate the switch as a fully asynchronous circuit when false, register outputs when true.
|
||||||
|
NO_DEAD_SLAVE : boolean := true -- Connect to slave 0,0 on no address match (saves resources)
|
||||||
|
);
|
||||||
|
port(
|
||||||
|
clk : in std_logic; -- System clock, must be shared with all slaves and masters.
|
||||||
|
rst : in std_logic; -- Asynchronous reset
|
||||||
|
|
||||||
|
-- Master connections (crossbar is a slave)
|
||||||
|
masters_o : in wishbone_slave_in_vector; -- Connections to masters (crossbar is slave), inputs to crossbar
|
||||||
|
masters_i : out wishbone_slave_out_vector; -- Connections to masters (crossbar is slave), outputs from crossbar
|
||||||
|
|
||||||
|
-- Slave connections (crossbar is a master)
|
||||||
|
slaves_o : in wishbone_master_in_vector; -- Connections to slaves (crossbar is master), inputs to crossbar
|
||||||
|
slaves_i : out wishbone_master_out_vector; -- Connections to slaves (crossbar is master), outputs from crossbar
|
||||||
|
|
||||||
|
-- Address configuration of the slaves connected
|
||||||
|
address : in wishbone_address_vector; -- Base address for each slave connection. Must be the same size as `master_i` and `master_o`
|
||||||
|
mask : in wishbone_address_vector -- Bit mask for slave base addresses. Must be the same size as `master_i` and `master_o`
|
||||||
|
);
|
||||||
|
end wishbone_arbiter;
|
||||||
|
|
||||||
|
architecture rtl of wishbone_arbiter is
|
||||||
|
subtype slave_index is integer range 0 to slaves_i'length - 1;
|
||||||
|
subtype master_index is integer range 0 to masters_i'length - 1;
|
||||||
|
|
||||||
|
signal slave_sel : slave_index;
|
||||||
|
signal master_sel : master_index;
|
||||||
|
signal matched : std_logic;
|
||||||
|
|
||||||
|
constant SLEEPY_MASTER : wishbone_master_out := (cyc => '0', stb => '0', adr => (others => '-'), sel => (others => '-'), we => '-', dat => (others => '-'));
|
||||||
|
constant SLEEPY_SLAVE : wishbone_slave_out := (ack => '0', err => '0', rty => '0', stall => '1', dat => (others => '-'));
|
||||||
|
|
||||||
|
procedure generate_logic(
|
||||||
|
signal mo : in wishbone_slave_in_vector;
|
||||||
|
signal so : in wishbone_master_in_vector;
|
||||||
|
signal ssel : out slave_index;
|
||||||
|
signal msel : out master_index;
|
||||||
|
signal mtch : out std_logic
|
||||||
|
) is
|
||||||
|
begin
|
||||||
|
ssel <= 0;
|
||||||
|
msel <= 0;
|
||||||
|
mtch <= '0';
|
||||||
|
master_loop : for master_id in mo'range loop
|
||||||
|
if (mo(master_id).cyc and mo(master_id).stb) then
|
||||||
|
slave_loop : for slave_id in so'range loop
|
||||||
|
if (mo(master_id).adr and mask(slave_id)) = address(slave_id) then
|
||||||
|
ssel <= slave_id;
|
||||||
|
msel <= master_id;
|
||||||
|
mtch <= '1';
|
||||||
|
exit master_loop;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end procedure generate_logic;
|
||||||
|
|
||||||
|
procedure connect_slaves(
|
||||||
|
signal mo : in wishbone_slave_in_vector;
|
||||||
|
signal mi : out wishbone_slave_out_vector;
|
||||||
|
signal so : in wishbone_master_in_vector;
|
||||||
|
signal si : out wishbone_master_out_vector;
|
||||||
|
constant ssel : in slave_index;
|
||||||
|
constant msel : in master_index;
|
||||||
|
signal mtch : in std_logic
|
||||||
|
) is
|
||||||
|
begin
|
||||||
|
for slave_id in si'range loop
|
||||||
|
si(slave_id) <= SLEEPY_MASTER;
|
||||||
|
-- Always connect data path from selected master to *all* slave inputs
|
||||||
|
si(slave_id).dat <= mo(msel).dat;
|
||||||
|
si(slave_id).we <= mo(msel).we;
|
||||||
|
si(slave_id).sel <= mo(msel).sel;
|
||||||
|
si(slave_id).adr <= mo(msel).adr and (not mask(ssel));
|
||||||
|
if (mtch = '1' or NO_DEAD_SLAVE) and (slave_id = ssel) then -- If we are the currently active slave, then also connect these (else SLEEPY default)
|
||||||
|
si(slave_id).cyc <= mo(msel).cyc;
|
||||||
|
si(slave_id).stb <= mo(msel).stb;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
for master_id in mi'range loop
|
||||||
|
mi(master_id) <= SLEEPY_SLAVE;
|
||||||
|
-- Always connect data path from selected slave to *all* master inputs
|
||||||
|
mi(master_id).dat <= so(ssel).dat;
|
||||||
|
if (mtch = '1' or NO_DEAD_SLAVE) and (master_id = msel) then -- If we are the currently active master, also connect these (else SLEEPY default)
|
||||||
|
mi(master_id).ack <= so(ssel).ack;
|
||||||
|
mi(master_id).err <= so(ssel).err;
|
||||||
|
mi(master_id).rty <= so(ssel).rty;
|
||||||
|
mi(master_id).stall <= so(ssel).stall;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end procedure connect_slaves;
|
||||||
|
|
||||||
|
begin
|
||||||
|
assert ASYNC = true report "Arbiter does not support ASYNC mode" severity failure;
|
||||||
|
|
||||||
|
sync : if ASYNC generate
|
||||||
|
name : process(masters_o, slaves_o, address, mask) is
|
||||||
|
begin
|
||||||
|
generate_logic(masters_o, slaves_o, slave_sel, master_sel, matched);
|
||||||
|
end process name;
|
||||||
|
|
||||||
|
else generate
|
||||||
|
sync_proc : process(rst, clk) is
|
||||||
|
begin
|
||||||
|
if rst then
|
||||||
|
slave_sel <= 0;
|
||||||
|
master_sel <= 0;
|
||||||
|
elsif rising_edge(clk) then
|
||||||
|
generate_logic(masters_o, slaves_o, slave_sel, master_sel, matched);
|
||||||
|
end if;
|
||||||
|
end process sync_proc;
|
||||||
|
end generate sync;
|
||||||
|
|
||||||
|
name : process(masters_o, slaves_o, slave_sel, master_sel, matched, mask) is
|
||||||
|
begin
|
||||||
|
connect_slaves(masters_o, masters_i, slaves_o, slaves_i, slave_sel, master_sel, matched);
|
||||||
|
end process name;
|
||||||
|
|
||||||
|
end rtl;
|
51
fpga/hdl/generics/wishbone_pkg.vhd
Normal file
51
fpga/hdl/generics/wishbone_pkg.vhd
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- TODO
|
||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
package wishbone_pkg is
|
||||||
|
constant WISHBONE_ADDRESS_WIDTH : integer := 32;
|
||||||
|
constant WISHBONE_DATA_WIDTH : integer := 32;
|
||||||
|
|
||||||
|
subtype wishbone_address is std_logic_vector(WISHBONE_ADDRESS_WIDTH - 1 downto 0);
|
||||||
|
subtype wishbone_data is std_logic_vector(WISHBONE_DATA_WIDTH - 1 downto 0);
|
||||||
|
subtype wishbone_byte_select is std_logic_vector((WISHBONE_ADDRESS_WIDTH / 8) - 1 downto 0);
|
||||||
|
subtype wishbone_cycle_type is std_logic_vector(2 downto 0);
|
||||||
|
subtype wishbone_burst_type is std_logic_vector(1 downto 0);
|
||||||
|
|
||||||
|
type wishbone_master_out is record
|
||||||
|
cyc : std_logic;
|
||||||
|
stb : std_logic;
|
||||||
|
adr : wishbone_address;
|
||||||
|
sel : wishbone_byte_select;
|
||||||
|
we : std_logic;
|
||||||
|
dat : wishbone_data;
|
||||||
|
end record wishbone_master_out;
|
||||||
|
subtype wishbone_slave_in is wishbone_master_out;
|
||||||
|
|
||||||
|
type wishbone_slave_out is record
|
||||||
|
ack : std_logic;
|
||||||
|
err : std_logic;
|
||||||
|
rty : std_logic;
|
||||||
|
stall : std_logic;
|
||||||
|
dat : wishbone_data;
|
||||||
|
end record wishbone_slave_out;
|
||||||
|
subtype wishbone_master_in is wishbone_slave_out;
|
||||||
|
|
||||||
|
type wishbone_master_out_vector is array (natural range <>) of wishbone_master_out;
|
||||||
|
type wishbone_slave_out_vector is array (natural range <>) of wishbone_slave_out;
|
||||||
|
subtype wishbone_slave_in_vector is wishbone_master_out_vector;
|
||||||
|
subtype wishbone_master_in_vector is wishbone_slave_out_vector;
|
||||||
|
|
||||||
|
type wishbone_address_vector is array (natural range <>) of wishbone_address;
|
||||||
|
type wishbone_data_vector is array (natural range <>) of wishbone_data;
|
||||||
|
end wishbone_pkg;
|
8
fpga/hdl/header.sh
Executable file
8
fpga/hdl/header.sh
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
files=`find bench/ design/ device_models/ generics/ -name *.vhd`
|
||||||
|
|
||||||
|
for file in $files; do
|
||||||
|
cp $file /tmp/t
|
||||||
|
cat /tmp/h /tmp/t > $file
|
||||||
|
done
|
1
fpga/hdl/serv
Submodule
1
fpga/hdl/serv
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 086090046c98d31787af5e657ce0d4adbd5815f2
|
1
fpga/hdl/trashernet
Submodule
1
fpga/hdl/trashernet
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit da7e329939d12e853acbd7636701350babf5e3f4
|
57
fpga/run.py
Executable file
57
fpga/run.py
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
#!/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__, "..")) : {
|
||||||
|
"bench",
|
||||||
|
"design",
|
||||||
|
"device_models",
|
||||||
|
"generics",
|
||||||
|
"serv",
|
||||||
|
"trashernet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project_dir=pathlib.Path(__file__).parent.resolve()
|
||||||
|
|
||||||
|
libs = {}
|
||||||
|
|
||||||
|
vu = VUnit.from_argv()
|
||||||
|
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