diff --git a/demo/lattice_brevia2/.gitignore b/demo/lattice_brevia2/.gitignore new file mode 100644 index 0000000..0e1701e --- /dev/null +++ b/demo/lattice_brevia2/.gitignore @@ -0,0 +1,7 @@ +impl1/ +*.ccl +.recovery +.run_manager.ini +.setting.ini +.spread_sheet.ini +.spreadsheet_view.ini diff --git a/demo/lattice_brevia2/ip/pll0.vhd b/demo/lattice_brevia2/ip/pll0.vhd new file mode 100644 index 0000000..f06548c --- /dev/null +++ b/demo/lattice_brevia2/ip/pll0.vhd @@ -0,0 +1,112 @@ +-- VHDL netlist generated by SCUBA Diamond (64-bit) 3.12.0.240.2 +-- Module Version: 5.7 +--/usr/local/diamond/3.12/ispfpga/bin/lin64/scuba -w -n pll0 -lang vhdl -synth lse -arch mg5a00 -type pll -fin 50 -phase_cntl STATIC -fclkop 140 -fclkop_tol 0.0 -fb_mode CLOCKTREE -noclkos -noclkok -norst -noclkok2 + +-- Sat Jan 22 20:39:11 2022 + +library IEEE; +use IEEE.std_logic_1164.all; +-- synopsys translate_off +library xp2; +use xp2.components.all; +-- synopsys translate_on + +entity pll0 is + port( + CLK : in std_logic; + CLKOP : out std_logic; + LOCK : out std_logic); +end pll0; + +architecture Structure of pll0 is + + -- internal signal declarations + signal CLKOP_t : std_logic; + signal scuba_vlo : std_logic; + + -- local component declarations + component VLO + port(Z : out std_logic); + end component; + component EPLLD1 + -- synopsys translate_off + generic(CLKOK_BYPASS : in String; CLKOS_BYPASS : in String; + CLKOP_BYPASS : in String; DUTY : in Integer; + PHASEADJ : in String; PHASE_CNTL : in String; + CLKOK_DIV : in Integer; CLKFB_DIV : in Integer; + CLKOP_DIV : in Integer; CLKI_DIV : in Integer); + -- synopsys translate_on + port(CLKI : in std_logic; CLKFB : in std_logic; RST : in std_logic; + RSTK : in std_logic; DPAMODE : in std_logic; DRPAI3 : in std_logic; + DRPAI2 : in std_logic; DRPAI1 : in std_logic; DRPAI0 : in std_logic; + DFPAI3 : in std_logic; DFPAI2 : in std_logic; DFPAI1 : in std_logic; + DFPAI0 : in std_logic; PWD : in std_logic; CLKOP : out std_logic; + CLKOS : out std_logic; CLKOK : out std_logic; LOCK : out std_logic; + CLKINTFB : out std_logic); + end component; + attribute CLKOK_BYPASS : string; + attribute CLKOS_BYPASS : string; + attribute FREQUENCY_PIN_CLKOP : string; + attribute CLKOP_BYPASS : string; + attribute PHASE_CNTL : string; + attribute DUTY : string; + attribute PHASEADJ : string; + attribute FREQUENCY_PIN_CLKI : string; + attribute CLKOK_DIV : string; + attribute CLKOP_DIV : string; + attribute CLKFB_DIV : string; + attribute CLKI_DIV : string; + attribute FIN : string; + attribute CLKOK_BYPASS of PLLInst_0 : label is "DISABLED"; + attribute CLKOS_BYPASS of PLLInst_0 : label is "DISABLED"; + attribute FREQUENCY_PIN_CLKOP of PLLInst_0 : label is "140.000000"; + attribute CLKOP_BYPASS of PLLInst_0 : label is "DISABLED"; + attribute PHASE_CNTL of PLLInst_0 : label is "STATIC"; + attribute DUTY of PLLInst_0 : label is "8"; + attribute PHASEADJ of PLLInst_0 : label is "0.0"; + attribute FREQUENCY_PIN_CLKI of PLLInst_0 : label is "50.000000"; + attribute CLKOK_DIV of PLLInst_0 : label is "2"; + attribute CLKOP_DIV of PLLInst_0 : label is "4"; + attribute CLKFB_DIV of PLLInst_0 : label is "14"; + attribute CLKI_DIV of PLLInst_0 : label is "5"; + attribute FIN of PLLInst_0 : label is "50.000000"; + attribute syn_keep : boolean; + attribute NGD_DRC_MASK : integer; + attribute NGD_DRC_MASK of Structure : architecture is 1; + +begin + -- component instantiation statements + scuba_vlo_inst : VLO + port map(Z => scuba_vlo); + + PLLInst_0 : EPLLD1 + -- synopsys translate_off + generic map(CLKOK_BYPASS => "DISABLED", CLKOS_BYPASS => "DISABLED", + CLKOP_BYPASS => "DISABLED", PHASE_CNTL => "STATIC", DUTY => 8, + PHASEADJ => "0.0", CLKOK_DIV => 2, CLKOP_DIV => 4, CLKFB_DIV => 14, + CLKI_DIV => 5) + -- synopsys translate_on + port map(CLKI => CLK, CLKFB => CLKOP_t, RST => scuba_vlo, + RSTK => scuba_vlo, DPAMODE => scuba_vlo, DRPAI3 => scuba_vlo, + DRPAI2 => scuba_vlo, DRPAI1 => scuba_vlo, DRPAI0 => scuba_vlo, + DFPAI3 => scuba_vlo, DFPAI2 => scuba_vlo, DFPAI1 => scuba_vlo, + DFPAI0 => scuba_vlo, PWD => scuba_vlo, CLKOP => CLKOP_t, + CLKOS => open, CLKOK => open, LOCK => LOCK, CLKINTFB => open); + + CLKOP <= CLKOP_t; +end Structure; + +-- synopsys translate_off +library xp2; +configuration Structure_CON of pll0 is + for Structure + for all : VLO + use entity xp2.VLO(V); + end for; + for all : EPLLD1 + use entity xp2.EPLLD1(V); + end for; + end for; +end Structure_CON; + +-- synopsys translate_on diff --git a/demo/lattice_brevia2/mac_test/mac_test.ldf b/demo/lattice_brevia2/mac_test/mac_test.ldf new file mode 100644 index 0000000..d030f2e --- /dev/null +++ b/demo/lattice_brevia2/mac_test/mac_test.ldf @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/lattice_brevia2/mac_test/mac_test.lpf b/demo/lattice_brevia2/mac_test/mac_test.lpf new file mode 100644 index 0000000..d7a7fb9 --- /dev/null +++ b/demo/lattice_brevia2/mac_test/mac_test.lpf @@ -0,0 +1,47 @@ +BLOCK RESETPATHS ; +BLOCK ASYNCPATHS ; +LOCATE COMP "clk" SITE "21" ; +LOCATE COMP "rst_n" SITE "19" ; +LOCATE COMP "rx_p" SITE "94" ; +LOCATE COMP "led_n[0]" SITE "37" ; +LOCATE COMP "led_n[1]" SITE "38" ; +LOCATE COMP "led_n[2]" SITE "39" ; +LOCATE COMP "led_n[3]" SITE "40" ; +LOCATE COMP "led_n[4]" SITE "43" ; +LOCATE COMP "led_n[5]" SITE "44" ; +LOCATE COMP "led_n[6]" SITE "45" ; +LOCATE COMP "led_n[7]" SITE "46" ; +IOBUF PORT "rx_p" IO_TYPE=LVPECL33 ; +IOBUF PORT "clk" IO_TYPE=LVCMOS33 ; +IOBUF PORT "rst_n" IO_TYPE=LVCMOS33 ; +IOBUF PORT "debug_data[0]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "debug_data[1]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "debug_data[2]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "debug_data[3]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "debug_data[4]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "debug_data[5]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "debug_data[6]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "debug_data[7]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "led_n[0]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "led_n[1]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "led_n[2]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "led_n[3]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "led_n[4]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "led_n[5]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "led_n[6]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "led_n[7]" IO_TYPE=LVCMOS33 ; +IOBUF PORT "tx_n" IO_TYPE=LVCMOS33 ; +IOBUF PORT "tx_p" IO_TYPE=LVCMOS33 ; +LOCATE COMP "tx_n" SITE "114" ; +LOCATE COMP "tx_p" SITE "116" ; +LOCATE COMP "button_n[0]" SITE "54" ; +LOCATE COMP "debug_data[0]" SITE "73" ; +LOCATE COMP "debug_data[1]" SITE "74" ; +LOCATE COMP "debug_data[2]" SITE "77" ; +LOCATE COMP "debug_data[3]" SITE "87" ; +LOCATE COMP "debug_data[4]" SITE "88" ; +LOCATE COMP "debug_data[5]" SITE "89" ; +LOCATE COMP "debug_data[6]" SITE "90" ; +LOCATE COMP "debug_data[7]" SITE "91" ; +BLOCK PATH FROM CLKNET "clk_c" TO CLKNET "clk_phy" ; +BLOCK PATH FROM CLKNET "clk_phy" TO CLKNET "clk_c" ; diff --git a/demo/lattice_brevia2/mac_test/mac_test1.sty b/demo/lattice_brevia2/mac_test/mac_test1.sty new file mode 100644 index 0000000..5fe5de0 --- /dev/null +++ b/demo/lattice_brevia2/mac_test/mac_test1.sty @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/design/ledcon.vhd b/design/ledcon.vhd new file mode 100644 index 0000000..5673199 --- /dev/null +++ b/design/ledcon.vhd @@ -0,0 +1,77 @@ +-- -------------------------------------------------------------------------- -- +-- TRASHERNET - A Trashy Ethernet Stack for FPGAs -- +-- -------------------------------------------------------------------------- -- +-- ledcon.vhd : Simple debug LED helper +-- To blink or not blink. +-- -------------------------------------------------------------------------- -- +-- Author : Markus Koch +-- 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 ledcon is + generic( + F_CLK : integer; + BLINK : boolean_vector + ); + port( + clk : in std_logic; + rst : in std_logic; + sig : in std_logic_vector; + led_n : out std_logic_vector + ); +end entity ledcon; + +architecture RTL of ledcon is + constant MS_CNT_MAX : integer := integer(round(real(F_CLK) * (1.0 * 10.0 ** (-3)))); + signal ms_cnt : integer range 0 to MS_CNT_MAX; + signal ms_tick : std_logic; +begin + mstimer : process(clk, rst) is + begin + if rst then + ms_cnt <= MS_CNT_MAX; + elsif rising_edge(clk) then + if (ms_cnt = 0) then + ms_cnt <= MS_CNT_MAX; + else + ms_cnt <= ms_cnt - 1; + end if; + end if; + end process mstimer; + ms_tick <= '1' when ms_cnt = 0 else '0'; + + ledcongen : for i in sig'low to sig'high generate + ledblock : block + constant LED_CNT_MAX : integer := 50; -- on time, in ms + constant LED_CNT_MIN : integer := -50; -- off time, in ms + signal led_cnt : integer range LED_CNT_MIN to LED_CNT_MAX; + begin + ledgen : if BLINK(i) generate + ledproc : process(clk, rst) is + begin + if rst then + led_cnt <= LED_CNT_MIN; + elsif rising_edge(clk) then + if (led_cnt = LED_CNT_MIN) then + if sig(i) then + led_cnt <= LED_CNT_MAX; + end if; + elsif ms_tick then + led_cnt <= led_cnt - 1; + end if; + end if; + end process ledproc; + led_n(i) <= '0' when led_cnt > 0 else '1'; + else generate + led_n(i) <= not sig(i); + end generate ledgen; + end block ledblock; + end generate ledcongen; + +end architecture RTL; diff --git a/design/top_mac_test.vhd b/design/top_mac_test.vhd new file mode 100644 index 0000000..b1f77ea --- /dev/null +++ b/design/top_mac_test.vhd @@ -0,0 +1,212 @@ +-- -------------------------------------------------------------------------- -- +-- TRASHERNET - A Trashy Ethernet Stack for FPGAs -- +-- -------------------------------------------------------------------------- -- +-- top_mac_test.vhd: Test design to verify the functionality of the MAC core +-- Sends a broadcast with 100 decrementing numbers every 250 ms or when a +-- button is pushed. It will also directly reply with that content to any +-- packet addressed to us. +-- +-- Target: Lattice Brevia 2 (LFXP2-5E) +-- -------------------------------------------------------------------------- -- +-- Author : Markus Koch +-- 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; + +library trashernet; +use trashernet.trashernet_pkg.all; + +entity top_mac_test is + port( + clk : in std_logic; + rst_n : in std_logic; + rx_p : in std_logic; + tx_p : out std_logic; + tx_n : out std_logic; + led_n : out std_logic_vector(7 downto 0); + button_n : in std_logic_vector(3 downto 0); + debug_data : out std_logic_vector(7 downto 0) + ); +end entity top_mac_test; + +architecture rtl of top_mac_test is + component pll0 + port( + CLK : in std_logic; + CLKOP : out std_logic; + LOCK : out std_logic + ); + end component pll0; + + constant F_CLK : integer := 50000000; + constant F_CLK_PHY : integer := 140000000; + + constant LED_BLINK : boolean_vector(led_n'range) := ( + 6 downto 2 => true, + others => false + ); + + constant ETH_CONFIG : configuration_t := ( + mac_address => (x"00", x"ff", x"ff", x"11", x"22", x"33") + ); + + signal rst : std_logic; + signal clk_phy : std_logic; + signal phy_pll_lock : std_logic; + + signal led_sig : std_logic_vector(led_n'range); + + signal phy_out : phy_out_t; + signal phy_in : phy_in_t; + + signal mac_out : mac_out_t; + signal mac_in : mac_in_t; + + type status_t is (IDLE, TX, WAITDONE); + signal state : status_t; + constant BYTE_CNT_MAX : integer := 100; + signal byte_cnt : integer range 0 to BYTE_CNT_MAX; + + signal button_n_sync : std_logic_vector(button_n'range); + signal button : std_logic_vector(button_n'range); + + constant TMO_MAX : integer := integer(round((real(F_CLK) * 0.25))) - 1; + signal tmo : integer range 0 to TMO_MAX; +begin + trashernet_mac_inst : entity trashernet.trashernet_mac + port map( + clk => clk, + rst => rst, + phy_out => phy_out, + phy_in => phy_in, + mac_out => mac_out, + mac_in => mac_in + ); + + pll0_inst : pll0 + port map( + CLK => clk, + CLKOP => clk_phy, + LOCK => phy_pll_lock + ); + + trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc + generic map( + F_CLK => F_CLK, + F_CLK_PHY => F_CLK_PHY + ) + port map( + clk => clk, + phy_clk => clk_phy, + rst => rst, + phy_out => phy_out, + phy_in => phy_in, + rx_p => rx_p, + tx_p => tx_p, + tx_n => tx_n + ); + + reset_sync : process(clk, rst_n) is + begin + if (rst_n = '0') then + rst <= '1'; + elsif (rising_edge(clk)) then + rst <= '0'; + end if; + end process reset_sync; + + ledcon_inst : entity work.ledcon + generic map( + F_CLK => F_CLK, + BLINK => LED_BLINK + ) + port map( + clk => clk, + rst => rst, + sig => led_sig, + led_n => led_n + ); + + led_sig <= ( + 0 => phy_pll_lock, + 1 => phy_out.carrier_detect, + 2 => phy_out.rx_active, + 3 => phy_out.rx_error, + 4 => mac_out.rx_mac_crc_ok, + 5 => mac_out.rx_mac_crc_error, + 6 => mac_out.tx_active, + 7 => '0' + ); + + synchronizer_inst : entity trashernet.synchronizer + generic map( + SIZE => 2 + ) + port map( + clk => clk, + rst => rst, + data_in => button_n(0), + data_out => button_n_sync(0) + ); + + button <= not button_n_sync; + + receiver : process(clk, rst) is + begin + if rst then + state <= IDLE; + mac_in.tx_mac_data_en <= '0'; + tmo <= 0; + elsif rising_edge(clk) then + if (tmo /= 0) then + tmo <= tmo - 1; + end if; + case state is + when IDLE => + if mac_out.rx_mac_crc_ok then + if (mac_out.rx_header.mac_destination = ETH_CONFIG.mac_address) then -- Note: We won't respond to broadcasts! + state <= TX; + byte_cnt <= BYTE_CNT_MAX; + mac_in.tx_header.mac_destination <= mac_out.rx_header.mac_source; + end if; + end if; + + if (tmo = 0) or (button(0) = '1') then + state <= TX; + byte_cnt <= BYTE_CNT_MAX; + mac_in.tx_header.mac_destination <= (others => x"FF"); + end if; + when TX => + tmo <= TMO_MAX; + mac_in.tx_header.mac_ethertype <= (x"00", std_logic_vector(to_unsigned(BYTE_CNT_MAX, 8))); + mac_in.tx_mac_data_en <= '1'; + mac_in.tx_mac_data <= std_logic_vector(to_unsigned(byte_cnt, 8)); + if mac_out.tx_mac_data_ack then + if byte_cnt = 1 then + mac_in.tx_mac_data_en <= '0'; + state <= WAITDONE; + else + byte_cnt <= byte_cnt - 1; + end if; + end if; + when WAITDONE => + if mac_out.tx_active = '0' then + state <= IDLE; + end if; + end case; + + end if; + end process receiver; + + mac_in.tx_header.mac_source <= ETH_CONFIG.mac_address; + + debug_data(0) <= tx_p; + debug_data(1) <= tx_n; + +end architecture rtl;