├── Readme.md ├── build.sh ├── clash └── kvs.hs ├── fpga ├── compile.tcl └── src │ ├── arty.xdc │ ├── rx_mac.v │ ├── top.v │ └── tx_mac.v ├── setup_net.sh └── software ├── Makefile └── test.hs /Readme.md: -------------------------------------------------------------------------------- 1 | # FPGA key-value store 2 | 3 | An FPGA based networked key-value store. Responds to requests to lookup/insert/delete key-value pairs via a simple UDP based protocol. 4 | 5 | See the [blog post](https://adamwalker.github.io/Building-FPGA-KVS/) 6 | 7 | Implemented in [Clash](https://clash-lang.org/). 8 | 9 | Runs on the [Arty board](https://store.digilentinc.com/arty-a7-artix-7-fpga-development-board-for-makers-and-hobbyists/). 10 | 11 | An improved version of this hashtable can be found [here](https://github.com/adamwalker/fpga-hashmap). 12 | 13 | ## Build 14 | 15 | Make sure Vivado is in your path, then 16 | 17 | ``` 18 | $ ./build.sh 19 | ``` 20 | 21 | ## Setup 22 | 23 | Program the image onto the FPGA using the Vivado hardware manager, then 24 | 25 | ``` 26 | $ sudo ./setup_net.sh 27 | ``` 28 | 29 | ## Test 30 | 31 | ``` 32 | $ cd test 33 | $ make 34 | $ ./test 35 | ``` 36 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | pushd clash 5 | stack exec clash -- --verilog kvs.hs 6 | popd 7 | mkdir -p fpga/src/generated 8 | cp clash/verilog/Main.topEntity/* fpga/src/generated 9 | pushd fpga 10 | vivado -mode batch -nojournal -source compile.tcl 11 | 12 | -------------------------------------------------------------------------------- /clash/kvs.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric, RecordWildCards #-} 2 | import Clash.Prelude 3 | import qualified Prelude 4 | 5 | import Data.Maybe 6 | 7 | import Clash.Container.CuckooPipeline 8 | import Clash.Container.FIFO 9 | import Clash.ErrorControl.CRC 10 | import Clash.Misc 11 | import Clash.Network.Types 12 | import Clash.Stream.Packet 13 | import Clash.Stream.Resize 14 | 15 | networkHeaders :: Vec 84 (BitVector 4) 16 | networkHeaders = concatMap func $ bitCoerce (ethernetHeader, ipHeader, udpHeader) 17 | where 18 | func :: BitVector 8 -> Vec 2 (BitVector 4) 19 | func = reverse . unpack 20 | 21 | ethernetHeader = EthernetHeader { 22 | destMac = repeat 0xff, 23 | sourceMac = 0x12 :> 0x34 :> 0x56 :> 0x78 :> 0x90 :> 0xab :> Nil, 24 | etherType = 0x0800 25 | } 26 | 27 | ipHeader = IPv4Header { 28 | version = 4, 29 | ihl = 5, 30 | dscp = 0, 31 | ecn = 0, 32 | ipLen = 0x002c, 33 | identification = 0, 34 | flags = 0, 35 | fragmentOffset = 0, 36 | ttl = 0x80, 37 | protocol = 0x11, 38 | headerChecksum = 0xaf6d, 39 | sourceIP = 192 :> 168 :> 5 :> 2 :> Nil, 40 | destIP = 192 :> 168 :> 5 :> 1 :> Nil 41 | } 42 | 43 | udpHeader = UDPHeader { 44 | sourcePort = 0x1234, 45 | destPort = 0x1234, 46 | udpLen = 0x0018, 47 | udpChecksum = 0x0 48 | } 49 | 50 | hashtable 51 | :: HiddenClockResetEnable dom 52 | => Signal dom (BitVector 64) 53 | -> Signal dom (Maybe (Maybe (BitVector 64))) 54 | -> ( 55 | Signal dom (Maybe (BitVector 64)), 56 | Signal dom Bool 57 | ) 58 | hashtable lu cmd = cuckooPipelineInsert (SNat @ 0) hashFunctions lu cmd 59 | where 60 | hashFunctions 61 | = (\x -> unpack (crc0 x)) 62 | :> (\x -> unpack (crc1 x)) 63 | :> (\x -> unpack (crc2 x)) 64 | :> (\x -> unpack (crc3 x)) 65 | :> Nil 66 | where 67 | table0 = $(lift $ (makeCRCTable (pack . crcSteps 0x5db (repeat 0)) :: Vec 64 (BitVector 11))) 68 | crc0 = crcTable table0 69 | table1 = $(lift $ (makeCRCTable (pack . crcSteps 0x64d (repeat 0)) :: Vec 64 (BitVector 11))) 70 | crc1 = crcTable table1 71 | table2 = $(lift $ (makeCRCTable (pack . crcSteps 0x62b (repeat 0)) :: Vec 64 (BitVector 11))) 72 | crc2 = crcTable table2 73 | table3 = $(lift $ (makeCRCTable (pack . crcSteps 0x473 (repeat 0)) :: Vec 64 (BitVector 11))) 74 | crc3 = crcTable table3 75 | 76 | data Command = Command { 77 | command :: BitVector 32, 78 | commandKey :: BitVector 64, 79 | commandValue :: BitVector 64 80 | } deriving (Generic, NFDataX, Eq, BitPack) 81 | 82 | decodeComand :: Command -> (Bool, BitVector 64, Maybe (Maybe (BitVector 64))) 83 | decodeComand Command{..} 84 | | command == 0 = (True, commandKey, Nothing) 85 | | command == 1 = (False, commandKey, Just (Just commandValue)) 86 | | command == 2 = (False, commandKey, Just Nothing) 87 | | otherwise = (False, commandKey, Nothing) 88 | 89 | topEntity' 90 | :: forall dom 91 | . HiddenClockResetEnable dom 92 | => Signal dom Bool 93 | -> Signal dom Bool 94 | -> Signal dom (BitVector 4) 95 | -> Signal dom Bool 96 | -> ( 97 | Signal dom Bool, 98 | Signal dom Bool, 99 | Signal dom (BitVector 4) 100 | ) 101 | topEntity' vld eof dat ready = unbundle headeredStream 102 | where 103 | noHeaderStream = dropStream (SNat @ 84) $ bundle (vld, eof, dat) 104 | (wideVld, _, wideDat) = unbundle $ fst $ widenStream noHeaderStream (pure True) 105 | 106 | (bufferedDat, bufferedFull, _, _) = blockRamFIFO (SNat @ 10) (not <$> busy) wideDat wideVld 107 | 108 | bufferedVld = not <$> bufferedFull 109 | 110 | cmd :: Signal dom Command 111 | cmd = bitCoerce . swapNibbles <$> bufferedDat 112 | 113 | (lookup, key, cmd') = unbundle $ decodeComand <$> cmd 114 | 115 | (result, busy) = hashtable key $ mux bufferedVld cmd' (pure Nothing) 116 | 117 | nextCycle = register False (lookup .&&. bufferedVld) 118 | 119 | packResult :: Maybe (BitVector 64) -> BitVector 176 120 | packResult x = pack . swapNibbles . (unpack :: BitVector 176 -> Vec 44 (BitVector 4)) $ (0 :: BitVector 31) ++# pack x ++# (0 :: BitVector 80) 121 | 122 | bufferedStream = packetize @8 (pure 0) (bundle (nextCycle, unpack . packResult <$> result)) narrowedReady 123 | (narrowedStream, narrowedReady) = narrowStream bufferedStream headeredReady 124 | (headeredStream, headeredReady) = prependHeader (pure networkHeaders) narrowedStream ready 125 | 126 | {-# ANN topEntity 127 | (Synthesize 128 | { t_name = "kvs" 129 | , t_inputs = [ 130 | PortName "clk", 131 | PortName "rst", 132 | PortName "clkEn", 133 | PortName "iVld", 134 | PortName "iEof", 135 | PortName "iDat", 136 | PortName "iReady" 137 | ] 138 | , t_output = PortProduct "" [ 139 | PortName "oVld", 140 | PortName "oEof", 141 | PortName "oDat" 142 | ] 143 | }) #-} 144 | topEntity = exposeClockResetEnable @System topEntity' 145 | 146 | -------------------------------------------------------------------------------- /fpga/compile.tcl: -------------------------------------------------------------------------------- 1 | #Compile TCL script for Arty project template 2 | #Configure the VIO input/output ports in the "Generate the VIO IP" section 3 | #Configure the ILA clock in the "Insert the ILA" section 4 | 5 | #Outputs go in outputs directory 6 | set ::output_dir "./outputs" 7 | file mkdir $::output_dir 8 | 9 | #Generate the VIO IP 10 | file mkdir ip 11 | create_project ip_project -in_memory -part xc7a35ticsg324-1L -ip 12 | create_ip -name vio -vendor xilinx.com -library ip -version 3.0 -module_name vio_0 -dir ip -force 13 | 14 | set_property -dict \ 15 | [list \ 16 | CONFIG.C_PROBE_OUT0_WIDTH {64} \ 17 | CONFIG.C_PROBE_OUT1_WIDTH {64} \ 18 | CONFIG.C_PROBE_OUT2_WIDTH {64} \ 19 | CONFIG.C_PROBE_OUT3_WIDTH {64} \ 20 | CONFIG.C_PROBE_IN0_WIDTH {64} \ 21 | CONFIG.C_PROBE_IN1_WIDTH {64} \ 22 | CONFIG.C_PROBE_IN2_WIDTH {64} \ 23 | CONFIG.C_PROBE_IN3_WIDTH {64} \ 24 | CONFIG.C_NUM_PROBE_OUT {4} \ 25 | CONFIG.C_NUM_PROBE_IN {4} \ 26 | ] \ 27 | [get_ips vio_0] 28 | 29 | generate_target {instantiation_template} [get_files vio_0.xci] 30 | generate_target all [get_files vio_0.xci] 31 | 32 | close_project 33 | 34 | #Create the project 35 | create_project -part xc7a35ticsg324-1l -in_memory 36 | 37 | #Read the sources 38 | read_ip -verbose ip/vio_0/vio_0.xci 39 | read_verilog -quiet [glob -nocomplain -directory src *.v] 40 | read_vhdl -quiet [glob -nocomplain -directory src *.vhdl] 41 | read_verilog -quiet [glob -nocomplain -directory src/generated *.v] 42 | read_vhdl -quiet [glob -nocomplain -directory src/generated *.vhdl] 43 | read_xdc src/arty.xdc 44 | 45 | #Enable xilinx XPM modules 46 | auto_detect_xpm 47 | 48 | #Do the IP dance 49 | upgrade_ip [get_ips] 50 | set_property generate_synth_checkpoint false [get_files ip/vio_0/vio_0.xci] 51 | generate_target all [get_ips] 52 | validate_ip -verbose [get_ips] 53 | 54 | #Synthesize the design 55 | synth_design -top top -flatten_hierarchy rebuilt 56 | write_checkpoint -force "${::output_dir}/post_synth.dcp" 57 | 58 | #Insert the ILA 59 | #See the section "Using XDC Commands to Insert Debug Cores" in UG908 60 | set debug_nets [lsort -dictionary [get_nets -hier -filter {mark_debug}]] 61 | set n_nets [llength $debug_nets] 62 | 63 | if { $n_nets > 0 } { 64 | create_debug_core u_ila_0 ila 65 | 66 | set_property C_DATA_DEPTH 1024 [get_debug_cores u_ila_0] 67 | set_property C_TRIGIN_EN false [get_debug_cores u_ila_0] 68 | set_property C_TRIGOUT_EN false [get_debug_cores u_ila_0] 69 | set_property C_ADV_TRIGGER false [get_debug_cores u_ila_0] 70 | set_property C_INPUT_PIPE_STAGES 0 [get_debug_cores u_ila_0] 71 | set_property C_EN_STRG_QUAL false [get_debug_cores u_ila_0] 72 | set_property ALL_PROBE_SAME_MU true [get_debug_cores u_ila_0] 73 | set_property ALL_PROBE_SAME_MU_CNT 1 [get_debug_cores u_ila_0] 74 | 75 | set_property port_width 1 [get_debug_ports u_ila_0/clk] 76 | connect_debug_port u_ila_0/clk [get_nets eth_tx_clk_i] 77 | 78 | set_property port_width $n_nets [get_debug_ports u_ila_0/probe0] 79 | connect_debug_port u_ila_0/probe0 $debug_nets 80 | } 81 | 82 | #Continue with implementation 83 | opt_design 84 | write_checkpoint -force "${::output_dir}/post_opt.dcp" 85 | 86 | place_design -directive Explore 87 | write_checkpoint -force "${::output_dir}/post_place.dcp" 88 | 89 | phys_opt_design -directive AggressiveExplore 90 | write_checkpoint -force "${::output_dir}/post_phys_opt.dcp" 91 | 92 | route_design -directive Explore -tns_cleanup 93 | write_checkpoint -force "${::output_dir}/post_route.dcp" 94 | 95 | phys_opt_design -directive Explore 96 | write_checkpoint -force "${::output_dir}/post_route_phys_opt.dcp" 97 | 98 | #Reports 99 | report_clocks -file "${::output_dir}/clocks.rpt" 100 | report_timing_summary -file "${::output_dir}/timing.rpt" 101 | report_utilization -file "${::output_dir}/utilization.rpt" 102 | 103 | #Outputs 104 | write_bitstream "${::output_dir}/arty.bit" -force 105 | write_debug_probes "${::output_dir}/arty.ltx" -force 106 | 107 | -------------------------------------------------------------------------------- /fpga/src/arty.xdc: -------------------------------------------------------------------------------- 1 | # Clock signal 2 | set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk_100 }]; #IO_L12P_T1_MRCC_35 Sch=gclk[100] 3 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { clk_100 }]; 4 | 5 | # Switches 6 | set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L12N_T1_MRCC_16 Sch=sw[0] 7 | set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L13P_T2_MRCC_16 Sch=sw[1] 8 | set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2] 9 | set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3] 10 | 11 | # RGB LEDs 12 | set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led_b[0] }]; #IO_L18N_T2_35 Sch=led0_b 13 | set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led_g[0] }]; #IO_L19N_T3_VREF_35 Sch=led0_g 14 | set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led_r[0] }]; #IO_L19P_T3_35 Sch=led0_r 15 | set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led_b[1] }]; #IO_L20P_T3_35 Sch=led1_b 16 | set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led_g[1] }]; #IO_L21P_T3_DQS_35 Sch=led1_g 17 | set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led_r[1] }]; #IO_L20N_T3_35 Sch=led1_r 18 | set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led_b[2] }]; #IO_L21N_T3_DQS_35 Sch=led2_b 19 | set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led_g[2] }]; #IO_L22N_T3_35 Sch=led2_g 20 | set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led_r[2] }]; #IO_L22P_T3_35 Sch=led2_r 21 | set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led_b[3] }]; #IO_L23P_T3_35 Sch=led3_b 22 | set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led_g[3] }]; #IO_L24P_T3_35 Sch=led3_g 23 | set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led_r[3] }]; #IO_L23N_T3_35 Sch=led3_r 24 | 25 | # LEDs 26 | set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L24N_T3_35 Sch=led[4] 27 | set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_25_35 Sch=led[5] 28 | set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L24P_T3_A01_D17_14 Sch=led[6] 29 | set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L24N_T3_A00_D16_14 Sch=led[7] 30 | 31 | # Buttons 32 | set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }]; #IO_L6N_T0_VREF_16 Sch=btn[0] 33 | set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }]; #IO_L11P_T1_SRCC_16 Sch=btn[1] 34 | set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L11N_T1_SRCC_16 Sch=btn[2] 35 | set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L12P_T1_MRCC_16 Sch=btn[3] 36 | 37 | ## Pmod Header JA 38 | #set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_0_15 Sch=ja[1] 39 | #set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L4P_T0_15 Sch=ja[2] 40 | #set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L4N_T0_15 Sch=ja[3] 41 | #set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L6P_T0_15 Sch=ja[4] 42 | #set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L6N_T0_VREF_15 Sch=ja[7] 43 | #set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L10P_T1_AD11P_15 Sch=ja[8] 44 | #set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L10N_T1_AD11N_15 Sch=ja[9] 45 | #set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_25_15 Sch=ja[10] 46 | 47 | ## Pmod Header JB 48 | #set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L11P_T1_SRCC_15 Sch=jb_p[1] 49 | #set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L11N_T1_SRCC_15 Sch=jb_n[1] 50 | #set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L12P_T1_MRCC_15 Sch=jb_p[2] 51 | #set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L12N_T1_MRCC_15 Sch=jb_n[2] 52 | #set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L23P_T3_FOE_B_15 Sch=jb_p[3] 53 | #set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L23N_T3_FWE_B_15 Sch=jb_n[3] 54 | #set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L24P_T3_RS1_15 Sch=jb_p[4] 55 | #set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L24N_T3_RS0_15 Sch=jb_n[4] 56 | 57 | ## Pmod Header JC 58 | #set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L20P_T3_A08_D24_14 Sch=jc_p[1] 59 | #set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L20N_T3_A07_D23_14 Sch=jc_n[1] 60 | #set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L21P_T3_DQS_14 Sch=jc_p[2] 61 | #set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=jc_n[2] 62 | #set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L22P_T3_A05_D21_14 Sch=jc_p[3] 63 | #set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22N_T3_A04_D20_14 Sch=jc_n[3] 64 | #set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L23P_T3_A03_D19_14 Sch=jc_p[4] 65 | #set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L23N_T3_A02_D18_14 Sch=jc_n[4] 66 | 67 | ## Pmod Header JD 68 | #set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L11N_T1_SRCC_35 Sch=jd[1] 69 | #set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L12N_T1_MRCC_35 Sch=jd[2] 70 | #set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L13P_T2_MRCC_35 Sch=jd[3] 71 | #set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L13N_T2_MRCC_35 Sch=jd[4] 72 | #set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L14P_T2_SRCC_35 Sch=jd[7] 73 | #set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L14N_T2_SRCC_35 Sch=jd[8] 74 | #set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15P_T2_DQS_35 Sch=jd[9] 75 | #set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L15N_T2_DQS_35 Sch=jd[10] 76 | 77 | ## USB-UART Interface 78 | #set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L19N_T3_VREF_16 Sch=uart_rxd_out 79 | #set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L14N_T2_SRCC_16 Sch=uart_txd_in 80 | 81 | ## ChipKit Outer Digital Header 82 | #set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io0 }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0] 83 | #set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { ck_io1 }]; #IO_L18P_T2_A12_D28_14 Sch=ck_io[1] 84 | #set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { ck_io2 }]; #IO_L8N_T1_D12_14 Sch=ck_io[2] 85 | #set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { ck_io3 }]; #IO_L19P_T3_A10_D26_14 Sch=ck_io[3] 86 | #set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { ck_io4 }]; #IO_L5P_T0_D06_14 Sch=ck_io[4] 87 | #set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io5 }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5] 88 | #set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io6 }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6] 89 | #set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io7 }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7] 90 | #set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { ck_io8 }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8] 91 | #set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { ck_io9 }]; #IO_L10P_T1_D14_14 Sch=ck_io[9] 92 | #set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io10 }]; #IO_L18N_T2_A11_D27_14 Sch=ck_io[10] 93 | #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ck_io11 }]; #IO_L17N_T2_A13_D29_14 Sch=ck_io[11] 94 | #set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io12 }]; #IO_L12N_T1_MRCC_14 Sch=ck_io[12] 95 | #set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { ck_io13 }]; #IO_L12P_T1_MRCC_14 Sch=ck_io[13] 96 | 97 | ## ChipKit Inner Digital Header 98 | #set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { ck_io26 }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=ck_io[26] 99 | #set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { ck_io27 }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[27] 100 | #set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { ck_io28 }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[28] 101 | #set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { ck_io29 }]; #IO_25_14 Sch=ck_io[29] 102 | #set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { ck_io30 }]; #IO_0_14 Sch=ck_io[30] 103 | #set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { ck_io31 }]; #IO_L5N_T0_D07_14 Sch=ck_io[31] 104 | #set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { ck_io32 }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[32] 105 | #set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_io33 }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[33] 106 | #set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io34 }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=ck_io[34] 107 | #set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { ck_io35 }]; #IO_L11N_T1_SRCC_14 Sch=ck_io[35] 108 | #set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { ck_io36 }]; #IO_L8P_T1_D11_14 Sch=ck_io[36] 109 | #set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io37 }]; #IO_L17P_T2_A14_D30_14 Sch=ck_io[37] 110 | #set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { ck_io38 }]; #IO_L7N_T1_D10_14 Sch=ck_io[38] 111 | #set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { ck_io39 }]; #IO_L7P_T1_D09_14 Sch=ck_io[39] 112 | #set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io40 }]; #IO_L9N_T1_DQS_D13_14 Sch=ck_io[40] 113 | #set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io41 }]; #IO_L9P_T1_DQS_14 Sch=ck_io[41] 114 | 115 | ## ChipKit Outer Analog Header - as Single-Ended Analog Inputs 116 | ## NOTE: These ports can be used as single-ended analog inputs with voltages from 0-3.3V (ChipKit analog pins A0-A5) or as digital I/O. 117 | ## WARNING: Do not use both sets of constraints at the same time! 118 | ## NOTE: The following constraints should be used with the XADC IP core when using these ports as analog inputs. 119 | #set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vaux4_n }]; #IO_L1N_T0_AD4N_35 Sch=ck_an_n[0] ChipKit pin=A0 120 | #set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vaux4_p }]; #IO_L1P_T0_AD4P_35 Sch=ck_an_p[0] ChipKit pin=A0 121 | #set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vaux5_n }]; #IO_L3N_T0_DQS_AD5N_35 Sch=ck_an_n[1] ChipKit pin=A1 122 | #set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vaux5_p }]; #IO_L3P_T0_DQS_AD5P_35 Sch=ck_an_p[1] ChipKit pin=A1 123 | #set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_n }]; #IO_L7N_T1_AD6N_35 Sch=ck_an_n[2] ChipKit pin=A2 124 | #set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_p }]; #IO_L7P_T1_AD6P_35 Sch=ck_an_p[2] ChipKit pin=A2 125 | #set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_n }]; #IO_L9N_T1_DQS_AD7N_35 Sch=ck_an_n[3] ChipKit pin=A3 126 | #set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_p }]; #IO_L9P_T1_DQS_AD7P_35 Sch=ck_an_p[3] ChipKit pin=A3 127 | #set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { vaux15_n }]; #IO_L10N_T1_AD15N_35 Sch=ck_an_n[4] ChipKit pin=A4 128 | #set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { vaux15_p }]; #IO_L10P_T1_AD15P_35 Sch=ck_an_p[4] ChipKit pin=A4 129 | #set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_n }]; #IO_L1N_T0_AD0N_15 Sch=ck_an_n[5] ChipKit pin=A5 130 | #set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_p }]; #IO_L1P_T0_AD0P_15 Sch=ck_an_p[5] ChipKit pin=A5 131 | ## ChipKit Outer Analog Header - as Digital I/O 132 | ## NOTE: the following constraints should be used when using these ports as digital I/O. 133 | #set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { ck_a0 }]; #IO_0_35 Sch=ck_a[0] ChipKit pin=A0 134 | #set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { ck_a1 }]; #IO_L4P_T0_35 Sch=ck_a[1] ChipKit pin=A1 135 | #set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { ck_a2 }]; #IO_L4N_T0_35 Sch=ck_a[2] ChipKit pin=A2 136 | #set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { ck_a3 }]; #IO_L6P_T0_35 Sch=ck_a[3] ChipKit pin=A3 137 | #set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { ck_a4 }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4] ChipKit pin=A4 138 | #set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ck_a5 }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5] ChipKit pin=A5 139 | 140 | ## ChipKit Inner Analog Header - as Differential Analog Inputs 141 | ## NOTE: These ports can be used as differential analog inputs with voltages from 0-1.0V (ChipKit Analog pins A6-A11) or as digital I/O. 142 | ## WARNING: Do not use both sets of constraints at the same time! 143 | ## NOTE: The following constraints should be used with the XADC core when using these ports as analog inputs. 144 | #set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vaux12_p }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6 145 | #set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vaux12_n }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7 146 | #set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { vaux13_p }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8 147 | #set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { vaux13_n }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9 148 | #set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vaux14_p }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10 149 | #set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vaux14_n }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11 150 | ## ChipKit Inner Analog Header - as Digital I/O 151 | ## NOTE: the following constraints should be used when using the inner analog header ports as digital I/O. 152 | #set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { ck_io20 }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6 153 | #set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { ck_io21 }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7 154 | #set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { ck_io22 }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8 155 | #set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { ck_io23 }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9 156 | #set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { ck_io24 }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10 157 | #set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { ck_io25 }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11 158 | 159 | ## ChipKit SPI 160 | #set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso 161 | #set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi 162 | #set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck 163 | #set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss 164 | 165 | ## ChipKit I2C 166 | #set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl 167 | #set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda 168 | #set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15 Sch=scl_pup 169 | #set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15 Sch=sda_pup 170 | 171 | ## Misc. ChipKit Ports 172 | #set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa 173 | #set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { ck_rst }]; #IO_L16P_T2_35 Sch=ck_rst 174 | 175 | # SMSC Ethernet PHY 176 | set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col 177 | set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=eth_crs 178 | set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L14N_T2_SRCC_15 Sch=eth_mdc 179 | set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L17P_T2_A26_15 Sch=eth_mdio 180 | set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { eth_ref_clk }]; #IO_L22P_T3_A17_15 Sch=eth_ref_clk 181 | set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L20P_T3_A20_15 Sch=eth_rstn 182 | set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_clk }]; #IO_L14P_T2_SRCC_15 Sch=eth_rx_clk 183 | set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_dv }]; #IO_L13N_T2_MRCC_15 Sch=eth_rx_dv 184 | set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L21N_T3_DQS_A18_15 Sch=eth_rxd[0] 185 | set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L16P_T2_A28_15 Sch=eth_rxd[1] 186 | set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[2] }]; #IO_L21P_T3_DQS_15 Sch=eth_rxd[2] 187 | set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[3] }]; #IO_L18N_T2_A23_15 Sch=eth_rxd[3] 188 | set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L20N_T3_A19_15 Sch=eth_rxerr 189 | set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_clk }]; #IO_L13P_T2_MRCC_15 Sch=eth_tx_clk 190 | set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_en }]; #IO_L19N_T3_A21_VREF_15 Sch=eth_tx_en 191 | set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L15P_T2_DQS_15 Sch=eth_txd[0] 192 | set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L19P_T3_A22_15 Sch=eth_txd[1] 193 | set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[2] }]; #IO_L17N_T2_A25_15 Sch=eth_txd[2] 194 | set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[3] }]; #IO_L18P_T2_A24_15 Sch=eth_txd[3] 195 | 196 | create_clock -add -name eth_tx_clk -period 40.00 [get_ports { eth_tx_clk }]; 197 | create_clock -add -name eth_rx_clk -period 40.00 [get_ports { eth_rx_clk }]; 198 | 199 | ## Quad SPI Flash 200 | #set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs 201 | #set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] 202 | #set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] 203 | #set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] 204 | #set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] 205 | 206 | ## Power Measurements 207 | #set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15 Sch=ad_n[2] 208 | #set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15 Sch=ad_p[2] 209 | #set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15 Sch=ad_n[1] 210 | #set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15 Sch=ad_p[1] 211 | #set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15 Sch=ad_n[9] 212 | #set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15 Sch=ad_p[9] 213 | #set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15 Sch=ad_n[10] 214 | #set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15 Sch=ad_p[10] 215 | 216 | -------------------------------------------------------------------------------- /fpga/src/rx_mac.v: -------------------------------------------------------------------------------- 1 | //100M MII Ethernet RX module 2 | //Very minimal. Only strips the preamble. No error checking. 3 | module rx_mac ( 4 | 5 | input clk_rx, 6 | 7 | //User interface signals 8 | output rx_vld, 9 | output rx_eof, 10 | output [3:0] rx_dat, 11 | 12 | //MII phy signals 13 | input mii_rx_dv, 14 | input [3:0] mii_rxd 15 | ); 16 | 17 | //Strip the preamble 18 | reg [4:0] packet_cnt = 0; 19 | 20 | always @(posedge clk_rx) 21 | if (!mii_rx_dv) 22 | packet_cnt <= 0; 23 | else if (packet_cnt < 25) 24 | packet_cnt <= packet_cnt + 1; 25 | 26 | //Strip the FCS 27 | reg [35:0] data_shift = 0; 28 | 29 | always @(posedge clk_rx) 30 | data_shift <= {data_shift[31:0], mii_rxd}; 31 | 32 | //Assign the outputs 33 | assign rx_vld = packet_cnt == 25; 34 | assign rx_dat = data_shift[35:32]; 35 | assign rx_eof = !mii_rx_dv; 36 | 37 | endmodule 38 | -------------------------------------------------------------------------------- /fpga/src/top.v: -------------------------------------------------------------------------------- 1 | module top ( 2 | //System clock 3 | input clk_100, 4 | 5 | //GPIO 6 | input [3:0] sw, 7 | input [3:0] btn, 8 | 9 | output [3:0] led_b, 10 | output [3:0] led_g, 11 | output [3:0] led_r, 12 | 13 | output [3:0] led, 14 | 15 | //Ethernet 16 | output eth_mdc, 17 | inout eth_mdio, 18 | 19 | output eth_ref_clk, 20 | output eth_rstn, 21 | 22 | input eth_rx_clk, 23 | input eth_col, 24 | input eth_crs, 25 | input eth_rx_dv, 26 | input [3:0] eth_rxd, 27 | input eth_rxerr, 28 | 29 | input eth_tx_clk, 30 | output eth_tx_en, 31 | output [3:0] eth_txd 32 | 33 | ); 34 | 35 | ////////////////////////////////////////////////////////////////// 36 | //Main clock buffer 37 | ////////////////////////////////////////////////////////////////// 38 | 39 | (* keep = "true" *) wire clk_100_i; 40 | 41 | //This buffer is necessary to prevent Vivado from shitting itself if you use 42 | //clk_100 as the debug clk for an ILA (which can be set in compile.tcl). If 43 | //you are using a different clock, or not using the ILA at all, this can be 44 | //safely removed. 45 | BUFG BUFG_inst_clk_100( 46 | .I(clk_100), 47 | .O(clk_100_i) 48 | ); 49 | 50 | ////////////////////////////////////////////////////////////////// 51 | //Ethernet 52 | ////////////////////////////////////////////////////////////////// 53 | 54 | (* keep = "true" *) wire eth_rx_clk_i; 55 | (* keep = "true" *) wire eth_tx_clk_i; 56 | 57 | //Ethernet clock buffers 58 | BUFG BUFG_inst_eth_tx( 59 | .I(eth_tx_clk), 60 | .O(eth_tx_clk_i) 61 | ); 62 | 63 | BUFG BUFG_inst_eth_rx( 64 | .I(eth_rx_clk), 65 | .O(eth_rx_clk_i) 66 | ); 67 | 68 | assign eth_rstn = 1'b1; 69 | 70 | wire clkfbin; 71 | wire clkfbout; 72 | wire locked; 73 | wire ref_clk; 74 | 75 | BUFG clkfb_buf ( 76 | .O (clkfbin), 77 | .I (clkfbout) 78 | ); 79 | 80 | //Generate the reference clock needed by the external Ethernet phy 81 | MMCME2_BASE #( 82 | .CLKFBOUT_MULT_F (8), 83 | .DIVCLK_DIVIDE (1), 84 | .CLKOUT0_DIVIDE_F (32), 85 | .CLKOUT0_PHASE (0.000), 86 | .CLKIN1_PERIOD (10.000) 87 | ) mmcme2_clk_tx_inst ( 88 | .CLKIN1 (clk_100_i), 89 | .RST (1'b0), 90 | .PWRDWN (1'b0), 91 | 92 | .CLKOUT0 (ref_clk), 93 | 94 | .CLKFBOUT (clkfbout), 95 | .CLKFBIN (clkfbin), 96 | 97 | .LOCKED (locked) 98 | ); 99 | 100 | BUFGCE clk_net_buf ( 101 | .CE (locked), 102 | .I (ref_clk), 103 | .O (eth_ref_clk) 104 | ); 105 | 106 | (* dont_touch = "true" *)(* mark_debug = "true" *)wire tx_vld; 107 | (* dont_touch = "true" *)(* mark_debug = "true" *)wire [3:0] tx_dat; 108 | (* dont_touch = "true" *)(* mark_debug = "true" *)wire tx_ack; 109 | (* dont_touch = "true" *)(* mark_debug = "true" *)wire tx_eof; 110 | 111 | (* dont_touch = "true" *)(* mark_debug = "true" *)wire eth_tx_en_p; 112 | (* dont_touch = "true" *)(* mark_debug = "true" *)wire [3:0] eth_txd_p; 113 | 114 | (* IOB = "TRUE" *) reg eth_tx_en_pp; 115 | (* IOB = "TRUE" *) reg [3:0] eth_txd_pp; 116 | 117 | always @(posedge eth_tx_clk_i) begin 118 | eth_tx_en_pp <= eth_tx_en_p; 119 | eth_txd_pp <= eth_txd_p; 120 | end 121 | 122 | assign eth_tx_en = eth_tx_en_pp; 123 | assign eth_txd = eth_txd_pp; 124 | 125 | //The Ethernet TX MAC, which is responsible for prepending the preamble and 126 | //appending the CRC 127 | tx_mac tx_mac_inst ( 128 | 129 | .clk_tx(eth_tx_clk_i), 130 | 131 | .tx_vld(tx_vld), 132 | .tx_eof(tx_eof), 133 | .tx_dat(tx_dat), 134 | .tx_ack(tx_ack), 135 | 136 | .mii_tx_en(eth_tx_en_p), 137 | .mii_tx_dat(eth_txd_p) 138 | ); 139 | 140 | wire rx_vld; 141 | wire [3:0] rx_dat; 142 | wire rx_eof; 143 | 144 | //The Ethernet RX MAC, which is responsible for stripping the preamble and CRC 145 | rx_mac rx_mac_inst ( 146 | 147 | .clk_rx(eth_rx_clk_i), 148 | 149 | .rx_vld(rx_vld), 150 | .rx_eof(rx_eof), 151 | .rx_dat(rx_dat), 152 | 153 | .mii_rx_dv(eth_rx_dv), 154 | .mii_rxd(eth_rxd) 155 | ); 156 | 157 | ////////////////////////////////////////////////////////////////// 158 | //Radio 159 | ///////////////////////////////////////////////////////////////// 160 | 161 | (* dont_touch = "true" *)(* mark_debug = "true" *) wire vld; 162 | (* dont_touch = "true" *)(* mark_debug = "true" *) wire eof; 163 | (* dont_touch = "true" *)(* mark_debug = "true" *) wire full; 164 | 165 | (* dont_touch = "true" *)(* mark_debug = "true" *)wire [3:0] dat_in; 166 | 167 | xpm_fifo_async#( 168 | .FIFO_MEMORY_TYPE("auto"), //String 169 | .FIFO_READ_LATENCY(0), //DECIMAL 170 | .FIFO_WRITE_DEPTH(4096), //DECIMAL 171 | .READ_DATA_WIDTH(5), //DECIMAL 172 | .READ_MODE("fwft"), //String 173 | .USE_ADV_FEATURES("1000"), //String 174 | .WRITE_DATA_WIDTH(5) //DECIMAL 175 | ) xpm_fifo_async_rx_inst ( 176 | 177 | .wr_clk(eth_rx_clk_i), 178 | .rd_clk(eth_tx_clk_i), 179 | 180 | .rst(1'b0), 181 | 182 | .full(), 183 | .wr_en(rx_vld), 184 | .din({rx_eof, rx_dat}), 185 | 186 | .data_valid(vld), 187 | .rd_en(1), 188 | .dout({eof, dat_in}) 189 | ); 190 | 191 | kvs kvs_inst ( 192 | .clk(eth_tx_clk_i), 193 | .rst(1'b0), 194 | .clkEn(1'b1), 195 | 196 | //Samples in 197 | .iVld(vld), 198 | .iEof(eof), 199 | .iDat(dat_in), 200 | 201 | //Samples out 202 | .iReady(tx_ack), 203 | .oVld(tx_vld), 204 | .oEof(tx_eof), 205 | .oDat(tx_dat) 206 | ); 207 | 208 | endmodule 209 | 210 | -------------------------------------------------------------------------------- /fpga/src/tx_mac.v: -------------------------------------------------------------------------------- 1 | //100M MII Ethernet TX module 2 | module tx_mac ( 3 | 4 | input clk_tx, 5 | 6 | //User interface signals 7 | input tx_vld, 8 | input tx_eof, 9 | input [3:0] tx_dat, 10 | output tx_ack, 11 | 12 | //MII phy signals 13 | output mii_tx_en, 14 | reg [3:0] mii_tx_dat 15 | 16 | ); 17 | 18 | //Packet formatter state machine 19 | reg [5:0] packet_cnt; 20 | 21 | always @(posedge clk_tx) 22 | if (packet_cnt == 0) //Idle 23 | packet_cnt <= packet_cnt + tx_vld; 24 | else if (packet_cnt < 16) //Preamble 25 | packet_cnt <= packet_cnt + 1; 26 | else if (packet_cnt == 16) //Data 27 | packet_cnt <= packet_cnt + tx_eof; 28 | else if (packet_cnt < 48) //FCS + interpacket gap 29 | packet_cnt <= packet_cnt + 1; 30 | else 31 | packet_cnt <= 0; 32 | 33 | //Ack if we're in a state were we can accept data 34 | assign tx_ack = packet_cnt == 16; 35 | 36 | //Set the MII output signals 37 | assign mii_tx_en = (tx_vld || |packet_cnt) && (packet_cnt <= 24); 38 | 39 | always @(*) 40 | //preamble 41 | if (packet_cnt <= 14) 42 | mii_tx_dat = 4'h5; 43 | //SFD 44 | else if (packet_cnt == 15) 45 | mii_tx_dat = 4'hd; 46 | //data 47 | else if (packet_cnt == 16) 48 | mii_tx_dat = tx_dat; 49 | //CRC 50 | else 51 | mii_tx_dat = {!crc_final[28], !crc_final[29], !crc_final[30], !crc_final[31]}; 52 | 53 | 54 | //CRC calculation 55 | integer i; 56 | reg [31:0] crc_i [0:4]; 57 | 58 | reg [31:0] crc_final = 32'hffffffff; 59 | 60 | always @(posedge clk_tx) 61 | if (tx_vld && packet_cnt == 16) 62 | crc_final <= crc_i[4]; 63 | else 64 | crc_final <= {crc_final[27:0], 4'hf}; 65 | 66 | always @(*) begin 67 | 68 | crc_i[0] = crc_final; 69 | 70 | for (i=0; i<4; i = i + 1) 71 | if (tx_dat[i] == crc_i[i][31]) 72 | crc_i[i + 1] = {crc_i[i][30:0], 1'b0}; 73 | else 74 | crc_i[i + 1] = {crc_i[i][30:0], 1'b0} ^ 32'h04C11DB7; 75 | end 76 | 77 | endmodule 78 | -------------------------------------------------------------------------------- /setup_net.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Enable the interface connected to the Arty 5 | ip link set dev $1 up 6 | # Give that interface an IP address 7 | ip addr add 192.168.5.1/24 dev $1 8 | # Give the Arty a dummy MAC so it doesn't need to respond to ARPs 9 | ip neigh add 192.168.5.2 lladdr 00:80:77:31:01:07 nud permanent dev $1 10 | -------------------------------------------------------------------------------- /software/Makefile: -------------------------------------------------------------------------------- 1 | test: test.hs 2 | stack exec ghc test.hs 3 | -------------------------------------------------------------------------------- /software/test.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RecordWildCards #-} 2 | 3 | import Prelude hiding (lookup) 4 | 5 | import Data.Word 6 | import Control.Monad 7 | 8 | import Network.Socket (Socket, SockAddr) 9 | import qualified Network.Socket as Socket 10 | import Network.Socket.ByteString (sendAllTo, recv) 11 | import Data.Serialize 12 | import System.IO (hFlush, stdout) 13 | 14 | --Insert/delete/lookup command to send to FPGA 15 | data Command = Command { 16 | command :: Word32, 17 | key :: Word64, 18 | value :: Word64 19 | } deriving (Show) 20 | 21 | --Encode the command 22 | putCommand :: Putter Command 23 | putCommand Command{..} 24 | = putWord32be command 25 | <> putWord64be key 26 | <> putWord64be value 27 | 28 | --Result of a lookup 29 | data LookupResult = LookupResult { 30 | present :: Word32, 31 | result :: Word64 32 | } deriving (Show) 33 | 34 | --Decode the result 35 | getResult :: Get LookupResult 36 | getResult 37 | = LookupResult 38 | <$> getWord32be 39 | <*> getWord64be 40 | 41 | --Send commands to FPGA 42 | insert :: Socket -> SockAddr -> Word64 -> Word64 -> IO () 43 | insert socket fpgaAddress key value = do 44 | let cmd = Command 1 key value 45 | sendAllTo socket (runPut $ putCommand cmd) fpgaAddress 46 | 47 | delete :: Socket -> SockAddr -> Word64 -> IO () 48 | delete socket fpgaAddress key = do 49 | let cmd = Command 2 key 0 50 | sendAllTo socket (runPut $ putCommand cmd) fpgaAddress 51 | 52 | lookup :: Socket -> SockAddr -> Word64 -> IO (Either String LookupResult) 53 | lookup socket fpgaAddress key = do 54 | let cmd = Command 0 key 0 55 | sendAllTo socket (runPut $ putCommand cmd) fpgaAddress 56 | res <- recv socket 16 57 | return $ runGet getResult res 58 | 59 | --How many items to insert. Based on the number of RAMs available on the FPGA 60 | maxIdx = 7500 61 | 62 | --Derive keys and values from indices to get a "random" distribution of keys 63 | keyFunc1 :: Int -> Word64 64 | keyFunc1 x = fromIntegral $ x ^ 2 65 | 66 | keyFunc2 :: Int -> Word64 67 | keyFunc2 x = fromIntegral $ x ^ 3 68 | 69 | valueFunc :: Int -> Word64 70 | valueFunc x = fromIntegral $ x ^ 5 71 | 72 | --Test which fills up the hashtable, reads everything back, deletes everything, and checks its empty 73 | fillAndEmpty :: Socket -> SockAddr -> IO () 74 | fillAndEmpty socket fpgaAddress = do 75 | 76 | putStr "Testing filling the hashtable up, reading everything back, deleting everything, then making sure its empty... " 77 | hFlush stdout 78 | 79 | --Insert the values 80 | forM_ [0..maxIdx] $ \idx -> insert socket fpgaAddress (keyFunc1 idx) (valueFunc idx) 81 | 82 | --Readback the values 83 | forM_ [0..maxIdx] $ \idx -> do 84 | res <- lookup socket fpgaAddress (keyFunc1 idx) 85 | case res of 86 | Left err 87 | -> putStrLn $ "Parsing error after insert" ++ err 88 | Right res -> do 89 | when (present res /= 1) $ putStrLn "Error: inserted item is not present" 90 | when (result res /= valueFunc idx) $ putStrLn $ "Error: inserted item has the wrong value. Expected: " ++ show (valueFunc idx) ++ ". Got: " ++ show (result res) 91 | 92 | --Delete the values 93 | forM_ [0..maxIdx] $ \idx -> delete socket fpgaAddress (keyFunc1 idx) 94 | 95 | forM_ [0..maxIdx] $ \idx -> do 96 | res <- lookup socket fpgaAddress (keyFunc1 idx) 97 | case res of 98 | Left err -> putStrLn $ "Parsing error after delete" ++ err 99 | Right res -> when (present res /= 0) $ putStrLn "Error: item is still present after deletion" 100 | 101 | putStrLn "Success!" 102 | 103 | --Test which fills up the hashtable, immediately reading back inserted keys as they are inserted. Then does the same with deletes. 104 | alternateInsertRead :: Socket -> SockAddr -> IO () 105 | alternateInsertRead socket fpgaAddress = do 106 | 107 | putStr "Testing filling the hashtable up while reading back each inserted value... " 108 | hFlush stdout 109 | 110 | --Alternate inserting and reading back 111 | forM_ [0..maxIdx] $ \idx -> do 112 | 113 | --Insert a value 114 | insert socket fpgaAddress (keyFunc2 idx) (valueFunc idx + 1) 115 | --Overwrite it 116 | insert socket fpgaAddress (keyFunc2 idx) (valueFunc idx) 117 | 118 | --Lookup the value 119 | res <- lookup socket fpgaAddress (keyFunc2 idx) 120 | --Check the correct value is returned 121 | case res of 122 | Left err 123 | -> putStrLn $ "Parsing error after insert" ++ err 124 | Right res -> do 125 | when (present res /= 1) $ putStrLn "Error: inserted item is not present" 126 | when (result res /= valueFunc idx) $ putStrLn $ "Error: inserted item has the wrong value. Expected: " ++ show (valueFunc idx) ++ ". Got: " ++ show (result res) 127 | 128 | --Alternate deleting and reading back 129 | forM_ [0..maxIdx] $ \idx -> do 130 | 131 | --Delete it 132 | delete socket fpgaAddress (keyFunc2 idx) 133 | 134 | --Check it's not there 135 | res <- lookup socket fpgaAddress (keyFunc2 idx) 136 | case res of 137 | Left err 138 | -> putStrLn $ "Parsing error after delete" ++ err 139 | Right res 140 | -> when (present res /= 0) $ putStrLn "Error: item is still present after deletion" 141 | 142 | putStrLn "Success!" 143 | 144 | main :: IO () 145 | main = do 146 | 147 | let hostAddress = Socket.SockAddrInet 0x1234 0 148 | fpgaAddress = Socket.SockAddrInet 0x1234 (Socket.tupleToHostAddress (192, 168, 5, 2)) 149 | 150 | socket <- Socket.socket Socket.AF_INET Socket.Datagram Socket.defaultProtocol 151 | Socket.bind socket hostAddress 152 | 153 | --Repeat both tests forever in a loop 154 | putStrLn "Looping tests forever..." 155 | forever $ do 156 | alternateInsertRead socket fpgaAddress 157 | fillAndEmpty socket fpgaAddress 158 | 159 | --------------------------------------------------------------------------------