From dd7cf08b6f8ed3208b8598557a976a3ff5de4938 Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Sat, 6 Jul 2024 19:14:39 +0200 Subject: [PATCH] fpga: Continue work on full HW support --- fpga/build.sh | 19 ++++- fpga/constraints.pcf | 7 +- fpga/hdl/bench/bench_top_manual.vhd | 4 +- fpga/hdl/design/pll0.vhd | 55 ++++++++++++-- fpga/hdl/design/top.vhd | 99 +++++++++++++++++--------- fpga/hdl/design/trashernet_phy_wb.vhd | 50 +++++++++++-- fpga/hdl/generics/fifo_block.vhd | 4 +- fpga/hdl/generics/ice40_components.vhd | 88 +++++++++++++++++++++++ fpga/hdl/trashernet | 2 +- 9 files changed, 274 insertions(+), 54 deletions(-) create mode 100644 fpga/hdl/generics/ice40_components.vhd diff --git a/fpga/build.sh b/fpga/build.sh index 86ee281..935665a 100755 --- a/fpga/build.sh +++ b/fpga/build.sh @@ -1,5 +1,20 @@ #!/bin/bash +# -------------------------------------------------------------------------- -- +# TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs -- +# -------------------------------------------------------------------------- -- +# TODO +# -------------------------------------------------------------------------- -- +# Author : Markus Koch +# 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 cd build @@ -8,7 +23,7 @@ set -e ../run.py --compile BASEDIR=".." -DEVICE=--u4k # --up5k, --u4k +DEVICE=--up5k # --up5k, --u4k PACKAGE=sg48 # Collect pre-analyzed VHDL sources @@ -22,7 +37,7 @@ VLOGS="$VLOGS $SERV/servant/servant_ram.v $SERV/servant/servant_timer.v" # Synthesize and PnR # -device 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 icepack netlist.asc bitstream.bin diff --git a/fpga/constraints.pcf b/fpga/constraints.pcf index 1353d28..04a221b 100644 --- a/fpga/constraints.pcf +++ b/fpga/constraints.pcf @@ -23,9 +23,9 @@ set_io pmod[7] 31 set_io uart_rx 37 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_tx_n[0] 46 @@ -42,3 +42,6 @@ set_io eth_led_green 40 set_io eth_led_orange 41 set_io led_user 34 + +set_frequency clk 24 +set_frequency clk_phy 50 diff --git a/fpga/hdl/bench/bench_top_manual.vhd b/fpga/hdl/bench/bench_top_manual.vhd index 17a7b2e..ad79c92 100644 --- a/fpga/hdl/bench/bench_top_manual.vhd +++ b/fpga/hdl/bench/bench_top_manual.vhd @@ -73,11 +73,11 @@ begin top_inst : entity design.top port map( - clk_12m => clk, + clk_50m => clk, uart_tx => uart_txd, uart_rx => uart_rxd, eth_rx_p => rx_p, - eth_rx_n => rx_n, + --eth_rx_n => rx_n, eth_tx_p => tx_p, eth_tx_n => tx_n, psram_ce_n => psram_ce_n, diff --git a/fpga/hdl/design/pll0.vhd b/fpga/hdl/design/pll0.vhd index dba159e..8f76f7e 100644 --- a/fpga/hdl/design/pll0.vhd +++ b/fpga/hdl/design/pll0.vhd @@ -11,15 +11,60 @@ library IEEE; use IEEE.std_logic_1164.all; +library generics; +use generics.ice40_components.all; + entity pll0 is + generic( + F_CLK : in integer; + F_CLK_PHY : in integer + ); port( - CLKI : in std_logic; - CLKOP : out std_logic; - LOCK : out std_logic); + clk_in : in std_logic; + clk_out : out std_logic; + clk_out_phy : out std_logic; + locked : out std_logic + ); end pll0; architecture Structure of pll0 is + signal clk_int_osc : std_logic; begin - CLKOP <= CLKI; - LOCK <= '1'; + SB_HFOSC_inst : component SB_HFOSC + 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; diff --git a/fpga/hdl/design/top.vhd b/fpga/hdl/design/top.vhd index 515569a..31ebdd6 100644 --- a/fpga/hdl/design/top.vhd +++ b/fpga/hdl/design/top.vhd @@ -15,19 +15,17 @@ use ieee.numeric_std.all; library generics; use generics.all; use generics.wishbone_pkg.all; - -library trashernet; -use trashernet.all; +use generics.ice40_components.all; entity top is generic( -- System configuration - F_CLK : integer := 12000000; - F_CLK_PHY : integer := 48000000; - UART_BAUD : integer := 9600 + F_CLK : integer := 25000000; + F_CLK_PHY : integer := 50000000; + UART_BAUD : integer := 19200 ); port( - clk_12m : in std_logic; -- System clock + clk_50m : in std_logic; -- System clock -- UART uart_tx : out std_logic; -- UART TX @@ -35,44 +33,41 @@ entity top is -- Trashernet 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_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; + 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); + 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); + 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 clk_phy : 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; + signal eth_rx_p_i : std_logic; -- System Timer signal irq_timer : std_logic; @@ -120,8 +115,26 @@ architecture rtl of top is or true -- -- pragma translate_on ; - 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 clock_driver : process constant period : time := 1 sec / real(F_CLK); @@ -135,21 +148,31 @@ begin pll_locked <= '1'; else generate - pll_inst : pll0 + pll_inst : entity work.pll0 + generic map( + F_CLK => F_CLK, + F_CLK_PHY => F_CLK_PHY + ) port map( - CLKI => clk_12m, - CLKOP => clk, - LOCK => pll_locked + clk_in => clk_50m, + clk_out => clk, + clk_out_phy => clk_phy, + locked => pll_locked ); end generate clockgen; por : process(clk) is - variable reset_done : std_logic := '0'; + variable reset_cnt : integer range 0 to 255 := 0; begin if rising_edge(clk) then - rst <= not reset_done; - clr <= not reset_done; - reset_done := '1'; + if reset_cnt = 255 then + rst <= '0'; + clr <= '0'; + else + reset_cnt := reset_cnt + 1; + rst <= '1'; + clr <= '1'; + end if; end if; end process por; @@ -166,7 +189,7 @@ begin servant_rom_vhdl_inst : entity work.servant_ram_vhdl generic map( - memfile => "../../sw/bootrom/bootrom.vhex", + memfile => "../sw/bootrom/bootrom.vhex", read_only => true, adr_width => 9 ) @@ -200,7 +223,7 @@ begin uart_wb_inst : entity work.uart_wb generic map( F_CLK => F_CLK, - BAUD_RATE => 9600 + BAUD_RATE => UART_BAUD ) port map( clk => clk, @@ -218,11 +241,11 @@ begin ) port map( clk => clk, - phy_clk => clk, + phy_clk => clk_phy, rst => rst, wb_o => wb_eth_o, wb_i => wb_eth_i, - rx_p => eth_rx_p, + rx_p => eth_rx_p_i, tx_p => eth_tx_p_i, tx_n => eth_tx_n_i ); @@ -241,7 +264,13 @@ begin mask => wishbone_masks ); - eth_led_green <= '0'; - eth_led_orange <= '1'; - led_user <= '1'; + eth_led_green <= uart_tx; + eth_led_orange <= uart_rx; + led_user <= not psram_ce_n; + + flash_ce_n <= 'Z'; + flash_sclk <= 'Z'; + flash_sio <= (others => 'Z'); + + pmod <= (others => 'Z'); end architecture rtl; diff --git a/fpga/hdl/design/trashernet_phy_wb.vhd b/fpga/hdl/design/trashernet_phy_wb.vhd index 0cbcb9a..73996a3 100644 --- a/fpga/hdl/design/trashernet_phy_wb.vhd +++ b/fpga/hdl/design/trashernet_phy_wb.vhd @@ -16,6 +16,7 @@ library trashernet; use trashernet.trashernet_pkg.all; library generics; +use generics.all; use generics.wishbone_pkg.all; 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_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 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 trashernet_phy_inst : entity trashernet.trashernet_phy_cdc generic map( @@ -65,22 +72,53 @@ begin 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)); wbif : process(clk, rst) is + variable bytes_rxd : unsigned(15 downto 0); begin if rst then - wb_o.ack <= '0'; + wb_o.ack <= '0'; + rx_fifo_read <= '0'; + bytes_rxd := (others => '0'); 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 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 + wb_o.dat <= (others => '0'); + + 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; @@ -93,5 +131,5 @@ begin phy_in.tx_data_en <= '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; diff --git a/fpga/hdl/generics/fifo_block.vhd b/fpga/hdl/generics/fifo_block.vhd index a54e52f..b93e34d 100644 --- a/fpga/hdl/generics/fifo_block.vhd +++ b/fpga/hdl/generics/fifo_block.vhd @@ -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`. -- FIFO meta - usage : out integer -- Usage counter + usage : out integer range 0 to SIZE -- Usage counter ); end fifo_block; @@ -68,6 +68,7 @@ begin read_pointer_last <= SIZE - 1; write_pointer_committed <= 0; current_is_first <= '1'; + usage <= 0; elsif rising_edge(clk) then succesful_read := read and not empty; @@ -109,6 +110,7 @@ begin if clr then read_pointer <= 0; write_pointer <= 0; + read_pointer_last <= SIZE - 1; write_pointer_committed <= 0; current_is_first <= '1'; usage <= 0; diff --git a/fpga/hdl/generics/ice40_components.vhd b/fpga/hdl/generics/ice40_components.vhd new file mode 100644 index 0000000..8367a5f --- /dev/null +++ b/fpga/hdl/generics/ice40_components.vhd @@ -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; diff --git a/fpga/hdl/trashernet b/fpga/hdl/trashernet index da7e329..21a0d0e 160000 --- a/fpga/hdl/trashernet +++ b/fpga/hdl/trashernet @@ -1 +1 @@ -Subproject commit da7e329939d12e853acbd7636701350babf5e3f4 +Subproject commit 21a0d0e69aeacf9747bfac0262e0d7ca30a691d9