fpga: Continue work on full HW support

This commit is contained in:
Markus Koch 2024-07-06 19:14:39 +02:00
parent c7caf2189b
commit dd7cf08b6f
9 changed files with 274 additions and 54 deletions

View File

@ -1,5 +1,20 @@
#!/bin/bash #!/bin/bash
# -------------------------------------------------------------------------- --
# TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
# -------------------------------------------------------------------------- --
# TODO
# -------------------------------------------------------------------------- --
# Author : Markus Koch <markus@notsyncing.net>
# Contributors : None
# License : Mozilla Public License (MPL) Version 2
# -------------------------------------------------------------------------- --
if [ "$1" == "flash" ]; then
openFPGALoader --unprotect-flash -f -c ft2232 -b ice40_generic build/bitstream.bin
exit 0
fi
mkdir -p build mkdir -p build
cd build cd build
@ -8,7 +23,7 @@ set -e
../run.py --compile ../run.py --compile
BASEDIR=".." BASEDIR=".."
DEVICE=--u4k # --up5k, --u4k DEVICE=--up5k # --up5k, --u4k
PACKAGE=sg48 PACKAGE=sg48
# Collect pre-analyzed VHDL sources # Collect pre-analyzed VHDL sources
@ -22,7 +37,7 @@ VLOGS="$VLOGS $SERV/servant/servant_ram.v $SERV/servant/servant_timer.v"
# Synthesize and PnR # Synthesize and PnR
# -device <hx | lp | u> # -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" 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 nextpnr-ice40 $DEVICE --package $PACKAGE --asc netlist.asc --report report.json --detailed-timing-report --json netlist.json --pcf ../constraints.pcf
# Generate bitstream # Generate bitstream
icepack netlist.asc bitstream.bin icepack netlist.asc bitstream.bin

View File

@ -23,9 +23,9 @@ set_io pmod[7] 31
set_io uart_rx 37 set_io uart_rx 37
set_io uart_tx 36 set_io uart_tx 36
set_io clk_12m 35 set_io clk_50m 35
set_io eth_rx_n 38 #set_io eth_rx_n 38
set_io eth_rx_p 42 set_io eth_rx_p 42
set_io eth_tx_n[0] 46 set_io eth_tx_n[0] 46
@ -42,3 +42,6 @@ set_io eth_led_green 40
set_io eth_led_orange 41 set_io eth_led_orange 41
set_io led_user 34 set_io led_user 34
set_frequency clk 24
set_frequency clk_phy 50

View File

@ -73,11 +73,11 @@ begin
top_inst : entity design.top top_inst : entity design.top
port map( port map(
clk_12m => clk, clk_50m => clk,
uart_tx => uart_txd, uart_tx => uart_txd,
uart_rx => uart_rxd, uart_rx => uart_rxd,
eth_rx_p => rx_p, eth_rx_p => rx_p,
eth_rx_n => rx_n, --eth_rx_n => rx_n,
eth_tx_p => tx_p, eth_tx_p => tx_p,
eth_tx_n => tx_n, eth_tx_n => tx_n,
psram_ce_n => psram_ce_n, psram_ce_n => psram_ce_n,

View File

@ -11,15 +11,60 @@
library IEEE; library IEEE;
use IEEE.std_logic_1164.all; use IEEE.std_logic_1164.all;
library generics;
use generics.ice40_components.all;
entity pll0 is entity pll0 is
generic(
F_CLK : in integer;
F_CLK_PHY : in integer
);
port( port(
CLKI : in std_logic; clk_in : in std_logic;
CLKOP : out std_logic; clk_out : out std_logic;
LOCK : out std_logic); clk_out_phy : out std_logic;
locked : out std_logic
);
end pll0; end pll0;
architecture Structure of pll0 is architecture Structure of pll0 is
signal clk_int_osc : std_logic;
begin begin
CLKOP <= CLKI; SB_HFOSC_inst : component SB_HFOSC
LOCK <= '1'; generic map(
CLKHF_DIV => "0b01" -- 24 MHz
)
port map(
CLKHFPU => '1',
CLKHFEN => '1',
CLKHF => clk_int_osc
);
-- SB_PLL40_PAD_inst : component SB_PLL40_PAD
-- generic map(
-- FEEDBACK_PATH => "SIMPLE",
-- DIVR => "0000",
-- DIVF => "1000010",
-- DIVQ => "100",
-- FILTER_RANGE => "001"
-- )
-- port map(
-- RESETB => '1',
-- BYPASS => '0',
-- PACKAGEPIN => clk_in,
-- PLLOUTCORE => clk_out_phy
-- );
clk_out_phy <= clk_in;
-- Not clean, but it works...
ckdiv2 : process(clk_out_phy) is
begin
if rising_edge(clk_out_phy) then
clk_out <= not clk_out;
end if;
end process ckdiv2;
assert F_CLK = 25000000 report "clk: PLL generates clock different from specified." severity failure;
assert F_CLK_PHY = 50000000 report "clk_phy: PLL generates clock different from specified." severity failure;
end Structure; end Structure;

View File

@ -15,19 +15,17 @@ use ieee.numeric_std.all;
library generics; library generics;
use generics.all; use generics.all;
use generics.wishbone_pkg.all; use generics.wishbone_pkg.all;
use generics.ice40_components.all;
library trashernet;
use trashernet.all;
entity top is entity top is
generic( generic(
-- System configuration -- System configuration
F_CLK : integer := 12000000; F_CLK : integer := 25000000;
F_CLK_PHY : integer := 48000000; F_CLK_PHY : integer := 50000000;
UART_BAUD : integer := 9600 UART_BAUD : integer := 19200
); );
port( port(
clk_12m : in std_logic; -- System clock clk_50m : in std_logic; -- System clock
-- UART -- UART
uart_tx : out std_logic; -- UART TX uart_tx : out std_logic; -- UART TX
@ -35,44 +33,41 @@ entity top is
-- Trashernet -- Trashernet
eth_rx_p : in std_logic; -- Ethernet RX+ eth_rx_p : in std_logic; -- Ethernet RX+
eth_rx_n : 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_p : out std_logic_vector(3 downto 0); -- Ethernet TX+
eth_tx_n : out std_logic_vector(3 downto 0); -- Ethernet TX- eth_tx_n : out std_logic_vector(3 downto 0); -- Ethernet TX-
-- LEDs -- LEDs
eth_led_green : out std_logic; eth_led_green : out std_logic;
eth_led_orange : out std_logic; eth_led_orange : out std_logic;
led_user : out std_logic; led_user : out std_logic; --
-- PSRAM IF -- PSRAM IF
psram_ce_n : out std_logic; psram_ce_n : out std_logic;
psram_sclk : out std_logic; psram_sclk : out std_logic;
psram_sio : inout std_logic_vector(3 downto 0); psram_sio : inout std_logic_vector(3 downto 0); --
-- Config Flash -- Config Flash
flash_ce_n : out std_logic; flash_ce_n : out std_logic;
flash_sclk : out std_logic; flash_sclk : out std_logic;
flash_sio : inout std_logic_vector(3 downto 0); flash_sio : inout std_logic_vector(3 downto 0); --
-- PMOD -- PMOD
pmod : inout std_logic_vector(7 downto 0) pmod : inout std_logic_vector(7 downto 0)
); );
end entity top; end entity top;
architecture rtl of top is architecture rtl of top is
component pll0
port(
CLKI : in std_logic;
CLKOP : out std_logic;
LOCK : out std_logic
);
end component pll0;
-- System -- System
signal pll_locked : std_logic; signal pll_locked : std_logic;
signal clk : std_logic; signal clk : std_logic;
signal clk_phy : std_logic;
signal rst : std_logic := '1'; -- Asynchronous assert, synchronous release reset signal rst : std_logic := '1'; -- Asynchronous assert, synchronous release reset
signal clr : std_logic := '1'; -- Fully synchronous reset signal clr : std_logic := '1'; -- Fully synchronous reset
signal eth_tx_p_i : std_logic; signal eth_tx_p_i : std_logic;
signal eth_tx_n_i : std_logic; signal eth_tx_n_i : std_logic;
signal eth_rx_p_i : std_logic;
-- System Timer -- System Timer
signal irq_timer : std_logic; signal irq_timer : std_logic;
@ -120,8 +115,26 @@ architecture rtl of top is
or true -- or true --
-- pragma translate_on -- pragma translate_on
; ;
begin begin
SB_IO_inst : component SB_IO
generic map(
PIN_TYPE => "000000",
IO_STANDARD => "SB_LVDS_INPUT"
)
port map(
PACKAGE_PIN => eth_rx_p,
LATCH_INPUT_VALUE => '1',
CLOCK_ENABLE => '1',
INPUT_CLK => clk_phy,
OUTPUT_CLK => clk_phy,
OUTPUT_ENABLE => '0',
D_OUT_0 => '0',
D_OUT_1 => '0',
D_IN_0 => eth_rx_p_i,
D_IN_1 => open
);
clockgen : if IN_SIMULATION generate clockgen : if IN_SIMULATION generate
clock_driver : process clock_driver : process
constant period : time := 1 sec / real(F_CLK); constant period : time := 1 sec / real(F_CLK);
@ -135,21 +148,31 @@ begin
pll_locked <= '1'; pll_locked <= '1';
else generate else generate
pll_inst : pll0 pll_inst : entity work.pll0
generic map(
F_CLK => F_CLK,
F_CLK_PHY => F_CLK_PHY
)
port map( port map(
CLKI => clk_12m, clk_in => clk_50m,
CLKOP => clk, clk_out => clk,
LOCK => pll_locked clk_out_phy => clk_phy,
locked => pll_locked
); );
end generate clockgen; end generate clockgen;
por : process(clk) is por : process(clk) is
variable reset_done : std_logic := '0'; variable reset_cnt : integer range 0 to 255 := 0;
begin begin
if rising_edge(clk) then if rising_edge(clk) then
rst <= not reset_done; if reset_cnt = 255 then
clr <= not reset_done; rst <= '0';
reset_done := '1'; clr <= '0';
else
reset_cnt := reset_cnt + 1;
rst <= '1';
clr <= '1';
end if;
end if; end if;
end process por; end process por;
@ -166,7 +189,7 @@ begin
servant_rom_vhdl_inst : entity work.servant_ram_vhdl servant_rom_vhdl_inst : entity work.servant_ram_vhdl
generic map( generic map(
memfile => "../../sw/bootrom/bootrom.vhex", memfile => "../sw/bootrom/bootrom.vhex",
read_only => true, read_only => true,
adr_width => 9 adr_width => 9
) )
@ -200,7 +223,7 @@ begin
uart_wb_inst : entity work.uart_wb uart_wb_inst : entity work.uart_wb
generic map( generic map(
F_CLK => F_CLK, F_CLK => F_CLK,
BAUD_RATE => 9600 BAUD_RATE => UART_BAUD
) )
port map( port map(
clk => clk, clk => clk,
@ -218,11 +241,11 @@ begin
) )
port map( port map(
clk => clk, clk => clk,
phy_clk => clk, phy_clk => clk_phy,
rst => rst, rst => rst,
wb_o => wb_eth_o, wb_o => wb_eth_o,
wb_i => wb_eth_i, wb_i => wb_eth_i,
rx_p => eth_rx_p, rx_p => eth_rx_p_i,
tx_p => eth_tx_p_i, tx_p => eth_tx_p_i,
tx_n => eth_tx_n_i tx_n => eth_tx_n_i
); );
@ -241,7 +264,13 @@ begin
mask => wishbone_masks mask => wishbone_masks
); );
eth_led_green <= '0'; eth_led_green <= uart_tx;
eth_led_orange <= '1'; eth_led_orange <= uart_rx;
led_user <= '1'; led_user <= not psram_ce_n;
flash_ce_n <= 'Z';
flash_sclk <= 'Z';
flash_sio <= (others => 'Z');
pmod <= (others => 'Z');
end architecture rtl; end architecture rtl;

View File

@ -16,6 +16,7 @@ library trashernet;
use trashernet.trashernet_pkg.all; use trashernet.trashernet_pkg.all;
library generics; library generics;
use generics.all;
use generics.wishbone_pkg.all; use generics.wishbone_pkg.all;
entity trashernet_phy_wb is entity trashernet_phy_wb is
@ -45,9 +46,15 @@ architecture RTL of trashernet_phy_wb is
signal phy_out : phy_out_t; -- PHY application IF (out) signal phy_out : phy_out_t; -- PHY application IF (out)
signal phy_in : phy_in_t; -- PHY application IF (in) signal phy_in : phy_in_t; -- PHY application IF (in)
signal wb_adr : unsigned(2 downto 0); signal wb_adr : unsigned(2 downto 2);
signal status_register : std_logic_vector(31 downto 0); signal status_register : std_logic_vector(31 downto 0);
signal rx_fifo_read : std_logic;
signal rx_fifo_full : std_logic;
signal rx_fifo_empty : std_logic;
signal rx_fifo_data : std_logic_vector(7 downto 0);
signal rx_fifo_usage : integer range 0 to 2047;
begin begin
trashernet_phy_inst : entity trashernet.trashernet_phy_cdc trashernet_phy_inst : entity trashernet.trashernet_phy_cdc
generic map( generic map(
@ -65,22 +72,53 @@ begin
tx_n => tx_n tx_n => tx_n
); );
rx_fifo_inst : entity generics.fifo_block
generic map(
SIZE => 2047
)
port map(
clk => clk,
rst_a => '0',
clr => rst,
data_in => phy_out.rx_data,
write => phy_out.rx_data_valid,
commit => not phy_out.rx_active,
abort => '0',
full => rx_fifo_full,
data_out => rx_fifo_data,
data_first => open,
empty => rx_fifo_empty,
read => rx_fifo_read,
usage => rx_fifo_usage
);
wb_adr <= unsigned(wb_i.adr(wb_adr'range)); wb_adr <= unsigned(wb_i.adr(wb_adr'range));
wbif : process(clk, rst) is wbif : process(clk, rst) is
variable bytes_rxd : unsigned(15 downto 0);
begin begin
if rst then if rst then
wb_o.ack <= '0'; wb_o.ack <= '0';
rx_fifo_read <= '0';
bytes_rxd := (others => '0');
elsif rising_edge(clk) then elsif rising_edge(clk) then
wb_o.ack <= '0'; wb_o.ack <= '0';
rx_fifo_read <= '0';
if (phy_out.rx_data_valid = '1') then
bytes_rxd := bytes_rxd + 1;
end if;
if (wb_i.cyc and wb_i.stb) then if (wb_i.cyc and wb_i.stb) then
wb_o.ack <= '1'; wb_o.ack <= '1';
if wb_adr = 0 then if wb_adr = 0 then
wb_o.dat <= status_register; wb_o.dat <= status_register;
else else
wb_o.dat <= (others => '0'); wb_o.dat <= (others => '0');
wb_o.dat(7 downto 0) <= phy_out.rx_data; -- TODO: data
if wb_o.ack = '0' then
rx_fifo_read <= '1';
end if;
wb_o.dat(7 downto 0) <= rx_fifo_data;
end if; end if;
end if; end if;
end if; end if;
@ -93,5 +131,5 @@ begin
phy_in.tx_data_en <= '0'; phy_in.tx_data_en <= '0';
phy_in.tx_data <= (others => '0'); phy_in.tx_data <= (others => '0');
status_register <= (x"0000000" & "000" & phy_out.carrier_detect); status_register <= (x"0000" & x"000" & "000" & phy_out.carrier_detect);
end architecture RTL; end architecture RTL;

View File

@ -39,7 +39,7 @@ entity fifo_block is
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`. 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 -- FIFO meta
usage : out integer -- Usage counter usage : out integer range 0 to SIZE -- Usage counter
); );
end fifo_block; end fifo_block;
@ -68,6 +68,7 @@ begin
read_pointer_last <= SIZE - 1; read_pointer_last <= SIZE - 1;
write_pointer_committed <= 0; write_pointer_committed <= 0;
current_is_first <= '1'; current_is_first <= '1';
usage <= 0;
elsif rising_edge(clk) then elsif rising_edge(clk) then
succesful_read := read and not empty; succesful_read := read and not empty;
@ -109,6 +110,7 @@ begin
if clr then if clr then
read_pointer <= 0; read_pointer <= 0;
write_pointer <= 0; write_pointer <= 0;
read_pointer_last <= SIZE - 1;
write_pointer_committed <= 0; write_pointer_committed <= 0;
current_is_first <= '1'; current_is_first <= '1';
usage <= 0; usage <= 0;

View File

@ -0,0 +1,88 @@
library ieee;
use ieee.std_logic_1164.all;
package ice40_components is
component SB_PLL40_PAD
generic(
FEEDBACK_PATH : string;
DIVR : std_logic_vector(3 downto 0);
DIVF : std_logic_vector(6 downto 0);
DIVQ : std_logic_vector(2 downto 0);
FILTER_RANGE : std_logic_vector(2 downto 0)
);
port(
RESETB : in std_logic;
BYPASS : in std_logic;
PACKAGEPIN : in std_logic;
PLLOUTCORE : out std_logic
);
end component SB_PLL40_PAD;
component SB_PLL40_CORE
generic(
FEEDBACK_PATH : string := "SIMPLE";
-- DELAY_ADJUSTMENT_MODE_FEEDBACK : string := "FIXED";
-- DELAY_ADJUSTMENT_MODE_RELATIVE : string := "FIXED";
-- PLLOUT_SELECT : string := "GENCLK";
-- SHIFTREG_DIV_MODE : std_logic;
-- FDA_FEEDBACK : std_logic_vector(3 downto 0) := "1111";
-- FDA_RELATIVE : std_logic_vector(3 downto 0) := "1111";
DIVR : std_logic_vector(3 downto 0);
DIVF : std_logic_vector(6 downto 0);
DIVQ : std_logic_vector(2 downto 0);
FILTER_RANGE : std_logic_vector(2 downto 0)
-- ENABLE_ICEGATE : std_logic := '0';
-- TEST_MODE : std_logic := '0'
);
port(
REFERENCECLK : in std_logic;
-- PLLOUTCORE : out std_logic;
PLLOUTGLOBAL : out std_logic;
-- EXTFEEDBACK : in std_logic;
-- DYNAMICDELAY : in std_logic_vector(7 downto 0);
LOCK : out std_logic;
BYPASS : in std_logic;
RESETB : in std_logic
-- LATCHINPUTVALUE : in std_logic;
-- SDO : out std_logic;
-- SDI : in std_logic;
-- SCLK : in std_logic
);
end component SB_PLL40_CORE;
component SB_HFOSC
generic(
CLKHF_DIV : string
);
port(
CLKHFPU : in std_logic;
CLKHFEN : in std_logic;
CLKHF : out std_logic
);
end component SB_HFOSC;
COMPONENT SB_IO IS
GENERIC(
PIN_TYPE : std_logic_vector(5 downto 0) := "000000";
IO_STANDARD : string := "SB_LVDS_INPUT"
);
PORT(
PACKAGE_PIN : in std_logic;
LATCH_INPUT_VALUE : in std_logic;
CLOCK_ENABLE : in std_logic;
INPUT_CLK : in std_logic;
OUTPUT_CLK : in std_logic;
OUTPUT_ENABLE : in std_logic;
D_OUT_0 : in std_logic;
D_OUT_1 : in std_logic;
D_IN_0 : out std_logic;
D_IN_1 : out std_logic
);
END COMPONENT SB_IO;
component SB_GB
port(
USER_SIGNAL_TO_GLOBAL_BUFFER : in std_logic;
GLOBAL_BUFFER_OUTPUT : out std_logic);
end component;
end package ice40_components;

@ -1 +1 @@
Subproject commit da7e329939d12e853acbd7636701350babf5e3f4 Subproject commit 21a0d0e69aeacf9747bfac0262e0d7ca30a691d9