From d1a1059d748955ed93a8e87c437c7eae1258293c Mon Sep 17 00:00:00 2001 From: Alexander D'hoore Date: Fri, 15 Dec 2017 15:37:58 +0100 Subject: Add the linux device driver and netfpga files This adds the device driver and netfpga files from the master thesis (in Dutch) "Implementatie van de Recursive Internet Architecture op een FPGA platform" by Alexander D'hoore. --- linux/Makefile | 7 + linux/phy_conf.h | 728 ++++++++++++++++++++ linux/raptor.c | 940 ++++++++++++++++++++++++++ netfpga10g/constraints.ucf | 52 ++ netfpga10g/hdl/buff.vhd | 192 ++++++ netfpga10g/hdl/dma.vhd | 640 ++++++++++++++++++ netfpga10g/hdl/engine.vhd | 570 ++++++++++++++++ netfpga10g/hdl/eth.vhd | 219 ++++++ netfpga10g/hdl/eth_rx.vhd | 84 +++ netfpga10g/hdl/eth_tx.vhd | 68 ++ netfpga10g/hdl/mdio.vhd | 223 ++++++ netfpga10g/hdl/pcie.vhd | 268 ++++++++ netfpga10g/hdl/pcie_rx.vhd | 98 +++ netfpga10g/hdl/pcie_tx.vhd | 178 +++++ netfpga10g/hdl/pcie_wrapper.vhd | 358 ++++++++++ netfpga10g/hdl/port_fifo.vhd | 94 +++ netfpga10g/hdl/recv_mux.vhd | 86 +++ netfpga10g/hdl/rx_eth.vhd | 168 +++++ netfpga10g/hdl/send_mux.vhd | 77 +++ netfpga10g/hdl/system_loop.vhd | 253 +++++++ netfpga10g/hdl/top.vhd | 243 +++++++ netfpga10g/hdl/tx_eth.vhd | 96 +++ netfpga10g/tests/buff_test.vhd | 151 +++++ netfpga10g/tests/engine_test.vhd | 1123 +++++++++++++++++++++++++++++++ netfpga10g/tests/eth_buff_loop_test.vhd | 173 +++++ netfpga10g/tests/eth_rx_test.vhd | 225 +++++++ netfpga10g/tests/eth_tx_test.vhd | 126 ++++ netfpga10g/tests/pcie_rx_test.vhd | 322 +++++++++ netfpga10g/tests/pcie_tx_test.vhd | 561 +++++++++++++++ netfpga10g/tests/queue_test.vhd | 149 ++++ netfpga10g/tests/send_mux_test.vhd | 199 ++++++ netfpga10g/tests/system_loop_test.vhd | 285 ++++++++ 32 files changed, 8956 insertions(+) create mode 100644 linux/Makefile create mode 100644 linux/phy_conf.h create mode 100644 linux/raptor.c create mode 100644 netfpga10g/constraints.ucf create mode 100644 netfpga10g/hdl/buff.vhd create mode 100644 netfpga10g/hdl/dma.vhd create mode 100644 netfpga10g/hdl/engine.vhd create mode 100644 netfpga10g/hdl/eth.vhd create mode 100644 netfpga10g/hdl/eth_rx.vhd create mode 100644 netfpga10g/hdl/eth_tx.vhd create mode 100644 netfpga10g/hdl/mdio.vhd create mode 100644 netfpga10g/hdl/pcie.vhd create mode 100644 netfpga10g/hdl/pcie_rx.vhd create mode 100644 netfpga10g/hdl/pcie_tx.vhd create mode 100644 netfpga10g/hdl/pcie_wrapper.vhd create mode 100644 netfpga10g/hdl/port_fifo.vhd create mode 100644 netfpga10g/hdl/recv_mux.vhd create mode 100644 netfpga10g/hdl/rx_eth.vhd create mode 100644 netfpga10g/hdl/send_mux.vhd create mode 100644 netfpga10g/hdl/system_loop.vhd create mode 100644 netfpga10g/hdl/top.vhd create mode 100644 netfpga10g/hdl/tx_eth.vhd create mode 100644 netfpga10g/tests/buff_test.vhd create mode 100644 netfpga10g/tests/engine_test.vhd create mode 100644 netfpga10g/tests/eth_buff_loop_test.vhd create mode 100644 netfpga10g/tests/eth_rx_test.vhd create mode 100644 netfpga10g/tests/eth_tx_test.vhd create mode 100644 netfpga10g/tests/pcie_rx_test.vhd create mode 100644 netfpga10g/tests/pcie_tx_test.vhd create mode 100644 netfpga10g/tests/queue_test.vhd create mode 100644 netfpga10g/tests/send_mux_test.vhd create mode 100644 netfpga10g/tests/system_loop_test.vhd diff --git a/linux/Makefile b/linux/Makefile new file mode 100644 index 0000000..9c7b2b9 --- /dev/null +++ b/linux/Makefile @@ -0,0 +1,7 @@ +obj-m += raptor.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/linux/phy_conf.h b/linux/phy_conf.h new file mode 100644 index 0000000..71997ed --- /dev/null +++ b/linux/phy_conf.h @@ -0,0 +1,728 @@ + +#ifndef _PHY_CONF_H +#define _PHY_CONF_H + +//#include "nf10driver.h" + +#define MDIO_BASE_ADDR 0x7a000000ULL // Check the Xilinx XPS Address Space if the hw changed + +#define PMA_MDIO_DEVICE_ADDRESS 1 +#define PCS_MDIO_DEVICE_ADDRESS 3 +#define PHY_XS_MDIO_DEVICE_ADDRESS 4 + +#define PMA_CTL_REGISTER_ADDRESS 0x0 +#define PMA_STATUS_REGISTER_ADDRESS 0x1 +#define PMA_RESET_REGISTER_VALUE 0x8000 +#define PMA_SYS_LOOPBACK_REGISTER_VALUE 0x1 +#define PMA_RCV_SIG_DETECTED_ADDRESS 0xa + +#define PCS_STATUS_REGISTER_ADDRESS 0x1 +#define PHY_XS_STATUS_REGISTER_ADDRESS 0x1 + +#define AEL_MICRO_CONTROLLER_CTL_ADDRESS 0xc04a + +#define AEL_I2C_CTRL 0xc30a +#define AEL_I2C_DATA 0xc30b +#define AEL_I2C_STAT 0xc30c + +#define XEL_MDIOCNTR_OFFSET 0x07F0 //< MDIO Control +#define XEL_MDIOCNTR_STATUS_MASK 0x00000001 //< MDIO transfer in +#define XEL_MDIO_ADDRESS_SHIFT 0x5 /**< PHY Address shift*/ +#define XEL_MDIO_ADDRESS_MASK 0x00003E0 /**< PHY Address mask */ +#define XEL_MDIOADDR_OFFSET 0x07E4 // < MDIO Address offset +#define XEL_MDIOWR_OFFSET 0x07E8 //< MDIO write data +#define XEL_MDIOCNTR_ENABLE_MASK 0x00000008 /**< MDIO Enable */ +#define XEL_MDIORD_OFFSET 0x07EC //< MDIO read data +#define XEL_MDIO_OP_45_ADDRESS 0x00000000 /**< PHY address access */ +#define XEL_MDIO_OP_45_WRITE 0x00000400 /**< PHY write access */ +#define XEL_MDIO_OP_45_READ_INC 0x00000800 /**< PHY read inc access */ +#define XEL_MDIO_OP_45_READ 0x00000C00 /**< PHY read access */ +#define XEL_MDIO_CLAUSE_45 0x00001000 /**< PHY Clause type access */ + +/* PHY module I2C device address */ +#define MODULE_DEV_ADDR 0xa0 +#define SFF_DEV_ADDR 0xa2 + +enum { + MODE_TWINAX, + MODE_SR, + MODE_LR, // Not supported + MODE_LRM // Not supported +}; + +const uint16_t regs0[] = { + 0xc220, 0x711C + }; + +const uint16_t regs1_1g[] = { + 0xc220, 0x744C + }; + +// software reset and magic registers +const uint16_t reset[] = { + 0x0000, 0xa040, + 0xc001, 0x0428, + 0xc017, 0xfeb0, + 0xc013, 0xf341, + 0xc210, 0x8000, + 0xc210, 0x8100, + 0xc210, 0x8000, + 0xc210, 0x0000 + }; + +// unpause the microprocessor +const uint16_t regs1[] = { + 0xca00, 0x0080, + 0xca12, 0x0000 + }; + +// main Twinax EDC program +const uint16_t twinax_edc[] = { + 0xc04a, 0x5a00, + 0xcc00, 0x4009, + 0xcc01, 0x27ff, + 0xcc02, 0x300f, + 0xcc03, 0x40aa, + 0xcc04, 0x401c, + 0xcc05, 0x401e, + 0xcc06, 0x2ff4, + 0xcc07, 0x3cd4, + 0xcc08, 0x2035, + 0xcc09, 0x3145, + 0xcc0a, 0x6524, + 0xcc0b, 0x26a2, + 0xcc0c, 0x3012, + 0xcc0d, 0x1002, + 0xcc0e, 0x29c2, + 0xcc0f, 0x3002, + 0xcc10, 0x1002, + 0xcc11, 0x2072, + 0xcc12, 0x3012, + 0xcc13, 0x1002, + 0xcc14, 0x22cd, + 0xcc15, 0x301d, + 0xcc16, 0x2e52, + 0xcc17, 0x3012, + 0xcc18, 0x1002, + 0xcc19, 0x28e2, + 0xcc1a, 0x3002, + 0xcc1b, 0x1002, + 0xcc1c, 0x628f, + 0xcc1d, 0x2ac2, + 0xcc1e, 0x3012, + 0xcc1f, 0x1002, + 0xcc20, 0x5553, + 0xcc21, 0x2ae2, + 0xcc22, 0x3002, + 0xcc23, 0x1302, + 0xcc24, 0x401e, + 0xcc25, 0x2be2, + 0xcc26, 0x3012, + 0xcc27, 0x1002, + 0xcc28, 0x2da2, + 0xcc29, 0x3012, + 0xcc2a, 0x1002, + 0xcc2b, 0x2ba2, + 0xcc2c, 0x3002, + 0xcc2d, 0x1002, + 0xcc2e, 0x5ee3, + 0xcc2f, 0x305, + 0xcc30, 0x400e, + 0xcc31, 0x2bc2, + 0xcc32, 0x3002, + 0xcc33, 0x1002, + 0xcc34, 0x2b82, + 0xcc35, 0x3012, + 0xcc36, 0x1002, + 0xcc37, 0x5663, + 0xcc38, 0x302, + 0xcc39, 0x401e, + 0xcc3a, 0x6f72, + 0xcc3b, 0x1002, + 0xcc3c, 0x628f, + 0xcc3d, 0x2be2, + 0xcc3e, 0x3012, + 0xcc3f, 0x1002, + 0xcc40, 0x22cd, + 0xcc41, 0x301d, + 0xcc42, 0x2e52, + 0xcc43, 0x3012, + 0xcc44, 0x1002, + 0xcc45, 0x2522, + 0xcc46, 0x3012, + 0xcc47, 0x1002, + 0xcc48, 0x2da2, + 0xcc49, 0x3012, + 0xcc4a, 0x1002, + 0xcc4b, 0x2ca2, + 0xcc4c, 0x3012, + 0xcc4d, 0x1002, + 0xcc4e, 0x2fa4, + 0xcc4f, 0x3cd4, + 0xcc50, 0x6624, + 0xcc51, 0x410b, + 0xcc52, 0x56b3, + 0xcc53, 0x3c4, + 0xcc54, 0x2fb2, + 0xcc55, 0x3002, + 0xcc56, 0x1002, + 0xcc57, 0x220b, + 0xcc58, 0x303b, + 0xcc59, 0x56b3, + 0xcc5a, 0x3c3, + 0xcc5b, 0x866b, + 0xcc5c, 0x400c, + 0xcc5d, 0x23a2, + 0xcc5e, 0x3012, + 0xcc5f, 0x1002, + 0xcc60, 0x2da2, + 0xcc61, 0x3012, + 0xcc62, 0x1002, + 0xcc63, 0x2ca2, + 0xcc64, 0x3012, + 0xcc65, 0x1002, + 0xcc66, 0x2fb4, + 0xcc67, 0x3cd4, + 0xcc68, 0x6624, + 0xcc69, 0x56b3, + 0xcc6a, 0x3c3, + 0xcc6b, 0x866b, + 0xcc6c, 0x401c, + 0xcc6d, 0x2205, + 0xcc6e, 0x3035, + 0xcc6f, 0x5b53, + 0xcc70, 0x2c52, + 0xcc71, 0x3002, + 0xcc72, 0x13c2, + 0xcc73, 0x5cc3, + 0xcc74, 0x317, + 0xcc75, 0x2522, + 0xcc76, 0x3012, + 0xcc77, 0x1002, + 0xcc78, 0x2da2, + 0xcc79, 0x3012, + 0xcc7a, 0x1002, + 0xcc7b, 0x2b82, + 0xcc7c, 0x3012, + 0xcc7d, 0x1002, + 0xcc7e, 0x5663, + 0xcc7f, 0x303, + 0xcc80, 0x401e, + 0xcc81, 0x004, + 0xcc82, 0x2c42, + 0xcc83, 0x3012, + 0xcc84, 0x1002, + 0xcc85, 0x6f72, + 0xcc86, 0x1002, + 0xcc87, 0x628f, + 0xcc88, 0x2304, + 0xcc89, 0x3c84, + 0xcc8a, 0x6436, + 0xcc8b, 0xdff4, + 0xcc8c, 0x6436, + 0xcc8d, 0x2ff5, + 0xcc8e, 0x3005, + 0xcc8f, 0x8656, + 0xcc90, 0xdfba, + 0xcc91, 0x56a3, + 0xcc92, 0xd05a, + 0xcc93, 0x21c2, + 0xcc94, 0x3012, + 0xcc95, 0x1392, + 0xcc96, 0xd05a, + 0xcc97, 0x56a3, + 0xcc98, 0xdfba, + 0xcc99, 0x383, + 0xcc9a, 0x6f72, + 0xcc9b, 0x1002, + 0xcc9c, 0x28c5, + 0xcc9d, 0x3005, + 0xcc9e, 0x4178, + 0xcc9f, 0x5653, + 0xcca0, 0x384, + 0xcca1, 0x22b2, + 0xcca2, 0x3012, + 0xcca3, 0x1002, + 0xcca4, 0x2be5, + 0xcca5, 0x3005, + 0xcca6, 0x41e8, + 0xcca7, 0x5653, + 0xcca8, 0x382, + 0xcca9, 0x002, + 0xccaa, 0x4258, + 0xccab, 0x2474, + 0xccac, 0x3c84, + 0xccad, 0x6437, + 0xccae, 0xdff4, + 0xccaf, 0x6437, + 0xccb0, 0x2ff5, + 0xccb1, 0x3c05, + 0xccb2, 0x8757, + 0xccb3, 0xb888, + 0xccb4, 0x9787, + 0xccb5, 0xdff4, + 0xccb6, 0x6724, + 0xccb7, 0x866a, + 0xccb8, 0x6f72, + 0xccb9, 0x1002, + 0xccba, 0x2d01, + 0xccbb, 0x3011, + 0xccbc, 0x1001, + 0xccbd, 0xc620, + 0xccbe, 0x14e5, + 0xccbf, 0xc621, + 0xccc0, 0xc53d, + 0xccc1, 0xc622, + 0xccc2, 0x3cbe, + 0xccc3, 0xc623, + 0xccc4, 0x4452, + 0xccc5, 0xc624, + 0xccc6, 0xc5c5, + 0xccc7, 0xc625, + 0xccc8, 0xe01e, + 0xccc9, 0xc627, + 0xccca, 0x000, + 0xcccb, 0xc628, + 0xcccc, 0x000, + 0xcccd, 0xc62b, + 0xccce, 0x000, + 0xcccf, 0xc62c, + 0xccd0, 0x000, + 0xccd1, 0x000, + 0xccd2, 0x2d01, + 0xccd3, 0x3011, + 0xccd4, 0x1001, + 0xccd5, 0xc620, + 0xccd6, 0x000, + 0xccd7, 0xc621, + 0xccd8, 0x000, + 0xccd9, 0xc622, + 0xccda, 0x0ce, + 0xccdb, 0xc623, + 0xccdc, 0x07f, + 0xccdd, 0xc624, + 0xccde, 0x032, + 0xccdf, 0xc625, + 0xcce0, 0x000, + 0xcce1, 0xc627, + 0xcce2, 0x000, + 0xcce3, 0xc628, + 0xcce4, 0x000, + 0xcce5, 0xc62b, + 0xcce6, 0x000, + 0xcce7, 0xc62c, + 0xcce8, 0x000, + 0xcce9, 0x000, + 0xccea, 0x2d01, + 0xcceb, 0x3011, + 0xccec, 0x1001, + 0xcced, 0xc502, + 0xccee, 0x609f, + 0xccef, 0xc600, + 0xccf0, 0x2a6e, + 0xccf1, 0xc601, + 0xccf2, 0x2a2c, + 0xccf3, 0xc60c, + 0xccf4, 0x5400, + 0xccf5, 0xc710, + 0xccf6, 0x700, + 0xccf7, 0xc718, + 0xccf8, 0x700, + 0xccf9, 0xc720, + 0xccfa, 0x4700, + 0xccfb, 0xc728, + 0xccfc, 0x700, + 0xccfd, 0xc729, + 0xccfe, 0x1207, + 0xccff, 0xc801, + 0xcd00, 0x7f50, + 0xcd01, 0xc802, + 0xcd02, 0x7760, + 0xcd03, 0xc803, + 0xcd04, 0x7fce, + 0xcd05, 0xc804, + 0xcd06, 0x520e, + 0xcd07, 0xc805, + 0xcd08, 0x5c11, + 0xcd09, 0xc806, + 0xcd0a, 0x3c51, + 0xcd0b, 0xc807, + 0xcd0c, 0x4061, + 0xcd0d, 0xc808, + 0xcd0e, 0x49c1, + 0xcd0f, 0xc809, + 0xcd10, 0x3840, + 0xcd11, 0xc80a, + 0xcd12, 0x000, + 0xcd13, 0xc821, + 0xcd14, 0x002, + 0xcd15, 0xc822, + 0xcd16, 0x046, + 0xcd17, 0xc844, + 0xcd18, 0x182f, + 0xcd19, 0xc013, + 0xcd1a, 0xf341, + 0xcd1b, 0xc01a, + 0xcd1c, 0x446, + 0xcd1d, 0xc024, + 0xcd1e, 0x1000, + 0xcd1f, 0xc025, + 0xcd20, 0xa00, + 0xcd21, 0xc026, + 0xcd22, 0xc0c, + 0xcd23, 0xc027, + 0xcd24, 0xc0c, + 0xcd25, 0xc029, + 0xcd26, 0x0a0, + 0xcd27, 0xc030, + 0xcd28, 0xa00, + 0xcd29, 0xc03c, + 0xcd2a, 0x01c, + 0xcd2b, 0x000, + 0xcd2c, 0x2b84, + 0xcd2d, 0x3c74, + 0xcd2e, 0x6435, + 0xcd2f, 0xdff4, + 0xcd30, 0x6435, + 0xcd31, 0x2806, + 0xcd32, 0x3006, + 0xcd33, 0x8565, + 0xcd34, 0x2b24, + 0xcd35, 0x3c24, + 0xcd36, 0x6436, + 0xcd37, 0x1002, + 0xcd38, 0x2b24, + 0xcd39, 0x3c24, + 0xcd3a, 0x6436, + 0xcd3b, 0x4045, + 0xcd3c, 0x8656, + 0xcd3d, 0x1002, + 0xcd3e, 0x2807, + 0xcd3f, 0x31a7, + 0xcd40, 0x20c4, + 0xcd41, 0x3c24, + 0xcd42, 0x6724, + 0xcd43, 0x1002, + 0xcd44, 0x2807, + 0xcd45, 0x3187, + 0xcd46, 0x20c4, + 0xcd47, 0x3c24, + 0xcd48, 0x6724, + 0xcd49, 0x1002, + 0xcd4a, 0x2514, + 0xcd4b, 0x3c64, + 0xcd4c, 0x6436, + 0xcd4d, 0xdff4, + 0xcd4e, 0x6436, + 0xcd4f, 0x1002, + 0xcd50, 0x2806, + 0xcd51, 0x3cb6, + 0xcd52, 0xc161, + 0xcd53, 0x6134, + 0xcd54, 0x6135, + 0xcd55, 0x5443, + 0xcd56, 0x303, + 0xcd57, 0x6524, + 0xcd58, 0x00b, + 0xcd59, 0x1002, + 0xcd5a, 0xd019, + 0xcd5b, 0x2104, + 0xcd5c, 0x3c24, + 0xcd5d, 0x2105, + 0xcd5e, 0x3805, + 0xcd5f, 0x6524, + 0xcd60, 0xdff4, + 0xcd61, 0x4005, + 0xcd62, 0x6524, + 0xcd63, 0x2e8d, + 0xcd64, 0x303d, + 0xcd65, 0x5dd3, + 0xcd66, 0x306, + 0xcd67, 0x2ff7, + 0xcd68, 0x38f7, + 0xcd69, 0x60b7, + 0xcd6a, 0xdffd, + 0xcd6b, 0x00a, + 0xcd6c, 0x1002, + 0xcd6d, 0 + }; + +// main SR EDC program +const uint16_t sr_edc[] = { + 0xc003, 0x181, + 0xc010, 0x448a, + 0xc04a, 0x5200, + 0xcc00, 0x2ff4, + 0xcc01, 0x3cd4, + 0xcc02, 0x2015, + 0xcc03, 0x3105, + 0xcc04, 0x6524, + 0xcc05, 0x27ff, + 0xcc06, 0x300f, + 0xcc07, 0x2c8b, + 0xcc08, 0x300b, + 0xcc09, 0x4009, + 0xcc0a, 0x400e, + 0xcc0b, 0x2f72, + 0xcc0c, 0x3002, + 0xcc0d, 0x1002, + 0xcc0e, 0x2172, + 0xcc0f, 0x3012, + 0xcc10, 0x1002, + 0xcc11, 0x25d2, + 0xcc12, 0x3012, + 0xcc13, 0x1002, + 0xcc14, 0xd01e, + 0xcc15, 0x27d2, + 0xcc16, 0x3012, + 0xcc17, 0x1002, + 0xcc18, 0x2004, + 0xcc19, 0x3c84, + 0xcc1a, 0x6436, + 0xcc1b, 0x2007, + 0xcc1c, 0x3f87, + 0xcc1d, 0x8676, + 0xcc1e, 0x40b7, + 0xcc1f, 0xa746, + 0xcc20, 0x4047, + 0xcc21, 0x5673, + 0xcc22, 0x2982, + 0xcc23, 0x3002, + 0xcc24, 0x13d2, + 0xcc25, 0x8bbd, + 0xcc26, 0x2862, + 0xcc27, 0x3012, + 0xcc28, 0x1002, + 0xcc29, 0x2092, + 0xcc2a, 0x3012, + 0xcc2b, 0x1002, + 0xcc2c, 0x5cc3, + 0xcc2d, 0x314, + 0xcc2e, 0x2942, + 0xcc2f, 0x3002, + 0xcc30, 0x1002, + 0xcc31, 0xd019, + 0xcc32, 0x2032, + 0xcc33, 0x3012, + 0xcc34, 0x1002, + 0xcc35, 0x2a04, + 0xcc36, 0x3c74, + 0xcc37, 0x6435, + 0xcc38, 0x2fa4, + 0xcc39, 0x3cd4, + 0xcc3a, 0x6624, + 0xcc3b, 0x5563, + 0xcc3c, 0x2d42, + 0xcc3d, 0x3002, + 0xcc3e, 0x13d2, + 0xcc3f, 0x464d, + 0xcc40, 0x2862, + 0xcc41, 0x3012, + 0xcc42, 0x1002, + 0xcc43, 0x2032, + 0xcc44, 0x3012, + 0xcc45, 0x1002, + 0xcc46, 0x2fb4, + 0xcc47, 0x3cd4, + 0xcc48, 0x6624, + 0xcc49, 0x5563, + 0xcc4a, 0x2d42, + 0xcc4b, 0x3002, + 0xcc4c, 0x13d2, + 0xcc4d, 0x2ed2, + 0xcc4e, 0x3002, + 0xcc4f, 0x1002, + 0xcc50, 0x2fd2, + 0xcc51, 0x3002, + 0xcc52, 0x1002, + 0xcc53, 0x004, + 0xcc54, 0x2942, + 0xcc55, 0x3002, + 0xcc56, 0x1002, + 0xcc57, 0x2092, + 0xcc58, 0x3012, + 0xcc59, 0x1002, + 0xcc5a, 0x5cc3, + 0xcc5b, 0x317, + 0xcc5c, 0x2f72, + 0xcc5d, 0x3002, + 0xcc5e, 0x1002, + 0xcc5f, 0x2942, + 0xcc60, 0x3002, + 0xcc61, 0x1002, + 0xcc62, 0x22cd, + 0xcc63, 0x301d, + 0xcc64, 0x2862, + 0xcc65, 0x3012, + 0xcc66, 0x1002, + 0xcc67, 0x2ed2, + 0xcc68, 0x3002, + 0xcc69, 0x1002, + 0xcc6a, 0x2d72, + 0xcc6b, 0x3002, + 0xcc6c, 0x1002, + 0xcc6d, 0x628f, + 0xcc6e, 0x2112, + 0xcc6f, 0x3012, + 0xcc70, 0x1002, + 0xcc71, 0x5aa3, + 0xcc72, 0x2dc2, + 0xcc73, 0x3002, + 0xcc74, 0x1312, + 0xcc75, 0x6f72, + 0xcc76, 0x1002, + 0xcc77, 0x2807, + 0xcc78, 0x31a7, + 0xcc79, 0x20c4, + 0xcc7a, 0x3c24, + 0xcc7b, 0x6724, + 0xcc7c, 0x1002, + 0xcc7d, 0x2807, + 0xcc7e, 0x3187, + 0xcc7f, 0x20c4, + 0xcc80, 0x3c24, + 0xcc81, 0x6724, + 0xcc82, 0x1002, + 0xcc83, 0x2514, + 0xcc84, 0x3c64, + 0xcc85, 0x6436, + 0xcc86, 0xdff4, + 0xcc87, 0x6436, + 0xcc88, 0x1002, + 0xcc89, 0x40a4, + 0xcc8a, 0x643c, + 0xcc8b, 0x4016, + 0xcc8c, 0x8c6c, + 0xcc8d, 0x2b24, + 0xcc8e, 0x3c24, + 0xcc8f, 0x6435, + 0xcc90, 0x1002, + 0xcc91, 0x2b24, + 0xcc92, 0x3c24, + 0xcc93, 0x643a, + 0xcc94, 0x4025, + 0xcc95, 0x8a5a, + 0xcc96, 0x1002, + 0xcc97, 0x2731, + 0xcc98, 0x3011, + 0xcc99, 0x1001, + 0xcc9a, 0xc7a0, + 0xcc9b, 0x100, + 0xcc9c, 0xc502, + 0xcc9d, 0x53ac, + 0xcc9e, 0xc503, + 0xcc9f, 0xd5d5, + 0xcca0, 0xc600, + 0xcca1, 0x2a6d, + 0xcca2, 0xc601, + 0xcca3, 0x2a4c, + 0xcca4, 0xc602, + 0xcca5, 0x111, + 0xcca6, 0xc60c, + 0xcca7, 0x5900, + 0xcca8, 0xc710, + 0xcca9, 0x700, + 0xccaa, 0xc718, + 0xccab, 0x700, + 0xccac, 0xc720, + 0xccad, 0x4700, + 0xccae, 0xc801, + 0xccaf, 0x7f50, + 0xccb0, 0xc802, + 0xccb1, 0x7760, + 0xccb2, 0xc803, + 0xccb3, 0x7fce, + 0xccb4, 0xc804, + 0xccb5, 0x5700, + 0xccb6, 0xc805, + 0xccb7, 0x5f11, + 0xccb8, 0xc806, + 0xccb9, 0x4751, + 0xccba, 0xc807, + 0xccbb, 0x57e1, + 0xccbc, 0xc808, + 0xccbd, 0x2700, + 0xccbe, 0xc809, + 0xccbf, 0x000, + 0xccc0, 0xc821, + 0xccc1, 0x002, + 0xccc2, 0xc822, + 0xccc3, 0x014, + 0xccc4, 0xc832, + 0xccc5, 0x1186, + 0xccc6, 0xc847, + 0xccc7, 0x1e02, + 0xccc8, 0xc013, + 0xccc9, 0xf341, + 0xccca, 0xc01a, + 0xcccb, 0x446, + 0xcccc, 0xc024, + 0xcccd, 0x1000, + 0xccce, 0xc025, + 0xcccf, 0xa00, + 0xccd0, 0xc026, + 0xccd1, 0xc0c, + 0xccd2, 0xc027, + 0xccd3, 0xc0c, + 0xccd4, 0xc029, + 0xccd5, 0x0a0, + 0xccd6, 0xc030, + 0xccd7, 0xa00, + 0xccd8, 0xc03c, + 0xccd9, 0x01c, + 0xccda, 0xc005, + 0xccdb, 0x7a06, + 0xccdc, 0x000, + 0xccdd, 0x2731, + 0xccde, 0x3011, + 0xccdf, 0x1001, + 0xcce0, 0xc620, + 0xcce1, 0x000, + 0xcce2, 0xc621, + 0xcce3, 0x03f, + 0xcce4, 0xc622, + 0xcce5, 0x000, + 0xcce6, 0xc623, + 0xcce7, 0x000, + 0xcce8, 0xc624, + 0xcce9, 0x000, + 0xccea, 0xc625, + 0xcceb, 0x000, + 0xccec, 0xc627, + 0xcced, 0x000, + 0xccee, 0xc628, + 0xccef, 0x000, + 0xccf0, 0xc62c, + 0xccf1, 0x000, + 0xccf2, 0x000, + 0xccf3, 0x2806, + 0xccf4, 0x3cb6, + 0xccf5, 0xc161, + 0xccf6, 0x6134, + 0xccf7, 0x6135, + 0xccf8, 0x5443, + 0xccf9, 0x303, + 0xccfa, 0x6524, + 0xccfb, 0x00b, + 0xccfc, 0x1002, + 0xccfd, 0x2104, + 0xccfe, 0x3c24, + 0xccff, 0x2105, + 0xcd00, 0x3805, + 0xcd01, 0x6524, + 0xcd02, 0xdff4, + 0xcd03, 0x4005, + 0xcd04, 0x6524, + 0xcd05, 0x1002, + 0xcd06, 0x5dd3, + 0xcd07, 0x306, + 0xcd08, 0x2ff7, + 0xcd09, 0x38f7, + 0xcd0a, 0x60b7, + 0xcd0b, 0xdffd, + 0xcd0c, 0x00a, + 0xcd0d, 0x1002, + 0xcd0e, 0 + }; + +#endif diff --git a/linux/raptor.c b/linux/raptor.c new file mode 100644 index 0000000..cb28c44 --- /dev/null +++ b/linux/raptor.c @@ -0,0 +1,940 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2017 + * + * Raptor device driver + * + * Alexander D'hoore + * Dimitri Staessens + * Sander Vrijders + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy_conf.h" + +MODULE_LICENSE("GPL"); + +#define RAPTOR_VENDOR_ID 0x10EE +#define RAPTOR_DEVICE_ID 0xAD02 +#define RAPTOR_BAR 0 + +#define BAR_MDIO 30 + +#define CMD_STATUS 0 +#define CMD_SEND 1 +#define CMD_RECV 2 +#define CMD_MDIO 3 + +#define IOCTL_SEND 0xAD420000 +#define IOCTL_RECV 0xAD430000 +#define IOCTL_SEND_DONE 0xAD440000 +#define IOCTL_RECV_DONE 0xAD450000 +#define IOCTL_RECV_NEED 0xAD460000 +#define IOCTL_DEBUG 0xAD470000 + +#define BUFF_COUNT 16 + +#define BUFF_EMPTY 0 +#define BUFF_ADDR 1 +#define BUFF_DATA 2 +#define BUFF_FULL 3 + +#define PACKET_COUNT 1000 + +struct packet; + +struct packet { + uint64_t u_addr; + uint16_t length; + struct page* page; + dma_addr_t dma_addr; + struct packet* next; +}; + +struct queue { + struct packet* first; + struct packet* last; + uint64_t count; +}; + +struct raptor { + dev_t base; + struct class * class; + + dev_t dev; + struct device * device; + struct cdev cdev; + + uint64_t *bar; + struct pci_dev *pdev; + + bool interrupt; + + struct queue send_queue; + struct queue recv_queue; + struct queue send_done_queue; + struct queue recv_done_queue; + struct queue send_free_queue; + struct queue recv_free_queue; + + struct packet* send_packets; + struct packet* recv_packets; + + uint64_t recv_need; + + spinlock_t lock; + wait_queue_head_t wait; + + struct task_struct* kthread; + + uint64_t int_count; + uint64_t send_busy; + uint64_t recv_busy; +}; + +struct raptor raptor; + +// ------------------------------------------- + +static void queue_push(struct queue* queue, struct packet* packet) +{ + spin_lock_irq(&raptor.lock); + + if (queue->count == 0) { + queue->first = packet; + queue->last = packet; + } + else { + queue->last->next = packet; + queue->last = packet; + } + queue->count++; + + spin_unlock_irq(&raptor.lock); + wake_up(&raptor.wait); +} + +static struct packet* queue_pop(struct queue* queue, bool block) +{ + struct packet* packet; + + spin_lock_irq(&raptor.lock); + + if (block) { + if (wait_event_interruptible_lock_irq_timeout( + raptor.wait, queue->count > 0, raptor.lock, HZ) <= 0) { + + spin_unlock_irq(&raptor.lock); + return NULL; + } + } + else { + if (queue->count == 0) { + spin_unlock_irq(&raptor.lock); + return NULL; + } + } + + packet = queue->first; + queue->first = packet->next; + queue->count--; + + spin_unlock_irq(&raptor.lock); + wake_up(&raptor.wait); + return packet; +} + +// ------------------------------------------- + +uint64_t raptor_read(uint64_t offset) +{ + return raptor.bar[offset]; +} + +void raptor_write(uint64_t offset, uint64_t data) +{ + raptor.bar[offset] = data; +} + +uint64_t endian64(uint64_t data) +{ + uint64_t byte0 = (data & 0x00000000000000FF) << 7*8; + uint64_t byte1 = (data & 0x000000000000FF00) << 5*8; + uint64_t byte2 = (data & 0x0000000000FF0000) << 3*8; + uint64_t byte3 = (data & 0x00000000FF000000) << 1*8; + uint64_t byte4 = (data & 0x000000FF00000000) >> 1*8; + uint64_t byte5 = (data & 0x0000FF0000000000) >> 3*8; + uint64_t byte6 = (data & 0x00FF000000000000) >> 5*8; + uint64_t byte7 = (data & 0xFF00000000000000) >> 7*8; + + return byte0 | byte1 | byte2 | byte3 | byte4 | byte5 | byte6 | byte7; +} + +static irqreturn_t raptor_interrupt(int irq, void *dev_id) +{ + spin_lock(&raptor.lock); + raptor.interrupt = true; + spin_unlock(&raptor.lock); + wake_up(&raptor.wait); + + return IRQ_HANDLED; +} + +void mdio_raw(unsigned operation, unsigned phy_addr, unsigned dev_addr, unsigned data) +{ + unsigned command = (operation << 26) | (phy_addr << 21) | (dev_addr << 16) | (data & 0xFFFF); + + raptor_write(CMD_MDIO, endian64((uint64_t)command)); + msleep(1); +} + +void mdio_write(unsigned phy_addr, unsigned dev_addr, unsigned data_addr, unsigned data) +{ + mdio_raw(0, phy_addr, dev_addr, data_addr); + mdio_raw(1, phy_addr, dev_addr, data); +} + +unsigned mdio_read(unsigned phy_addr, unsigned dev_addr, unsigned data_addr) +{ + mdio_raw(0, phy_addr, dev_addr, data_addr); + mdio_raw(3, phy_addr, dev_addr, 0); + + return (unsigned)endian64(raptor_read(BAR_MDIO)); +} + +int mdio_i2c_read(uint32_t phy_addr, uint16_t dev_addr, uint16_t word_addr, uint16_t * data) +{ + uint16_t stat; + int i; + + mdio_write(phy_addr, 1, AEL_I2C_CTRL, (dev_addr << 8) | (1 << 8) | word_addr); + + for (i = 0; i < 20; i++) { + msleep(2); + stat = mdio_read(phy_addr, 1, AEL_I2C_STAT); + + if ((stat & 3) == 1){ + stat = mdio_read(phy_addr, 1, AEL_I2C_DATA); + + *data = stat >> 8; + return 0; + } + } + return -1; +} + +void mdio_initialize(uint32_t phy_addr, int mode) +{ + int size, i; + + // Step 1 + size = sizeof(reset) / sizeof(uint16_t); + + for(i = 0; i < size; i += 2) { + mdio_write(phy_addr, PMA_MDIO_DEVICE_ADDRESS, reset[i], reset[i+1]); + } + + msleep(5); + + // Step 2 + if (mode == MODE_SR) { + size = sizeof(sr_edc) / sizeof(uint16_t); + + for(i = 0; i < size; i += 2) { + mdio_write(phy_addr, PMA_MDIO_DEVICE_ADDRESS, sr_edc[i], sr_edc[i+1]); + } + } + else if (mode == MODE_TWINAX) { + size = sizeof(twinax_edc) / sizeof(uint16_t); + + for(i = 0; i < size; i += 2) { + mdio_write(phy_addr, PMA_MDIO_DEVICE_ADDRESS, twinax_edc[i], twinax_edc[i+1]); + } + } + + // Step 3 + size = sizeof(regs1) / sizeof(uint16_t); + for(i = 0; i < size; i+=2) { + mdio_write(phy_addr, PMA_MDIO_DEVICE_ADDRESS, regs1[i], regs1[i+1]); + } + + msleep(5); +} + +int phy_configuration(void) +{ + int port, dev; + uint16_t value = 0; + char port_mode; + + // check if we need initialization + value = mdio_read(2, PMA_MDIO_DEVICE_ADDRESS, AEL_MICRO_CONTROLLER_CTL_ADDRESS); + + //printk(KERN_INFO "raptor: 0xc04a: %04x\n",value); + if (value & 0x8000) { // uC held in reset + printk(KERN_INFO "raptor: Programming the AEL2005 PHY chips...\n"); + + for (port = 0; port < 4; port++) { + if (port == 0) dev = 2; + else if (port == 1) dev = 1; + else if (port == 2) dev = 0; + else dev = 3; + + value = 0; + + // check if we have a 10GBASE-SR cable + mdio_i2c_read(dev, MODULE_DEV_ADDR, 0x3, &value); + + if((value >> 4) == 1) { + port_mode = MODE_SR; + } + else { + port_mode = MODE_TWINAX; + } + + printk(KERN_INFO "raptor: Programming PHY %d...\n", port); + + mdio_initialize(dev, port_mode); + } + + return 0; + } + + return -1; +} + +static void read_debug(void) +{ + uint64_t status; + uint64_t address; + uint64_t data; + uint64_t cmd; + uint64_t buff; + uint64_t length; + uint64_t cmpl_count; + uint64_t cmpl_data; + uint64_t cmpl_tag; + uint64_t cmpl_state; + uint64_t write_count; + uint64_t write_length; + uint64_t write_addr; + uint64_t write_data; + uint64_t accept_count; + uint64_t done_count; + + status = endian64(raptor_read(0)); + address = endian64(raptor_read(1)); + data = endian64(raptor_read(2)); + cmd = endian64(raptor_read(3)); + buff = endian64(raptor_read(4)); + length = endian64(raptor_read(5)); + cmpl_count = endian64(raptor_read(10)); + cmpl_data = endian64(raptor_read(11)); + cmpl_tag = endian64(raptor_read(12)); + cmpl_state = endian64(raptor_read(13)); + + write_count = endian64(raptor_read(20)); + write_length = endian64(raptor_read(21)); + write_addr = endian64(raptor_read(22)); + write_data = endian64(raptor_read(23)); + accept_count = endian64(raptor_read(24)); + done_count = endian64(raptor_read(25)); + + printk(KERN_INFO "raptor: read_debug:\n"); + printk(KERN_INFO "raptor: status = 0x%llx.\n", status); + printk(KERN_INFO "raptor: address = 0x%llx.\n", address); + printk(KERN_INFO "raptor: data = 0x%llx.\n", data); + printk(KERN_INFO "raptor: cmd = 0x%llx.\n", cmd); + printk(KERN_INFO "raptor: buff = 0x%llx.\n", buff); + printk(KERN_INFO "raptor: length = %llu.\n", length); + printk(KERN_INFO "raptor: cmpl_count = %llu.\n", cmpl_count); + printk(KERN_INFO "raptor: cmpl_data = 0x%llx.\n", cmpl_data); + printk(KERN_INFO "raptor: cmpl_tag = 0x%llx.\n", cmpl_tag); + printk(KERN_INFO "raptor: cmpl_state = 0x%llx.\n", cmpl_state); + printk(KERN_INFO "raptor: write_count = %llu.\n", write_count); + printk(KERN_INFO "raptor: write_length = %llu.\n", write_length); + printk(KERN_INFO "raptor: write_addr = 0x%llx.\n", write_addr); + printk(KERN_INFO "raptor: write_data = 0x%llx.\n", write_data); + printk(KERN_INFO "raptor: accept_count = %llu.\n", accept_count); + printk(KERN_INFO "raptor: done_count = %llu.\n", done_count); +} + +#define get_send(status, i) ((status >> (i * 4 + 0)) & 0x3) +#define get_recv(status, i) ((status >> (i * 4 + 2)) & 0x3) + +struct packet* send_packets[BUFF_COUNT]; +struct packet* recv_packets[BUFF_COUNT]; +uint8_t send_buff[BUFF_COUNT]; +uint8_t recv_buff[BUFF_COUNT]; + +static int raptor_kthread(void* data) +{ + bool interrupt; + uint64_t status = 0; + uint8_t send_new; + uint8_t recv_new; + uint8_t send_old; + uint8_t recv_old; + uint64_t i; + bool send_full = false; + bool recv_full = false; + struct packet* packet; + struct device* dev = &raptor.pdev->dev; + uint64_t offset; + uint64_t rest; + + printk(KERN_INFO "raptor_kthread: started\n"); + + memset(send_packets, 0, sizeof(send_packets)); + memset(recv_packets, 0, sizeof(recv_packets)); + + raptor.interrupt = true; + + while (true) { + spin_lock_irq(&raptor.lock); + + if (wait_event_interruptible_lock_irq( + raptor.wait, + kthread_should_stop() || + raptor.interrupt || + (! send_full && raptor.send_queue.count > 0) || + (! recv_full && raptor.recv_queue.count > 0), + raptor.lock) != 0) { + + printk(KERN_ERR "raptor_kthread: wait_event failed\n"); + spin_unlock_irq(&raptor.lock); + break; + } + + interrupt = raptor.interrupt; + raptor.interrupt = false; + spin_unlock_irq(&raptor.lock); + + if (kthread_should_stop()) + break; + + if (interrupt) { + // read status + // update done_queues + // incr recv_need + status = endian64(raptor_read(0)); + + raptor.int_count++; + + for (i = 0; i < BUFF_COUNT; i++) { + send_new = get_send(status, i); + recv_new = get_recv(status, i); + send_old = send_buff[i]; + recv_old = recv_buff[i]; + + if (send_new != BUFF_EMPTY) + raptor.send_busy++; + if (recv_new != BUFF_EMPTY) + raptor.recv_busy++; + + if ((send_old == BUFF_ADDR || send_old == BUFF_DATA) && + (send_new == BUFF_FULL || send_new == BUFF_EMPTY) && + send_packets[i] != NULL) { + + packet = send_packets[i]; + offset = packet->u_addr & (~PAGE_MASK); + rest = PAGE_SIZE - offset; + + dma_unmap_page(dev, packet->dma_addr, rest, DMA_TO_DEVICE); + queue_push(&raptor.send_done_queue, packet); + send_packets[i] = NULL; + } + if ((recv_old == BUFF_ADDR || recv_old == BUFF_DATA) && + (recv_new == BUFF_FULL || recv_new == BUFF_EMPTY) && + recv_packets[i] != NULL) { + + packet = recv_packets[i]; + offset = packet->u_addr & (~PAGE_MASK); + rest = PAGE_SIZE - offset; + + dma_unmap_page(dev, packet->dma_addr, rest, DMA_FROM_DEVICE); + queue_push(&raptor.recv_done_queue, packet); + recv_packets[i] = NULL; + } + if (recv_old != BUFF_FULL && recv_new == BUFF_FULL) { + spin_lock_irq(&raptor.lock); + raptor.recv_need++; + spin_unlock_irq(&raptor.lock); + wake_up(&raptor.wait); + } + + send_buff[i] = send_new; + recv_buff[i] = recv_new; + } + } + + // handle send_queue + send_full = true; + + for (i = 0; i < BUFF_COUNT; i++) { + if (send_buff[i] == BUFF_EMPTY && send_packets[i] == NULL) { + + packet = queue_pop(&raptor.send_queue, false); + + if (packet == NULL) { + send_full = false; + break; + } + + // map page to dma_addr + // write that to hardware + + offset = packet->u_addr & (~PAGE_MASK); + rest = PAGE_SIZE - offset; + + packet->dma_addr = dma_map_page(dev, packet->page, offset, rest, DMA_TO_DEVICE); + + raptor_write(CMD_SEND | (i << 2) | (packet->length << 7), endian64(packet->dma_addr)); + + send_buff[i] = BUFF_ADDR; + send_packets[i] = packet; + } + } + + // handle recv_queue + recv_full = true; + + for (i = 0; i < BUFF_COUNT; i++) { + if (recv_buff[i] == BUFF_FULL && recv_packets[i] == NULL) { + + packet = queue_pop(&raptor.recv_queue, false); + + if (packet == NULL) { + recv_full = false; + break; + } + + // map page to dma_addr + // write that to hardware + + offset = packet->u_addr & (~PAGE_MASK); + rest = PAGE_SIZE - offset; + + packet->dma_addr = dma_map_page(dev, packet->page, offset, rest, DMA_FROM_DEVICE); + + raptor_write(CMD_RECV | (i << 2), endian64(packet->dma_addr)); + + recv_buff[i] = BUFF_ADDR; + recv_packets[i] = packet; + } + } + } + + printk(KERN_INFO "raptor_kthread: stopped\n"); + return 0; +} + +static int pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + if (pci_enable_device(pdev) != 0) + goto error_no_cleanup; + + if (pci_request_region(pdev, RAPTOR_BAR, "raptor") != 0) + goto error_disable_device; + + if ((raptor.bar = pci_ioremap_bar(pdev, RAPTOR_BAR)) == NULL) + goto error_release_region; + + if (pci_enable_msi(pdev) < 0) + goto error_iounmap; + + if (request_irq(pdev->irq, raptor_interrupt, 0, "raptor", NULL) < 0) + goto error_disable_msi; + + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) < 0) + goto error_free_irq; + + if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)) < 0) + goto error_free_irq; + + pci_set_master(pdev); + raptor.pdev = pdev; + + phy_configuration(); + + read_debug(); + + raptor.kthread = kthread_run(raptor_kthread, NULL, "raptor_kthread"); + + if (IS_ERR(raptor.kthread)) + goto error_clear_master; + + printk(KERN_INFO "raptor: pci_probe succes\n"); + + return 0; + +error_clear_master: + pci_clear_master(pdev); +error_free_irq: + free_irq(pdev->irq, NULL); +error_disable_msi: + pci_disable_msi(pdev); +error_iounmap: + iounmap(raptor.bar); +error_release_region: + pci_release_region(pdev, 0); +error_disable_device: + pci_disable_device(pdev); +error_no_cleanup: + raptor.bar = NULL; + raptor.pdev = NULL; + printk(KERN_ALERT "raptor: pci_probe FAILED\n"); + return -1; +} + +static void pci_remove(struct pci_dev *pdev) +{ + printk(KERN_INFO "raptor: pci_remove started...\n"); + + (void)kthread_stop(raptor.kthread); + + pci_clear_master(pdev); + free_irq(pdev->irq, NULL); + pci_disable_msi(pdev); + iounmap(raptor.bar); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + raptor.bar = NULL; + raptor.pdev = NULL; + + printk(KERN_INFO "raptor: pci_remove done\n"); +} + +static pci_ers_result_t pci_error_detected(struct pci_dev *pdev, enum pci_channel_state state) +{ + printk(KERN_ALERT "raptor: pcie error %d\n", state); + + return PCI_ERS_RESULT_RECOVERED; +} + +static int raptor_send(uint64_t count, uint64_t* u_addrs) +{ + uint64_t i; + uint64_t u_addr; + uint16_t bytes; + uint16_t length; + struct page* page; + struct packet* packet; + + for (i = 0; i < count; i++) { + if (copy_from_user(&u_addr, &u_addrs[i], sizeof(u_addr)) != 0) { + printk(KERN_ERR "raptor_send: copy_from_user u_addr failed\n"); + return i; + } + + if (copy_from_user(&bytes, (void*)u_addr, sizeof(bytes)) != 0) { + printk(KERN_ERR "raptor_send: copy_from_user bytes failed\n"); + return i; + } + + if (get_user_pages_fast(u_addr, 1, false, &page) != 1) { + printk(KERN_ERR "raptor_send: get_user_pages_fast failed\n"); + return i; + } + + packet = queue_pop(&raptor.send_free_queue, true); + + if (packet == NULL) { + printk(KERN_ERR "raptor_send: queue_pop send_free_queue failed\n"); + put_page(page); + return i; + } + + length = (bytes >> 3); + + if (bytes & 0x7) + length += 1; + + packet->u_addr = u_addr; + packet->length = length; + packet->page = page; + + queue_push(&raptor.send_queue, packet); + } + return count; +} + +static int raptor_recv(uint64_t count, uint64_t* u_addrs) +{ + uint64_t i; + uint64_t u_addr; + struct page* page; + struct packet* packet; + + for (i = 0; i < count; i++) { + if (copy_from_user(&u_addr, &u_addrs[i], sizeof(u_addr)) != 0) { + printk(KERN_ERR "raptor_recv: copy_from_user u_addr failed\n"); + return i; + } + + if (get_user_pages_fast(u_addr, 1, true, &page) != 1) { + printk(KERN_ERR "raptor_recv: get_user_pages_fast failed\n"); + return i; + } + + packet = queue_pop(&raptor.recv_free_queue, true); + + if (packet == NULL) { + printk(KERN_ERR "raptor_recv: queue_pop recv_free_queue failed\n"); + put_page(page); + return i; + } + + packet->u_addr = u_addr; + packet->page = page; + + queue_push(&raptor.recv_queue, packet); + } + return count; +} + +static int raptor_send_done(uint64_t count, uint64_t* u_addrs) +{ + uint64_t i; + struct packet* packet; + + for (i = 0; i < count; i++) { + packet = queue_pop(&raptor.send_done_queue, i == 0); + + if (packet == NULL) + return i; + + put_page(packet->page); + + if (copy_to_user(&u_addrs[i], &packet->u_addr, sizeof(packet->u_addr)) != 0) { + printk(KERN_ERR "raptor_send_done: copy_to_user u_addr failed\n"); + return i; + } + + queue_push(&raptor.send_free_queue, packet); + } + return count; +} + +static int raptor_recv_done(uint64_t count, uint64_t* u_addrs) +{ + uint64_t i; + struct packet* packet; + + for (i = 0; i < count; i++) { + packet = queue_pop(&raptor.recv_done_queue, i == 0); + + if (packet == NULL) + return i; + + put_page(packet->page); + + if (copy_to_user(&u_addrs[i], &packet->u_addr, sizeof(packet->u_addr)) != 0) { + printk(KERN_ERR "raptor_recv_done: copy_to_user u_addr failed\n"); + return i; + } + + queue_push(&raptor.recv_free_queue, packet); + } + return count; +} + +static int raptor_recv_need(uint64_t count) +{ + uint64_t ret; + + spin_lock_irq(&raptor.lock); + + if (wait_event_interruptible_lock_irq_timeout( + raptor.wait, raptor.recv_need > 0, raptor.lock, HZ) <= 0) { + + spin_unlock_irq(&raptor.lock); + return -1; + } + + if (raptor.recv_need > count) { + ret = count; + raptor.recv_need -= count; + } + else { + ret = raptor.recv_need; + raptor.recv_need = 0; + } + + spin_unlock_irq(&raptor.lock); + return ret; +} + +static int raptor_debug(uint64_t* u_array) +{ + if (copy_to_user(&u_array[0], &raptor.int_count, sizeof(uint64_t)) || + copy_to_user(&u_array[1], &raptor.send_busy, sizeof(uint64_t)) || + copy_to_user(&u_array[2], &raptor.recv_busy, sizeof(uint64_t))) { + + printk(KERN_ERR "raptor_debug: copy_to_user failed\n"); + return -1; + } + + raptor.int_count = 0; + raptor.send_busy = 0; + raptor.recv_busy = 0; + + return 0; +} + + +static long raptor_ioctl(struct file * file, unsigned int cmd, unsigned long arg) +{ + uint64_t type = cmd & 0xFFFF0000; + uint64_t count = cmd & 0x0000FFFF; + + if (raptor.bar == NULL) { + printk(KERN_ERR "raptor: no pcie device\n"); + return -1; + } + + switch (type) { + case IOCTL_SEND: + return raptor_send(count, (uint64_t*)arg); + case IOCTL_RECV: + return raptor_recv(count, (uint64_t*)arg); + case IOCTL_SEND_DONE: + return raptor_send_done(count, (uint64_t*)arg); + case IOCTL_RECV_DONE: + return raptor_recv_done(count, (uint64_t*)arg); + case IOCTL_RECV_NEED: + return raptor_recv_need(count); + case IOCTL_DEBUG: + return raptor_debug((uint64_t*)arg); + default: + printk(KERN_ERR "raptor: unknown ioctl\n"); + return -1; + } +} + +static struct pci_device_id pci_id_table[] = { + {PCI_DEVICE(RAPTOR_VENDOR_ID, RAPTOR_DEVICE_ID)}, + {0} +}; +MODULE_DEVICE_TABLE(pci, pci_id_table); + +static struct pci_error_handlers pci_err_handlers = { + .error_detected = pci_error_detected +}; + +static struct pci_driver pci_driver = { + .name = "raptor", + .id_table = pci_id_table, + .probe = pci_probe, + .remove = pci_remove, + .err_handler = &pci_err_handlers +}; + +static struct file_operations raptor_fops = { + .unlocked_ioctl = raptor_ioctl, +}; + +int init_module(void) +{ + int i; + + printk(KERN_INFO "raptor: inserting module...\n"); + + memset(&raptor, 0, sizeof(raptor)); + + spin_lock_init(&raptor.lock); + init_waitqueue_head(&raptor.wait); + + raptor.send_packets = kmalloc(PACKET_COUNT * sizeof(struct packet), GFP_KERNEL); + raptor.recv_packets = kmalloc(PACKET_COUNT * sizeof(struct packet), GFP_KERNEL); + + if (raptor.send_packets == NULL || raptor.recv_packets == NULL) { + printk(KERN_ERR "raptor: failed to allocate packets\n"); + return -1; + } + + for (i = 0; i < PACKET_COUNT; i++) { + queue_push(&raptor.send_free_queue, &raptor.send_packets[i]); + queue_push(&raptor.recv_free_queue, &raptor.recv_packets[i]); + } + + if (alloc_chrdev_region(&raptor.base, 0, 1, "raptor") < 0) { + printk(KERN_ERR "raptor: alloc_chrdev_region failed\n"); + return -1; + } + + raptor.class = class_create(THIS_MODULE, "raptor"); + + if (IS_ERR(raptor.class)) { + printk(KERN_ERR "raptor: class_create failed\n"); + return -1; + } + + raptor.dev = MKDEV(MAJOR(raptor.base), 0); + + raptor.device = device_create(raptor.class, NULL, raptor.dev, NULL, "raptor"); + + if (IS_ERR(raptor.device)) { + printk(KERN_ERR "raptor: device_create failed\n"); + return -1; + } + + cdev_init(&raptor.cdev, &raptor_fops); + + if (cdev_add(&raptor.cdev, raptor.dev, 1) < 0) { + printk(KERN_ERR "raptor: cdev_add failed\n"); + return -1; + } + + if (pci_register_driver(&pci_driver) != 0) { + printk(KERN_ALERT "raptor: pci driver NOT loaded\n"); + return -1; + } + + printk(KERN_INFO "raptor: module inserted\n"); + + return 0; +} + +void cleanup_module(void) +{ + printk(KERN_INFO "raptor: removing module...\n"); + + pci_unregister_driver(&pci_driver); + + cdev_del(&raptor.cdev); + device_destroy(raptor.class, raptor.dev); + + class_destroy(raptor.class); + unregister_chrdev_region(raptor.base, 1); + + kfree(raptor.send_packets); + kfree(raptor.recv_packets); + + memset(&raptor, 0, sizeof(raptor)); + + printk(KERN_INFO "raptor: module removed\n"); +} diff --git a/netfpga10g/constraints.ucf b/netfpga10g/constraints.ucf new file mode 100644 index 0000000..9f16110 --- /dev/null +++ b/netfpga10g/constraints.ucf @@ -0,0 +1,52 @@ + +CONFIG PART = xc5vtx240tff1759-2; + +NET "clk25" LOC = "AJ25" | IOSTANDARD = LVCMOS33; +NET "clk100" LOC = "AN25" | IOSTANDARD = LVCMOS33; + +NET "clk25" TNM_NET=TNM_NET_CLK25; +TIMESPEC TS_CLK25 = PERIOD TNM_NET_CLK25 25 MHz; + +NET "clk100" TNM_NET=TNM_NET_CLK100; +TIMESPEC TS_CLK100 = PERIOD TNM_NET_CLK100 100 MHz; + +NET "led1" LOC = "AK25" | IOSTANDARD = LVCMOS33; +NET "led2" LOC = "AM24" | IOSTANDARD = LVCMOS33; +NET "led3" LOC = "AP20" | IOSTANDARD = LVCMOS33; + +# PCI express +NET "pcie_clk_p" LOC = "AT4"; +NET "pcie_clk_n" LOC = "AT3"; +INST "pcie_wrapper/pcie_clk_ibuf" DIFF_TERM = "TRUE"; + +INST "pcie_wrapper/ep/pcie_ep0/pcie_blk/SIO/.pcie_gt_wrapper_i/GTD[0].GT_i" LOC = GTX_DUAL_X1Y5; +INST "pcie_wrapper/ep/pcie_ep0/pcie_blk/SIO/.pcie_gt_wrapper_i/GTD[2].GT_i" LOC = GTX_DUAL_X1Y4; +INST "pcie_wrapper/ep/pcie_ep0/pcie_blk/SIO/.pcie_gt_wrapper_i/GTD[4].GT_i" LOC = GTX_DUAL_X1Y3; +INST "pcie_wrapper/ep/pcie_ep0/pcie_blk/SIO/.pcie_gt_wrapper_i/GTD[6].GT_i" LOC = GTX_DUAL_X1Y2; + +NET "clk125" TNM_NET=TNM_NET_CLK125; +TIMESPEC TS_CLK125 = PERIOD TNM_NET_CLK125 125 MHz; + +# mdio + +NET "phy_reset_n" LOC = "AR20" | IOSTANDARD = LVCMOS33; +NET "mdc" LOC = "AK23" | IOSTANDARD = LVCMOS33; +NET "mdio" LOC = "AL20" | IOSTANDARD = LVCMOS33; + +# xaui + +NET "xaui/txoutclk" TNM_NET="clk156_top"; +TIMESPEC "TS_clk156_top" = PERIOD "clk156_top" 156.25 MHz; + +NET "clk50" TNM_NET=DCLK_CLK; +TIMESPEC TS_DCLK_CLK = PERIOD DCLK_CLK 50 MHz; + +NET *xaui_block/rocketio_wrapper_i/tile1_rxrecclk0_i TNM_NET=clk156_rec; +TIMESPEC TS_clk156_rec = PERIOD clk156_rec 156.25MHz; + +INST xaui/xaui_block/rocketio_wrapper_i/tile0_xaui_v10_4_rocketio_wrapper_i/YES_REVERSE_LANES.gtx_dual_i LOC=GTX_DUAL_X1Y6; +INST xaui/xaui_block/rocketio_wrapper_i/tile1_xaui_v10_4_rocketio_wrapper_i/YES_REVERSE_LANES.gtx_dual_i LOC=GTX_DUAL_X1Y7; + +NET "xaui0_clk_p" LOC = "M4" ; +NET "xaui0_clk_n" LOC = "M3" ; + diff --git a/netfpga10g/hdl/buff.vhd b/netfpga10g/hdl/buff.vhd new file mode 100644 index 0000000..39b3a80 --- /dev/null +++ b/netfpga10g/hdl/buff.vhd @@ -0,0 +1,192 @@ + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; +library UNISIM; +use UNISIM.VComponents.all; + +entity buff is + Port ( wr_clk : in STD_LOGIC; + wr_en : in STD_LOGIC; + wr_data : in STD_LOGIC_VECTOR (63 downto 0); + wr_done : in STD_LOGIC; + wr_cancel : in std_logic := '0'; + wr_accept : out STD_LOGIC; + rd_clk : in STD_LOGIC; + rd_en : in STD_LOGIC; + rd_data : out STD_LOGIC_VECTOR (63 downto 0) := (others => '0'); + rd_length : out STD_LOGIC_VECTOR (8 downto 0) := (others => '0'); + rd_valid : out STD_LOGIC := '0'); +end buff; + +architecture arch of buff is + + COMPONENT ram_4kB + PORT ( + clka : IN STD_LOGIC; + wea : IN STD_LOGIC_VECTOR(0 DOWNTO 0); + addra : IN STD_LOGIC_VECTOR(8 DOWNTO 0); + dina : IN STD_LOGIC_VECTOR(63 DOWNTO 0); + clkb : IN STD_LOGIC; + addrb : IN STD_LOGIC_VECTOR(8 DOWNTO 0); + doutb : OUT STD_LOGIC_VECTOR(63 DOWNTO 0) + ); + END COMPONENT; + + signal ram_wr_en : std_logic_vector(0 downto 0); + signal ram_wr_addr : std_logic_vector(8 downto 0); + signal ram_wr_data : std_logic_vector(63 downto 0); + + signal ram_rd_addr : std_logic_vector(8 downto 0); + signal ram_rd_data : std_logic_vector(63 downto 0); + + constant W1 : std_logic_vector(1 downto 0) := "00"; + constant W2 : std_logic_vector(1 downto 0) := "11"; + constant R1 : std_logic_vector(1 downto 0) := "01"; + constant R2 : std_logic_vector(1 downto 0) := "10"; + + signal wr_owner : std_logic_vector(1 downto 0) := W1; + signal rd_owner : std_logic_vector(1 downto 0) := W1; + signal wr_owner_tmp : std_logic_vector(1 downto 0) := W1; + signal wr_owner_sync : std_logic_vector(1 downto 0) := W1; + + -- MAX: 256 bytes less than 4kB, for ouroboros + -- 4kB = 512 x 64 bits + -- 256 bytes = 32 x 64 bits + -- 512 - 32 = 480 + -- 480 = "111100000" + + constant MAX : std_logic_vector(8 downto 0) := "111100000"; + constant ZERO : std_logic_vector(8 downto 0) := "000000000"; + constant ONE : std_logic_vector(8 downto 0) := "000000001"; + + type state_t is (state_empty, state_wait, state_full, state_first, state_valid); + + signal rd_state : state_t := state_empty; + signal rd_addr : std_logic_vector(8 downto 0) := MAX; + +begin + + ram : ram_4kB + PORT MAP ( + clka => wr_clk, + wea => ram_wr_en, + addra => ram_wr_addr, + dina => ram_wr_data, + clkb => rd_clk, + addrb => ram_rd_addr, + doutb => ram_rd_data + ); + + wr_accept <= '1' when (wr_owner = W1 or wr_owner = W2) and wr_done = '0' and wr_cancel = '0' else '0'; + + process (wr_clk) + variable wr_count : std_logic_vector(8 downto 0) := ZERO; + begin + if rising_edge(wr_clk) then + ram_wr_en(0) <= '0'; + ram_wr_addr <= (others => '0'); + ram_wr_data <= (others => '0'); + + if wr_owner = W1 or wr_owner = W2 then + if wr_cancel = '1' then + wr_count := ZERO; + + elsif wr_done = '1' then + if wr_count /= ZERO then + if wr_owner = W1 then + wr_owner <= R1; + ram_wr_data(1 downto 0) <= R1; + else + wr_owner <= R2; + ram_wr_data(1 downto 0) <= R2; + end if; + + ram_wr_en(0) <= '1'; + ram_wr_addr <= MAX; + ram_wr_data(10 downto 2) <= wr_count; + wr_count := ZERO; + end if; + + elsif wr_en = '1' then + if wr_count /= MAX then + ram_wr_en(0) <= '1'; + ram_wr_addr <= wr_count; + ram_wr_data <= wr_data; + wr_count := std_logic_vector(unsigned(wr_count) + 1); + end if; + end if; + elsif wr_owner = R1 then + if wr_owner_sync = W2 then + wr_owner <= W2; + end if; + elsif wr_owner = R2 then + if wr_owner_sync = W1 then + wr_owner <= W1; + end if; + end if; + + wr_owner_tmp <= rd_owner; + wr_owner_sync <= wr_owner_tmp; + end if; + end process; + + ram_rd_addr <= std_logic_vector(unsigned(rd_addr) + 1) + when rd_state = state_valid and rd_en = '1' + else rd_addr; + + process (rd_clk) + variable rd_count : std_logic_vector(8 downto 0) := ZERO; + variable tmp : std_logic_vector(1 downto 0); + begin + if rising_edge(rd_clk) then + if rd_state = state_empty then + rd_state <= state_wait; + + elsif rd_state = state_wait then + tmp := ram_rd_data(1 downto 0); + + if (rd_owner = W1 and tmp = R1) or + (rd_owner = W2 and tmp = R2) then + + rd_state <= state_full; + rd_addr <= ZERO; + rd_count := ram_rd_data(10 downto 2); + rd_owner <= tmp; + end if; + + elsif rd_state = state_full then + rd_state <= state_first; + rd_addr <= ONE; + + elsif rd_state = state_first then + rd_state <= state_valid; + rd_valid <= '1'; + rd_data <= ram_rd_data; + rd_length <= rd_count; + + elsif rd_state = state_valid then + if rd_en = '1' then + if rd_addr = rd_count then + rd_state <= state_empty; + rd_addr <= MAX; + rd_valid <= '0'; + rd_data <= (others => '0'); + rd_length <= ZERO; + rd_count := ZERO; + + if rd_owner = R1 then + rd_owner <= W2; + else + rd_owner <= W1; + end if; + else + rd_addr <= ram_rd_addr; + rd_data <= ram_rd_data; + end if; + end if; + end if; + end if; + end process; +end arch; + diff --git a/netfpga10g/hdl/dma.vhd b/netfpga10g/hdl/dma.vhd new file mode 100644 index 0000000..4c7e4f8 --- /dev/null +++ b/netfpga10g/hdl/dma.vhd @@ -0,0 +1,640 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity dma is +generic ( + BITS : integer := 14 +); +port ( + clk : in std_logic; + reset : in std_logic; + + rx_read : in std_logic; + rx_write : in std_logic; + rx_complete : in std_logic; + rx_data : in std_logic_vector(63 downto 0); + rx_address : in std_logic_vector(28 downto 0); + + tx_read : out std_logic; + tx_write : out std_logic; + tx_complete : out std_logic; + tx_data : out std_logic_vector(63 downto 0); + tx_address : out std_logic_vector(28 downto 0); + tx_length : out std_logic_vector(8 downto 0); + tx_accept : in std_logic; + tx_done : in std_logic; + + port0_read : out std_logic; + port0_rd_data : in std_logic_vector(63 downto 0); + port0_rd_empty : in std_logic; + port0_rd_count : in std_logic_vector(BITS downto 0); + + port0_write : out std_logic; + port0_wr_data : out std_logic_vector(63 downto 0); + port0_wr_full : in std_logic; + port0_wr_count : in std_logic_vector(BITS downto 0); + + port1_read : out std_logic; + port1_rd_data : in std_logic_vector(63 downto 0); + port1_rd_empty : in std_logic; + port1_rd_count : in std_logic_vector(BITS downto 0); + + port1_write : out std_logic; + port1_wr_data : out std_logic_vector(63 downto 0); + port1_wr_full : in std_logic; + port1_wr_count : in std_logic_vector(BITS downto 0); + + port2_read : out std_logic; + port2_rd_data : in std_logic_vector(63 downto 0); + port2_rd_empty : in std_logic; + port2_rd_count : in std_logic_vector(BITS downto 0); + + port2_write : out std_logic; + port2_wr_data : out std_logic_vector(63 downto 0); + port2_wr_full : in std_logic; + port2_wr_count : in std_logic_vector(BITS downto 0); + + port3_read : out std_logic; + port3_rd_data : in std_logic_vector(63 downto 0); + port3_rd_empty : in std_logic; + port3_rd_count : in std_logic_vector(BITS downto 0); + + port3_write : out std_logic; + port3_wr_data : out std_logic_vector(63 downto 0); + port3_wr_full : in std_logic; + port3_wr_count : in std_logic_vector(BITS downto 0); + + max_read : in std_logic_vector(2 downto 0); + max_write : in std_logic_vector(2 downto 0); + + interrupt : out std_logic; + interrupt_rdy : in std_logic; + + mdio_command : out std_logic_vector(0 to 27); + mdio_data : in std_logic_vector(0 to 15); + mdio_enable : out std_logic; + mdio_done : in std_logic; + + leds : out std_logic_vector(2 downto 0) +); +end dma; + +architecture arch of dma is + type state_t is (state_idle, state_tx_read, state_tx_write, state_tx_complete, state_rx_complete, + state_dma_read, state_dma_write, state_interrupt, state_command, + state_test_write_head, state_test_write, + state_test_read_head, state_test_read, state_test_complete, + state_mdio); + signal state : state_t; + + signal fifo_read : std_logic; + signal fifo_write : std_logic; + signal fifo_din : std_logic_vector(63 downto 0); + signal fifo_dout : std_logic_vector(63 downto 0); + signal fifo_full : std_logic; + signal fifo_empty : std_logic; + signal fifo_count : std_logic_vector(BITS downto 0); + + component simple_fifo port ( + clk : in std_logic; + rst : in std_logic; + rd_en : in std_logic; + wr_en : in std_logic; + din : in std_logic_vector(63 downto 0); + dout : out std_logic_vector(63 downto 0); + full : out std_logic; + empty : out std_logic; + data_count : out std_logic_vector(BITS downto 0) + ); + end component; + + signal cmd_read : std_logic; + signal cmd_write : std_logic; + signal cmd_din : std_logic_vector(63 downto 0); + signal cmd_dout : std_logic_vector(63 downto 0); + signal cmd_full : std_logic; + signal cmd_empty : std_logic; + + component cmd_fifo port ( + clk : in std_logic; + rst : in std_logic; + rd_en : in std_logic; + wr_en : in std_logic; + din : in std_logic_vector(63 downto 0); + dout : out std_logic_vector(63 downto 0); + full : out std_logic; + empty : out std_logic + ); + end component; + + signal test_completion : std_logic_vector(63 downto 0); +begin + process (clk, reset) + variable bar_addr : unsigned(BITS downto 0); + variable dma_addr : unsigned(28 downto 0); + variable length : unsigned(BITS downto 0); + variable remain : unsigned(BITS downto 0); + variable cycles : unsigned(BITS downto 0); + variable backup_addr : unsigned(28 downto 0); + variable backup_length : unsigned(BITS downto 0); + begin + if reset = '1' then + state <= state_idle; + tx_read <= '0'; + tx_write <= '0'; + tx_complete <= '0'; + tx_data <= (others => '0'); + tx_address <= (others => '0'); + tx_length <= (others => '0'); + fifo_read <= '0'; + fifo_write <= '0'; + fifo_din <= (others => '0'); + interrupt <= '0'; + cmd_read <= '0'; + cmd_write <= '0'; + cmd_din <= (others => '0'); + test_completion <= (others => '0'); + port0_read <= '0'; + port0_write <= '0'; + port0_wr_data <= (others => '0'); + port1_read <= '0'; + port1_write <= '0'; + port1_wr_data <= (others => '0'); + port2_read <= '0'; + port2_write <= '0'; + port2_wr_data <= (others => '0'); + port3_read <= '0'; + port3_write <= '0'; + port3_wr_data <= (others => '0'); + mdio_enable <= '0'; + mdio_command <= (others => '0'); + + elsif rising_edge(clk) then + fifo_read <= '0'; + fifo_write <= '0'; + fifo_din <= (others => '0'); + cmd_read <= '0'; + cmd_write <= '0'; + cmd_din <= (others => '0'); + port0_read <= '0'; + port0_write <= '0'; + port1_read <= '0'; + port1_write <= '0'; + port2_read <= '0'; + port2_write <= '0'; + port3_read <= '0'; + port3_write <= '0'; + + -- bar read + if state = state_idle and rx_read = '1' then + state <= state_tx_complete; + tx_complete <= '1'; + tx_data <= (others => '0'); + tx_address <= rx_address; + bar_addr := unsigned(rx_address(BITS downto 0)); + + -- read fifo + if bar_addr = 0 then + if fifo_empty = '1' then + tx_data <= (others => '1'); + else + tx_data <= fifo_dout; + fifo_read <= '1'; + end if; + + -- read command + elsif bar_addr = 1 then + if cmd_empty = '1' then + tx_data <= (others => '1'); + else + tx_data <= cmd_dout; + cmd_read <= '1'; + end if; + + -- other + elsif bar_addr = 3 then + tx_data(BITS downto 0) <= fifo_count; + + elsif bar_addr = 4 then + tx_data(2 downto 0) <= max_read; + + elsif bar_addr = 5 then + tx_data(2 downto 0) <= max_write; + + elsif bar_addr = 6 then + tx_data <= test_completion; + + -- read ports + elsif bar_addr = 10 then + if port0_rd_empty = '1' then + tx_data <= (others => '1'); + else + tx_data <= port0_rd_data; + port0_read <= '1'; + end if; + + elsif bar_addr = 11 then + if port1_rd_empty = '1' then + tx_data <= (others => '1'); + else + tx_data <= port1_rd_data; + port1_read <= '1'; + end if; + + elsif bar_addr = 12 then + if port2_rd_empty = '1' then + tx_data <= (others => '1'); + else + tx_data <= port2_rd_data; + port2_read <= '1'; + end if; + + elsif bar_addr = 13 then + if port3_rd_empty = '1' then + tx_data <= (others => '1'); + else + tx_data <= port3_rd_data; + port3_read <= '1'; + end if; + + -- read counts + elsif bar_addr = 20 then + tx_data(BITS downto 0) <= port0_rd_count; + + elsif bar_addr = 21 then + tx_data(BITS downto 0) <= port0_wr_count; + + elsif bar_addr = 22 then + tx_data(BITS downto 0) <= port1_rd_count; + + elsif bar_addr = 23 then + tx_data(BITS downto 0) <= port1_wr_count; + + elsif bar_addr = 24 then + tx_data(BITS downto 0) <= port2_rd_count; + + elsif bar_addr = 25 then + tx_data(BITS downto 0) <= port2_wr_count; + + elsif bar_addr = 26 then + tx_data(BITS downto 0) <= port3_rd_count; + + elsif bar_addr = 27 then + tx_data(BITS downto 0) <= port3_wr_count; + + -- read mdio + elsif bar_addr = 30 then + tx_data(15 downto 0) <= mdio_data; + end if; + + elsif state = state_tx_complete then + if tx_done = '1' then + state <= state_idle; + end if; + + -- bar write + elsif state = state_idle and rx_write = '1' then + bar_addr := unsigned(rx_address(BITS downto 0)); + + -- write fifo + if bar_addr = 0 then + if fifo_full = '0' then + fifo_din <= rx_data; + fifo_write <= '1'; + end if; + + -- write command + elsif bar_addr = 1 then + if cmd_full = '0' then + cmd_din <= rx_data; + cmd_write <= '1'; + end if; + + if rx_data(0) = '1' then + state <= state_command; + end if; + + -- write test + elsif bar_addr = 2 then + dma_addr := unsigned(rx_data(31 downto 3)); + length := unsigned(rx_data(BITS+32 downto 32)); + cycles := unsigned(rx_data(BITS+48 downto 48)); + backup_addr := dma_addr; + backup_length := length; + + if rx_data(1) = '0' then + state <= state_test_read_head; + else + state <= state_test_write_head; + end if; + + -- write ports + elsif bar_addr = 10 then + if port0_wr_full = '0' then + port0_wr_data <= rx_data; + port0_write <= '1'; + end if; + + elsif bar_addr = 11 then + if port1_wr_full = '0' then + port1_wr_data <= rx_data; + port1_write <= '1'; + end if; + + elsif bar_addr = 12 then + if port2_wr_full = '0' then + port2_wr_data <= rx_data; + port2_write <= '1'; + end if; + + elsif bar_addr = 13 then + if port3_wr_full = '0' then + port3_wr_data <= rx_data; + port3_write <= '1'; + end if; + + -- write mdio + elsif bar_addr = 30 then + state <= state_mdio; + mdio_enable <= '1'; + mdio_command <= rx_data(27 downto 0); + end if; + + -- mdio + elsif state = state_mdio then + if mdio_done = '1' then + mdio_enable <= '0'; + state <= state_interrupt; + interrupt <= '1'; + end if; + + -- test read + elsif state = state_test_read_head then + remain := 16 - resize(dma_addr(3 downto 0), remain'length); + + if max_read = "001" then + remain := 32 - resize(dma_addr(4 downto 0), remain'length); + elsif max_read = "010" then + remain := 64 - resize(dma_addr(5 downto 0), remain'length); + elsif max_read = "011" then + remain := 128 - resize(dma_addr(6 downto 0), remain'length); + elsif max_read = "100" then + remain := 256 - resize(dma_addr(7 downto 0), remain'length); + elsif max_read = "101" then + remain := 512 - resize(dma_addr(8 downto 0), remain'length); + end if; + + if remain > length then + remain := length; + end if; + + state <= state_test_read; + tx_read <= '1'; + tx_address <= std_logic_vector(dma_addr); + tx_length <= std_logic_vector(remain(8 downto 0)); + length := length - remain; + dma_addr := dma_addr + remain; + + elsif state = state_test_read then + if tx_done = '1' then + state <= state_test_complete; + end if; + + elsif state = state_test_complete then + if rx_complete = '1' then + test_completion <= rx_data; + remain := remain - 1; + + if remain = 0 then + if length > 0 then + state <= state_test_read_head; + + elsif cycles > 1 then + state <= state_test_read_head; + dma_addr := backup_addr; + length := backup_length; + cycles := cycles - 1; + else + state <= state_interrupt; + interrupt <= '1'; + end if; + end if; + end if; + + -- test write + elsif state = state_test_write_head then + remain := 16 - resize(dma_addr(3 downto 0), remain'length); + + if max_write = "001" then + remain := 32 - resize(dma_addr(4 downto 0), remain'length); + elsif max_write = "010" then + remain := 64 - resize(dma_addr(5 downto 0), remain'length); + elsif max_write = "011" then + remain := 128 - resize(dma_addr(6 downto 0), remain'length); + elsif max_write = "100" then + remain := 256 - resize(dma_addr(7 downto 0), remain'length); + elsif max_write = "101" then + remain := 512 - resize(dma_addr(8 downto 0), remain'length); + end if; + + if remain > length then + remain := length; + end if; + + state <= state_test_write; + tx_write <= '1'; + tx_data <= x"FFEEDDCC00000000"; + tx_address <= std_logic_vector(dma_addr); + tx_length <= std_logic_vector(remain(8 downto 0)); + length := length - remain; + dma_addr := dma_addr + remain; + + elsif state = state_test_write then + if tx_done = '1' then + if length > 0 then + state <= state_test_write_head; + + elsif cycles > 1 then + state <= state_test_write_head; + dma_addr := backup_addr; + length := backup_length; + cycles := cycles - 1; + else + state <= state_interrupt; + interrupt <= '1'; + end if; + end if; + + -- command + elsif state = state_command then + if cmd_empty = '1' then + state <= state_interrupt; + interrupt <= '1'; + else + cmd_read <= '1'; + + if cmd_dout(1) = '0' then + state <= state_dma_read; + dma_addr := unsigned(cmd_dout(31 downto 3)); + length := unsigned(cmd_dout(BITS+32 downto 32)); + fifo_din <= std_logic_vector(resize(length, fifo_din'length)); + fifo_write <= '1'; + else + state <= state_dma_write; + dma_addr := unsigned(cmd_dout(31 downto 3)); + length := unsigned(fifo_dout(BITS downto 0)) + 1; + end if; + end if; + + elsif state = state_interrupt then + if interrupt_rdy = '1' then + state <= state_idle; + interrupt <= '0'; + end if; + + -- dma read + elsif state = state_dma_read then + remain := 16 - resize(dma_addr(3 downto 0), remain'length); + + if max_read = "001" then + remain := 32 - resize(dma_addr(4 downto 0), remain'length); + elsif max_read = "010" then + remain := 64 - resize(dma_addr(5 downto 0), remain'length); + elsif max_read = "011" then + remain := 128 - resize(dma_addr(6 downto 0), remain'length); + elsif max_read = "100" then + remain := 256 - resize(dma_addr(7 downto 0), remain'length); + elsif max_read = "101" then + remain := 512 - resize(dma_addr(8 downto 0), remain'length); + end if; + + if remain > length then + remain := length; + end if; + + state <= state_tx_read; + tx_read <= '1'; + tx_address <= std_logic_vector(dma_addr); + tx_length <= std_logic_vector(remain(8 downto 0)); + length := length - remain; + dma_addr := dma_addr + remain; + + elsif state = state_tx_read then + if tx_done = '1' then + state <= state_rx_complete; + end if; + + elsif state = state_rx_complete then + if rx_complete = '1' then + fifo_din <= rx_data; + fifo_write <= '1'; + remain := remain - 1; + + if remain = 0 then + if length > 0 then + state <= state_dma_read; + else + state <= state_command; + end if; + end if; + end if; + + -- dma write + elsif state = state_dma_write then + remain := 16 - resize(dma_addr(3 downto 0), remain'length); + + if max_write = "001" then + remain := 32 - resize(dma_addr(4 downto 0), remain'length); + elsif max_write = "010" then + remain := 64 - resize(dma_addr(5 downto 0), remain'length); + elsif max_write = "011" then + remain := 128 - resize(dma_addr(6 downto 0), remain'length); + elsif max_write = "100" then + remain := 256 - resize(dma_addr(7 downto 0), remain'length); + elsif max_write = "101" then + remain := 512 - resize(dma_addr(8 downto 0), remain'length); + end if; + + if remain > length then + remain := length; + end if; + + state <= state_tx_write; + tx_write <= '1'; + tx_data <= fifo_dout; + tx_address <= std_logic_vector(dma_addr); + tx_length <= std_logic_vector(remain(8 downto 0)); + fifo_read <= '1'; + length := length - remain; + dma_addr := dma_addr + remain; + remain := remain - 1; + + elsif state = state_tx_write then + if tx_done = '1' then + if length > 0 then + state <= state_dma_write; + else + state <= state_command; + end if; + + elsif tx_accept = '1' and remain > 0 then + tx_data <= fifo_dout; + fifo_read <= '1'; + remain := remain - 1; + end if; + end if; + + if tx_done = '1' then + tx_read <= '0'; + tx_write <= '0'; + tx_complete <= '0'; + tx_data <= (others => '0'); + tx_address <= (others => '0'); + tx_length <= (others => '0'); + end if; + end if; + end process; + + fifo : entity work.port_fifo port map ( + reset => reset, + + rd_clk => clk, + rd_read => fifo_read, + rd_data => fifo_dout, + rd_empty => fifo_empty, + rd_count => fifo_count, + + wr_write => fifo_write, + wr_data => fifo_din, + wr_full => fifo_full + --wr_count => wr_count + ); + + commands : cmd_fifo port map ( + clk => clk, + rst => reset, + rd_en => cmd_read, + wr_en => cmd_write, + din => cmd_din, + dout => cmd_dout, + full => cmd_full, + empty => cmd_empty + ); + + leds <= "000" when state = state_idle else + -- bar read + "001" when state = state_tx_complete else + -- dma read + "010" when state = state_dma_read or state = state_tx_read or state = state_rx_complete else + -- dma write + "011" when state = state_dma_write or state = state_tx_write else + -- mdio + "100" when state = state_mdio else + -- interrupt + "101" when state = state_interrupt else + -- other + "111"; +end arch; + diff --git a/netfpga10g/hdl/engine.vhd b/netfpga10g/hdl/engine.vhd new file mode 100644 index 0000000..16f0a8b --- /dev/null +++ b/netfpga10g/hdl/engine.vhd @@ -0,0 +1,570 @@ + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; +library UNISIM; +use UNISIM.VComponents.all; + +entity engine is +generic ( + BUFF_COUNT : integer := 16; + BUFF_BITS : integer := 4; -- 2^4 = 16 + BAR_BITS : integer := 17; + TIME_BITS : integer := 20 +); +port ( + clk : in STD_LOGIC; + + rd_buff : out STD_LOGIC_VECTOR (BUFF_BITS - 1 downto 0) := (others => '0'); + rd_en : out STD_LOGIC := '0'; + rd_data : in STD_LOGIC_VECTOR (63 downto 0); + rd_length : in STD_LOGIC_VECTOR (8 downto 0); + rd_valid : in STD_LOGIC_VECTOR (BUFF_COUNT - 1 downto 0); + + wr_buff : out STD_LOGIC_VECTOR (BUFF_BITS - 1 downto 0) := (others => '0'); + wr_en : out STD_LOGIC := '0'; + wr_data : out STD_LOGIC_VECTOR (63 downto 0) := (others => '0'); + wr_done : out STD_LOGIC := '0'; + wr_cancel : out STD_LOGIC_VECTOR (BUFF_COUNT - 1 downto 0); + wr_accept : in STD_LOGIC_VECTOR (BUFF_COUNT - 1 downto 0); + + rx_read : in STD_LOGIC; + rx_write : in STD_LOGIC; + rx_complete : in STD_LOGIC; + rx_data : in STD_LOGIC_VECTOR (63 downto 0); + rx_address : in STD_LOGIC_VECTOR (63 downto 3); + rx_tag : in std_logic_vector(4 downto 0); + + tx_read : out STD_LOGIC := '0'; + tx_write : out STD_LOGIC := '0'; + tx_complete : out STD_LOGIC := '0'; + tx_data : out STD_LOGIC_VECTOR (63 downto 0) := (others => '0'); + tx_address : out STD_LOGIC_VECTOR (63 downto 3) := (others => '0'); + tx_length : out STD_LOGIC_VECTOR (8 downto 0) := (others => '0'); + tx_tag : out std_logic_vector(4 downto 0) := (others => '0'); + tx_accept : in STD_LOGIC; + tx_done : in STD_LOGIC; + + interrupt : out std_logic := '0'; + interrupt_rdy : in std_logic; + + max_read : in std_logic_vector(2 downto 0); + max_write : in std_logic_vector(2 downto 0); + + mdio_command : out std_logic_vector(0 to 27) := (others => '0'); + mdio_data : in std_logic_vector(0 to 15); + mdio_enable : out std_logic := '0'; + mdio_done : in std_logic +); +end engine; + +architecture arch of engine is + + constant BUFF_EMPTY : std_logic_vector(1 downto 0) := "00"; + constant BUFF_ADDR : std_logic_vector(1 downto 0) := "01"; + constant BUFF_DATA : std_logic_vector(1 downto 0) := "10"; + constant BUFF_FULL : std_logic_vector(1 downto 0) := "11"; + + type buff_t is array (0 to BUFF_COUNT - 1) of std_logic_vector(1 downto 0); + type length_t is array (0 to BUFF_COUNT - 1) of unsigned(8 downto 0); + type address_t is array (0 to BUFF_COUNT - 1) of unsigned(63 downto 3); + type time_t is array (0 to BUFF_COUNT - 1) of unsigned(TIME_BITS - 1 downto 0); + + type rx_state_t is (rx_state_idle, rx_state_write_done, rx_state_mdio); + type tx_state_t is (tx_state_idle, tx_state_read, tx_state_write, + tx_state_complete, tx_state_interrupt); + + signal rx_state : rx_state_t := rx_state_idle; + signal tx_state : tx_state_t := tx_state_idle; + + signal tx_data_i : std_logic_vector(63 downto 0) := (others => '0'); + + constant CMD_STATUS : std_logic_vector(1 downto 0) := "00"; + constant CMD_SEND : std_logic_vector(1 downto 0) := "01"; + constant CMD_RECV : std_logic_vector(1 downto 0) := "10"; + constant CMD_MDIO : std_logic_vector(1 downto 0) := "11"; + + signal send_buff : buff_t := (others => BUFF_FULL); + signal send_length : length_t := (others => (others => '0')); + signal send_remain : length_t := (others => (others => '0')); + signal send_address : address_t := (others => (others => '0')); + signal send_read_time : time_t := (others => (others => '0')); + + signal recv_buff : buff_t := (others => BUFF_EMPTY); + signal recv_address0 : unsigned(63 downto 3); + signal recv_address1 : unsigned(63 downto 3); + signal recv_address2 : unsigned(63 downto 3); + signal recv_address3 : unsigned(63 downto 3); + signal recv_address4 : unsigned(63 downto 3); + signal recv_address5 : unsigned(63 downto 3); + signal recv_address6 : unsigned(63 downto 3); + signal recv_address7 : unsigned(63 downto 3); + signal recv_address8 : unsigned(63 downto 3); + signal recv_address9 : unsigned(63 downto 3); + signal recv_address10 : unsigned(63 downto 3); + signal recv_address11 : unsigned(63 downto 3); + signal recv_address12 : unsigned(63 downto 3); + signal recv_address13 : unsigned(63 downto 3); + signal recv_address14 : unsigned(63 downto 3); + signal recv_address15 : unsigned(63 downto 3); + + signal send_int : std_logic := '0'; + signal send_int_needed : std_logic := '0'; + signal send_read : std_logic := '0'; + signal send_read_done : std_logic := '0'; + signal send_read_buff : integer range 0 to BUFF_COUNT - 1 := 0; + signal send_read_length : unsigned(8 downto 0); + signal send_read_remain : unsigned(8 downto 0); + signal send_read_address : unsigned(63 downto 3); + signal send_write : std_logic := '0'; + signal send_write_new : std_logic := '0'; + signal send_write_buff : integer range 0 to BUFF_COUNT - 1 := 0; + signal send_write_length : unsigned(8 downto 0); + signal send_write_address : unsigned(63 downto 3); + + signal debug_address : std_logic_vector(63 downto 3) := (others => '0'); + signal debug_data : std_logic_vector(63 downto 0) := (others => '0'); + signal debug_cmd : std_logic_vector(1 downto 0) := (others => '0'); + signal debug_buff : std_logic_vector(BUFF_BITS - 1 downto 0) := (others => '0'); + signal debug_length : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(42, 9)); + + signal debug_cmpl_count : unsigned(7 downto 0) := (others => '0'); + signal debug_cmpl_data : std_logic_vector(63 downto 0) := (others => '0'); + signal debug_cmpl_tag : std_logic_vector(4 downto 0) := (others => '0'); + signal debug_cmpl_state : std_logic_vector(7 downto 0) := x"FF"; + + signal debug_write_count : unsigned(7 downto 0) := (others => '0'); + signal debug_write_length : std_logic_vector(8 downto 0) := (others => '0'); + signal debug_write_addr : std_logic_vector(63 downto 3) := (others => '0'); + signal debug_write_data : std_logic_vector(63 downto 0) := (others => '0'); + + signal debug_accept_count : unsigned(7 downto 0) := (others => '0'); + signal debug_done_count : unsigned(7 downto 0) := (others => '0'); + + signal timer : unsigned(TIME_BITS - 1 downto 0) := (others => '0'); +begin + rd_en <= tx_accept when tx_state = tx_state_write else '0'; + + tx_data <= rd_data when tx_state = tx_state_write else tx_data_i; + + process (clk) + variable bar_read : std_logic := '0'; + variable bar_read_address : std_logic_vector(63 downto 3) := (others => '0'); + + variable tmp_cmd : std_logic_vector(1 downto 0); + variable tmp_buff : integer range 0 to BUFF_COUNT - 1; + variable tmp_length : unsigned(8 downto 0); + variable tmp_remain : unsigned(8 downto 0); + variable tmp_address : unsigned(63 downto 3); + variable tmp_bar : unsigned(BAR_BITS - 1 downto 0); + + -- see 'metered reads' in pcie core manual (xilinx) + -- a maximum of 8 openstanding reads is allowed + constant READ_MAX : unsigned(3 downto 0) := x"8"; + variable read_count : unsigned(3 downto 0) := (others => '0'); + variable read_decr : std_logic; + variable read_incr : std_logic; + begin + if rising_edge(clk) then + wr_en <= '0'; + wr_data <= (others => '0'); + wr_done <= '0'; + wr_cancel <= (others => '0'); + read_decr := '0'; + read_incr := '0'; + + timer <= timer + 1; + + -- ENGINE: RX + if rx_state = rx_state_idle then + if rx_read = '1' then + bar_read := '1'; + bar_read_address := rx_address; + + elsif rx_write = '1' then + tmp_cmd := rx_address(4 downto 3); + tmp_buff := to_integer(unsigned(rx_address(5 + BUFF_BITS - 1 downto 5))); + tmp_length := unsigned(rx_address(18 downto 10)); + tmp_address := unsigned(rx_data(63 downto 3)); + + debug_address <= rx_address; + debug_data <= rx_data; + debug_cmd <= tmp_cmd; + debug_buff <= std_logic_vector(to_unsigned(tmp_buff, debug_buff'length)); + debug_length <= std_logic_vector(tmp_length); + + if tmp_cmd = CMD_SEND then + if send_buff(tmp_buff) = BUFF_EMPTY then + send_buff(tmp_buff) <= BUFF_ADDR; + send_address(tmp_buff) <= tmp_address; + send_length(tmp_buff) <= tmp_length; + end if; + + elsif tmp_cmd = CMD_RECV then + if recv_buff(tmp_buff) = BUFF_FULL then + recv_buff(tmp_buff) <= BUFF_ADDR; + + if tmp_buff = 0 then + recv_address0 <= tmp_address; + elsif tmp_buff = 1 then + recv_address1 <= tmp_address; + elsif tmp_buff = 2 then + recv_address2 <= tmp_address; + elsif tmp_buff = 3 then + recv_address3 <= tmp_address; + elsif tmp_buff = 4 then + recv_address4 <= tmp_address; + elsif tmp_buff = 5 then + recv_address5 <= tmp_address; + elsif tmp_buff = 6 then + recv_address6 <= tmp_address; + elsif tmp_buff = 7 then + recv_address7 <= tmp_address; + elsif tmp_buff = 8 then + recv_address8 <= tmp_address; + elsif tmp_buff = 9 then + recv_address9 <= tmp_address; + elsif tmp_buff = 10 then + recv_address10 <= tmp_address; + elsif tmp_buff = 11 then + recv_address11 <= tmp_address; + elsif tmp_buff = 12 then + recv_address12 <= tmp_address; + elsif tmp_buff = 13 then + recv_address13 <= tmp_address; + elsif tmp_buff = 14 then + recv_address14 <= tmp_address; + elsif tmp_buff = 15 then + recv_address15 <= tmp_address; + end if; + end if; + + elsif tmp_cmd = CMD_MDIO then + rx_state <= rx_state_mdio; + mdio_enable <= '1'; + mdio_command <= rx_data(27 downto 0); + end if; + + elsif rx_complete = '1' then + tmp_buff := to_integer(unsigned(rx_tag(BUFF_BITS - 1 downto 0))); + + debug_cmpl_count <= debug_cmpl_count + 1; + debug_cmpl_data <= rx_data; + debug_cmpl_tag <= rx_tag; + debug_cmpl_state <= x"00"; + + if send_buff(tmp_buff) = BUFF_DATA then + wr_en <= '1'; + wr_data <= rx_data; + wr_buff <= std_logic_vector(to_unsigned(tmp_buff, BUFF_BITS)); + send_remain(tmp_buff) <= send_remain(tmp_buff) - 1; + debug_cmpl_state <= x"01"; + + if send_remain(tmp_buff) = 1 then + read_decr := '1'; + + if send_length(tmp_buff) = 0 then + rx_state <= rx_state_write_done; + debug_cmpl_state <= x"02"; + else + send_buff(tmp_buff) <= BUFF_ADDR; + debug_cmpl_state <= x"03"; + end if; + end if; + end if; + end if; + + elsif rx_state = rx_state_write_done then + rx_state <= rx_state_idle; + wr_done <= '1'; + + elsif rx_state = rx_state_mdio then + if mdio_done = '1' then + rx_state <= rx_state_idle; + mdio_enable <= '0'; + end if; + end if; + + -- ENGINE: TX + if send_read_done = '1' then + send_read_done <= '0'; + send_buff(send_read_buff) <= BUFF_DATA; + send_length(send_read_buff) <= send_read_length - send_read_remain; + send_remain(send_read_buff) <= send_read_remain; + send_address(send_read_buff) <= send_read_address + send_read_remain; + send_read_time(send_read_buff) <= timer; + end if; + + if tx_state = tx_state_idle or + (tx_state = tx_state_read and tx_done = '1') or + (tx_state = tx_state_write and tx_done = '1') or + (tx_state = tx_state_complete and tx_done = '1') or + (tx_state = tx_state_interrupt and interrupt_rdy = '1') then + + tx_state <= tx_state_idle; + tx_read <= '0'; + tx_write <= '0'; + tx_complete <= '0'; + tx_data_i <= (others => '0'); + tx_address <= (others => '0'); + tx_length <= (others => '0'); + tx_tag <= (others => '0'); + interrupt <= '0'; + + if bar_read = '1' then + tx_state <= tx_state_complete; + tx_complete <= '1'; + tx_address <= bar_read_address; + tmp_cmd := bar_read_address(4 downto 3); + tmp_bar := unsigned(bar_read_address(3 + BAR_BITS - 1 downto 3)); + bar_read := '0'; + + if tmp_bar = 0 then + --if tmp_cmd = CMD_STATUS then + for i in 0 to BUFF_COUNT - 1 loop + tx_data_i(i*4 + 1 downto i*4 + 0) <= send_buff(i); + tx_data_i(i*4 + 3 downto i*4 + 2) <= recv_buff(i); + end loop; + send_int <= '0'; + send_int_needed <= '1'; + + elsif tmp_bar = 1 then + tx_data_i(63 downto 3) <= debug_address; + + elsif tmp_bar = 2 then + tx_data_i <= debug_data; + + elsif tmp_bar = 3 then + tx_data_i(1 downto 0) <= debug_cmd; + + elsif tmp_bar = 4 then + tx_data_i(BUFF_BITS - 1 downto 0) <= debug_buff; + + elsif tmp_bar = 5 then + tx_data_i(8 downto 0) <= debug_length; + + elsif tmp_bar = 10 then + tx_data_i(7 downto 0) <= std_logic_vector(debug_cmpl_count); + + elsif tmp_bar = 11 then + tx_data_i <= debug_cmpl_data; + + elsif tmp_bar = 12 then + tx_data_i(4 downto 0) <= debug_cmpl_tag; + + elsif tmp_bar = 13 then + tx_data_i(7 downto 0) <= debug_cmpl_state; + + elsif tmp_bar = 20 then + tx_data_i(7 downto 0) <= std_logic_vector(debug_write_count); + + elsif tmp_bar = 21 then + tx_data_i(8 downto 0) <= debug_write_length; + + elsif tmp_bar = 22 then + tx_data_i(63 downto 3) <= debug_write_addr; + + elsif tmp_bar = 23 then + tx_data_i(63 downto 0) <= debug_write_data; + + elsif tmp_bar = 24 then + tx_data_i(7 downto 0) <= std_logic_vector(debug_accept_count); + + elsif tmp_bar = 25 then + tx_data_i(7 downto 0) <= std_logic_vector(debug_done_count); + + elsif tmp_bar = 30 then + tx_data_i(15 downto 0) <= mdio_data; + + else + tx_data_i(63 downto 3) <= bar_read_address; + end if; + + elsif send_int = '1' and send_int_needed = '1' then + tx_state <= tx_state_interrupt; + interrupt <= '1'; + send_int_needed <= '0'; + + elsif send_read = '1' and read_count < READ_MAX then + tmp_buff := send_read_buff; + tmp_length := send_read_length; + tmp_address := send_read_address; + tmp_remain := 16 - resize(tmp_address(6 downto 3), tmp_remain'length); + + if max_read = "001" then + tmp_remain := 32 - resize(tmp_address(7 downto 3), tmp_remain'length); + elsif max_read = "010" then + tmp_remain := 64 - resize(tmp_address(8 downto 3), tmp_remain'length); + elsif max_read = "011" then + tmp_remain := 128 - resize(tmp_address(9 downto 3), tmp_remain'length); + elsif max_read = "100" then + tmp_remain := 256 - resize(tmp_address(10 downto 3), tmp_remain'length); + elsif max_read = "101" then + tmp_remain := 512 - resize(tmp_address(11 downto 3), tmp_remain'length); + end if; + + if tmp_remain > tmp_length then + tmp_remain := tmp_length; + end if; + + tx_state <= tx_state_read; + tx_read <= '1'; + tx_address <= std_logic_vector(tmp_address); + tx_length <= std_logic_vector(tmp_remain); + tx_tag <= std_logic_vector(to_unsigned(tmp_buff, tx_tag'length)); + + send_read <= '0'; + send_read_done <= '1'; + send_read_remain <= tmp_remain; + read_incr := '1'; + + elsif send_write = '1' then + if send_write_new = '1' then + tmp_length := unsigned(rd_length); + else + tmp_length := send_write_length; + end if; + tmp_address := send_write_address; + tmp_remain := 16 - resize(tmp_address(6 downto 3), tmp_remain'length); + + if max_write = "001" then + tmp_remain := 32 - resize(tmp_address(7 downto 3), tmp_remain'length); + elsif max_write = "010" then + tmp_remain := 64 - resize(tmp_address(8 downto 3), tmp_remain'length); + elsif max_write = "011" then + tmp_remain := 128 - resize(tmp_address(9 downto 3), tmp_remain'length); + elsif max_write = "100" then + tmp_remain := 256 - resize(tmp_address(10 downto 3), tmp_remain'length); + elsif max_write = "101" then + tmp_remain := 512 - resize(tmp_address(11 downto 3), tmp_remain'length); + end if; + + if tmp_remain > tmp_length then + tmp_remain := tmp_length; + end if; + + tx_state <= tx_state_write; + tx_write <= '1'; + tx_address <= std_logic_vector(tmp_address); + tx_length <= std_logic_vector(tmp_remain); + + debug_write_count <= debug_write_count + 1; + debug_write_length <= std_logic_vector(tmp_remain); + debug_write_addr <= std_logic_vector(tmp_address); + debug_write_data <= rd_data; + + tmp_length := tmp_length - tmp_remain; + tmp_address := tmp_address + tmp_remain; + + send_write_length <= tmp_length; + send_write_address <= tmp_address; + send_write_new <= '0'; + + if tmp_length = 0 then + send_write <= '0'; + end if; + end if; + end if; + + if read_decr = '1' and read_incr = '0' then + read_count := read_count - 1; + elsif read_decr = '0' and read_incr = '1' then + read_count := read_count + 1; + end if; + + if tx_accept = '1' then + debug_accept_count <= debug_accept_count + 1; + end if; + if tx_done = '1' then + debug_done_count <= debug_done_count + 1; + end if; + + for i in 0 to BUFF_COUNT - 1 loop + if send_buff(i) = BUFF_DATA and wr_accept(i) = '0' then + send_buff(i) <= BUFF_FULL; + -- no send_int here + end if; + if send_buff(i) = BUFF_FULL and wr_accept(i) = '1' then + send_buff(i) <= BUFF_EMPTY; + send_int <= '1'; + end if; + if recv_buff(i) = BUFF_EMPTY and rd_valid(i) = '1' then + recv_buff(i) <= BUFF_FULL; + send_int <= '1'; + end if; + if recv_buff(i) = BUFF_DATA and rd_valid(i) = '0' then + recv_buff(i) <= BUFF_EMPTY; + send_int <= '1'; + end if; + + if send_buff(i) = BUFF_DATA and send_read_time(i) = timer then + -- read timeout + wr_cancel(i) <= '1'; + end if; + end loop; + + if send_read = '0' and send_read_done = '0' then + for i in 0 to BUFF_COUNT - 1 loop + tmp_buff := (send_read_buff + i) mod BUFF_COUNT; + + if send_buff(tmp_buff) = BUFF_ADDR then + send_read <= '1'; + send_read_buff <= tmp_buff; + send_read_length <= send_length(tmp_buff); + send_read_address <= send_address(tmp_buff); + exit; + end if; + end loop; + end if; + + if send_write = '0' and (tx_state /= tx_state_write or tx_done = '1') then + for i in 0 to BUFF_COUNT - 1 loop + tmp_buff := (send_write_buff + i) mod BUFF_COUNT; + + if recv_buff(tmp_buff) = BUFF_ADDR then + recv_buff(tmp_buff) <= BUFF_DATA; + send_write <= '1'; + send_write_new <= '1'; + send_write_buff <= tmp_buff; + rd_buff <= std_logic_vector(to_unsigned(tmp_buff, BUFF_BITS)); + + if tmp_buff = 0 then + send_write_address <= recv_address0; + elsif tmp_buff = 1 then + send_write_address <= recv_address1; + elsif tmp_buff = 2 then + send_write_address <= recv_address2; + elsif tmp_buff = 3 then + send_write_address <= recv_address3; + elsif tmp_buff = 4 then + send_write_address <= recv_address4; + elsif tmp_buff = 5 then + send_write_address <= recv_address5; + elsif tmp_buff = 6 then + send_write_address <= recv_address6; + elsif tmp_buff = 7 then + send_write_address <= recv_address7; + elsif tmp_buff = 8 then + send_write_address <= recv_address8; + elsif tmp_buff = 9 then + send_write_address <= recv_address9; + elsif tmp_buff = 10 then + send_write_address <= recv_address10; + elsif tmp_buff = 11 then + send_write_address <= recv_address11; + elsif tmp_buff = 12 then + send_write_address <= recv_address12; + elsif tmp_buff = 13 then + send_write_address <= recv_address13; + elsif tmp_buff = 14 then + send_write_address <= recv_address14; + elsif tmp_buff = 15 then + send_write_address <= recv_address15; + end if; + exit; + end if; + end loop; + end if; + end if; + end process; +end arch; diff --git a/netfpga10g/hdl/eth.vhd b/netfpga10g/hdl/eth.vhd new file mode 100644 index 0000000..8034ceb --- /dev/null +++ b/netfpga10g/hdl/eth.vhd @@ -0,0 +1,219 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity eth is +generic ( + BITS : integer := 14; + REVERSE_LANES : std_logic := '0' +); +port ( + clk : in std_logic; + reset : in std_logic; + clk156_out : out std_logic; + + read : out std_logic; + rd_data : in std_logic_vector(63 downto 0); + rd_empty : in std_logic; + rd_count : in std_logic_vector(BITS downto 0); + + write : out std_logic; + wr_data : out std_logic_vector(63 downto 0); + wr_full : in std_logic; + wr_count : in std_logic_vector(BITS downto 0); + + xaui_clk_p : in std_logic; + xaui_clk_n : in std_logic; + xaui_dclk : in std_logic; + xaui_tx_l0_p : out std_logic; + xaui_tx_l0_n : out std_logic; + xaui_tx_l1_p : out std_logic; + xaui_tx_l1_n : out std_logic; + xaui_tx_l2_p : out std_logic; + xaui_tx_l2_n : out std_logic; + xaui_tx_l3_p : out std_logic; + xaui_tx_l3_n : out std_logic; + xaui_rx_l0_p : in std_logic; + xaui_rx_l0_n : in std_logic; + xaui_rx_l1_p : in std_logic; + xaui_rx_l1_n : in std_logic; + xaui_rx_l2_p : in std_logic; + xaui_rx_l2_n : in std_logic; + xaui_rx_l3_p : in std_logic; + xaui_rx_l3_n : in std_logic +); +end eth; + +architecture arch of eth is + type state_t is (state_idle, state_length, state_data, state_end); + + signal xgmii_txd : std_logic_vector(63 downto 0); + signal xgmii_txc : std_logic_vector(7 downto 0); + signal xgmii_rxd : std_logic_vector(63 downto 0); + signal xgmii_rxc : std_logic_vector(7 downto 0); + + signal clk156 : std_logic; + + signal rx_data : std_logic_vector(63 downto 0); + signal rx_start : std_logic; + signal rx_end : std_logic; + signal rx_rem : integer range 0 to 7; + + signal tx_data : std_logic_vector(63 downto 0); + signal tx_start : std_logic; + signal tx_end : std_logic; + signal tx_rem : integer range 0 to 7; +begin + clk156_out <= clk156; + + -- sending + process (clk, reset) + variable state : state_t; + variable length : unsigned(BITS downto 0); + begin + if reset = '1' then + state := state_idle; + read <= '0'; + tx_data <= (others => '0'); + tx_start <= '0'; + tx_end <= '0'; + tx_rem <= 0; + + elsif rising_edge(clk) then + read <= '0'; + tx_data <= (others => '0'); + tx_start <= '0'; + tx_end <= '0'; + tx_rem <= 0; + + if state = state_idle then + if rd_empty = '0' then + length := unsigned(rd_data(BITS downto 0)) + 1; + + if length <= unsigned(rd_count) then + state := state_data; + read <= '1'; + tx_start <= '1'; + end if; + end if; + + elsif state = state_data then + tx_data <= rd_data; + length := length - 1; + + if length > 0 then + read <= '1'; + else + state := state_end; + end if; + + elsif state = state_end then + state := state_idle; + tx_end <= '1'; + tx_rem <= 0; + end if; + end if; + end process; + + -- receiving + process (clk, reset) + variable state : state_t; + variable length : unsigned(BITS downto 0); + begin + if reset = '1' then + state := state_idle; + write <= '0'; + wr_data <= (others => '0'); + + elsif rising_edge(clk) then + write <= '0'; + wr_data <= (others => '0'); + + if state = state_idle then + if rx_start = '1' and rx_end = '0' then + state := state_length; + end if; + + elsif state = state_length then + state := state_idle; + + if rx_end = '0' and + unsigned(rx_data) <= 511 and + 16384 - unsigned(wr_count) >= 512 + then + state := state_data; + length := unsigned(rx_data(BITS downto 0)) + 1; + end if; + end if; + + if state = state_data then + write <= '1'; + wr_data <= rx_data; + length := length - 1; + + if length = 0 then + state := state_idle; + end if; + end if; + end if; + end process; + + xaui : entity work.xaui_top + generic map ( + REVERSE_LANES => REVERSE_LANES + ) + port map ( + dclk => xaui_dclk, + reset => reset, + xgmii_txd => xgmii_txd, + xgmii_txc => xgmii_txc, + xgmii_rxd => xgmii_rxd, + xgmii_rxc => xgmii_rxc, + clk156_out => clk156, + refclk_p => xaui_clk_p, + refclk_n => xaui_clk_n, + xaui_tx_l0_p => xaui_tx_l0_p, + xaui_tx_l0_n => xaui_tx_l0_n, + xaui_tx_l1_p => xaui_tx_l1_p, + xaui_tx_l1_n => xaui_tx_l1_n, + xaui_tx_l2_p => xaui_tx_l2_p, + xaui_tx_l2_n => xaui_tx_l2_n, + xaui_tx_l3_p => xaui_tx_l3_p, + xaui_tx_l3_n => xaui_tx_l3_n, + xaui_rx_l0_p => xaui_rx_l0_p, + xaui_rx_l0_n => xaui_rx_l0_n, + xaui_rx_l1_p => xaui_rx_l1_p, + xaui_rx_l1_n => xaui_rx_l1_n, + xaui_rx_l2_p => xaui_rx_l2_p, + xaui_rx_l2_n => xaui_rx_l2_n, + xaui_rx_l3_p => xaui_rx_l3_p, + xaui_rx_l3_n => xaui_rx_l3_n + ); + + rx_eth : entity work.rx_eth port map ( + clk => clk, + reset => reset, + + xgmii_rxd => xgmii_rxd, + xgmii_rxc => xgmii_rxc, + + rx_data => rx_data, + rx_start => rx_start, + rx_end => rx_end, + rx_rem => rx_rem + ); + + tx_eth : entity work.tx_eth port map ( + clk => clk, + reset => reset, + + xgmii_txd => xgmii_txd, + xgmii_txc => xgmii_txc, + + tx_data => tx_data, + tx_start => tx_start, + tx_end => tx_end, + tx_rem => tx_rem + ); +end arch; diff --git a/netfpga10g/hdl/eth_rx.vhd b/netfpga10g/hdl/eth_rx.vhd new file mode 100644 index 0000000..bcd395f --- /dev/null +++ b/netfpga10g/hdl/eth_rx.vhd @@ -0,0 +1,84 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity eth_rx is port ( + clk : in std_logic; + + wr_en : out std_logic := '0'; + wr_data : out std_logic_vector (63 downto 0) := (others => '0'); + wr_done : out std_logic := '0'; + wr_accept : in std_logic; + + xgmii_rxd : in std_logic_vector(63 downto 0); + xgmii_rxc : in std_logic_vector(7 downto 0) +); +end eth_rx; + +architecture arch of eth_rx is + constant IDLE : std_logic_vector(7 downto 0) := x"07"; + constant START : std_logic_vector(7 downto 0) := x"FB"; + constant TERMINATE : std_logic_vector(7 downto 0) := x"FD"; + constant ERR : std_logic_vector(7 downto 0) := x"FE"; + + type lanes_t is array (0 to 7) of std_logic_vector(7 downto 0); + signal lanes_a : lanes_t; + signal lanes_b : lanes_t; + + signal control_a : std_logic_vector(7 downto 0); + signal control_b : std_logic_vector(7 downto 0); + + type state_t is (state_idle, state_a, state_b); + signal state : state_t := state_idle; +begin + gen_a : for i in 0 to 7 generate + lanes_a(i) <= xgmii_rxd(7+8*i downto 8*i); + control_a(i) <= xgmii_rxc(i); + end generate gen_a; + + lanes_b(4 to 7) <= lanes_a(0 to 3); + control_b(7 downto 4) <= control_a(3 downto 0); + + process (clk) + begin + if rising_edge(clk) then + wr_en <= '0'; + wr_data <= (others => '0'); + wr_done <= '0'; + + lanes_b(0 to 3) <= lanes_a(4 to 7); + control_b(3 downto 0) <= control_a(7 downto 4); + + if state = state_idle and wr_accept = '1' then + if control_a(0) = '1' and lanes_a(0) = START then + state <= state_a; + elsif control_b(0) = '1' and lanes_b(0) = START then + state <= state_b; + end if; + + elsif state = state_a then + wr_en <= '1'; + for i in 0 to 7 loop + wr_data(63-8*i downto 56-8*i) <= lanes_a(i); + + if control_a(i) = '1' and (lanes_a(i) = TERMINATE or lanes_a(i) = ERR) then + state <= state_idle; + wr_done <= '1'; + end if; + end loop; + + elsif state = state_b then + wr_en <= '1'; + for i in 0 to 7 loop + wr_data(63-8*i downto 56-8*i) <= lanes_b(i); + + if control_b(i) = '1' and (lanes_b(i) = TERMINATE or lanes_b(i) = ERR) then + state <= state_idle; + wr_done <= '1'; + end if; + end loop; + end if; + end if; + end process; +end arch; diff --git a/netfpga10g/hdl/eth_tx.vhd b/netfpga10g/hdl/eth_tx.vhd new file mode 100644 index 0000000..cf0081d --- /dev/null +++ b/netfpga10g/hdl/eth_tx.vhd @@ -0,0 +1,68 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity eth_tx is port ( + clk : in std_logic; + + rd_en : out std_logic; + rd_data : in std_logic_vector (63 downto 0); + rd_valid : in std_logic; + + xgmii_txd : out std_logic_vector(63 downto 0); + xgmii_txc : out std_logic_vector(7 downto 0) +); +end eth_tx; + +architecture arch of eth_tx is + constant IDLE : std_logic_vector(7 downto 0) := x"07"; + constant START : std_logic_vector(7 downto 0) := x"FB"; + constant TERMINATE : std_logic_vector(7 downto 0) := x"FD"; + + constant PREAMBLE : std_logic_vector(7 downto 0) := "01010101"; + constant SFD : std_logic_vector(7 downto 0) := "11010101"; + + type lanes_t is array (0 to 7) of std_logic_vector(7 downto 0); + signal lanes : lanes_t := (others => IDLE); + signal control : std_logic_vector(7 downto 0) := (others => '1'); + + type state_t is (state_idle, state_data); + signal state : state_t := state_idle; +begin + lanes_gen : for i in 0 to 7 generate + xgmii_txd(7+8*i downto 8*i) <= lanes(i); + xgmii_txc(i) <= control(i); + end generate lanes_gen; + + rd_en <= '1' when state = state_data else '0'; + + process (clk) + begin + if rising_edge(clk) then + lanes <= (others => IDLE); + control <= (others => '1'); + + if state = state_idle then + if rd_valid = '1' then + state <= state_data; + lanes(0) <= START; + lanes(1 to 6) <= (others => PREAMBLE); + lanes(7) <= SFD; + control(7 downto 1) <= (others => '0'); + end if; + + elsif state = state_data then + if rd_valid = '1' then + for i in 0 to 7 loop + lanes(i) <= rd_data(63-8*i downto 56-8*i); + control(i) <= '0'; + end loop; + else + state <= state_idle; + lanes(0) <= TERMINATE; + end if; + end if; + end if; + end process; +end arch; diff --git a/netfpga10g/hdl/mdio.vhd b/netfpga10g/hdl/mdio.vhd new file mode 100644 index 0000000..1cb34fa --- /dev/null +++ b/netfpga10g/hdl/mdio.vhd @@ -0,0 +1,223 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity mdio is port ( + clk125 : in std_logic; + reset125 : in std_logic; + + command : in std_logic_vector(0 to 27); -- operation(2) & phyaddr(5) & devaddr(5) & data_in(16) + data_out : out std_logic_vector(0 to 15); + enable : in std_logic; + done : out std_logic; + + mdio_in : in std_logic; + mdio_out : out std_logic; + mdio_Z : out std_logic; + mdc : out std_logic; + phy_reset_n : out std_logic; + + total_count : out std_logic_vector(31 downto 0); + address_count : out std_logic_vector(31 downto 0); + write_count : out std_logic_vector(31 downto 0); + read_count : out std_logic_vector(31 downto 0); + read_incr_count : out std_logic_vector(31 downto 0) +); +end mdio; + +architecture arch of mdio is + type state_t is (state_idle, state_preamble, state_start, state_operation, + state_phyaddr, state_devaddr, state_turnaround, state_data); + + signal state : state_t; + signal state_count : natural range 0 to 32; + + signal operation : std_logic_vector(0 to 1); + signal phyaddr : std_logic_vector(0 to 4); + signal devaddr : std_logic_vector(0 to 4); + signal data_in : std_logic_vector(0 to 15); + + signal mdc_count : natural range 0 to 25; + signal mdc_i : std_logic; + + signal total_count_i : unsigned(31 downto 0); + signal address_count_i : unsigned(31 downto 0); + signal write_count_i : unsigned(31 downto 0); + signal read_count_i : unsigned(31 downto 0); + signal read_incr_count_i : unsigned(31 downto 0); + + signal done_i : std_logic; +begin + phy_reset_n <= not reset125; + mdc <= mdc_i; + + operation <= command(0 to 1); + phyaddr <= command(2 to 6); + devaddr <= command(7 to 11); + data_in <= command(12 to 27); + + done <= done_i; + + process (clk125, reset125) begin + if reset125 = '1' then + mdc_i <= '0'; + mdc_count <= 0; + done_i <= '0'; + + elsif rising_edge(clk125) then + done_i <= '0'; + + if mdc_count = 25 - 1 then + mdc_count <= 0; + mdc_i <= not mdc_i; -- 2.5 MHz + + if mdc_i = '0' then -- rising edge + if state = state_data and state_count = 15 then + done_i <= '1'; + end if; + end if; + else + mdc_count <= mdc_count + 1; + end if; + end if; + end process; + + process (mdc_i, reset125) begin + if reset125 = '1' then + state <= state_idle; + state_count <= 0; + data_out <= (others => '0'); + + elsif rising_edge(mdc_i) then + state_count <= state_count + 1; + + if state = state_preamble then + if state_count = 31 then + state <= state_start; + state_count <= 0; + end if; + elsif state = state_start then + if state_count = 1 then + state <= state_operation; + state_count <= 0; + end if; + elsif state = state_operation then + if state_count = 1 then + state <= state_phyaddr; + state_count <= 0; + end if; + elsif state = state_phyaddr then + if state_count = 4 then + state <= state_devaddr; + state_count <= 0; + end if; + elsif state = state_devaddr then + if state_count = 4 then + state <= state_turnaround; + state_count <= 0; + end if; + elsif state = state_turnaround then + if state_count = 1 then + state <= state_data; + state_count <= 0; + end if; + elsif state = state_data then + data_out(state_count) <= mdio_in; + + if state_count = 15 then + state <= state_idle; + state_count <= 0; + end if; + else -- state = state_idle + if enable = '1' then + state <= state_preamble; + state_count <= 0; + end if; + end if; + end if; + end process; + + process (mdc_i, reset125) begin + if reset125 = '1' then + mdio_out <= '0'; + mdio_Z <= '1'; + + elsif falling_edge(mdc_i) then + mdio_out <= '0'; + mdio_Z <= '1'; + + if state = state_preamble then + mdio_out <= '1'; + mdio_Z <= '0'; + + elsif state = state_start then + mdio_out <= '0'; + mdio_Z <= '0'; + + elsif state = state_operation then + mdio_out <= operation(state_count); + mdio_Z <= '0'; + + elsif state = state_phyaddr then + mdio_out <= phyaddr(state_count); + mdio_Z <= '0'; + + elsif state = state_devaddr then + mdio_out <= devaddr(state_count); + mdio_Z <= '0'; + + elsif state = state_turnaround then + if operation(0) = '0' then -- write or address + mdio_Z <= '0'; + + if state_count = 0 then + mdio_out <= '1'; + else + mdio_out <= '0'; + end if; + end if; + + elsif state = state_data then + if operation(0) = '0' then -- write or address + mdio_Z <= '0'; + mdio_out <= data_in(state_count); + end if; + end if; + end if; + end process; + + total_count <= std_logic_vector(total_count_i); + address_count <= std_logic_vector(address_count_i); + write_count <= std_logic_vector(write_count_i); + read_count <= std_logic_vector(read_count_i); + read_incr_count <= std_logic_vector(read_incr_count_i); + + process (clk125, reset125) begin + if reset125 = '1' then + total_count_i <= (others => '0'); + address_count_i <= (others => '0'); + write_count_i <= (others => '0'); + read_count_i <= (others => '0'); + read_incr_count_i <= (others => '0'); + + elsif rising_edge(clk125) then + if done_i = '1' then + total_count_i <= total_count_i + 1; + + if operation = "00" then + address_count_i <= address_count_i + 1; + end if; + if operation = "01" then + write_count_i <= write_count_i + 1; + end if; + if operation = "11" then + read_count_i <= read_count_i + 1; + end if; + if operation = "10" then + read_incr_count_i <= read_incr_count_i + 1; + end if; + end if; + end if; + end process; +end arch; diff --git a/netfpga10g/hdl/pcie.vhd b/netfpga10g/hdl/pcie.vhd new file mode 100644 index 0000000..6dd99cf --- /dev/null +++ b/netfpga10g/hdl/pcie.vhd @@ -0,0 +1,268 @@ + +library ieee; +use ieee.std_logic_1164.all; + +entity pcie is +generic ( + BITS : integer := 14 +); +port ( + pcie_clk_p : in std_logic; + pcie_clk_n : in std_logic; + reset25 : in std_logic; + + clk125_out : out std_logic; + reset125_out : out std_logic; + + pci_exp_rxn : in std_logic_vector(7 downto 0); + pci_exp_rxp : in std_logic_vector(7 downto 0); + pci_exp_txn : out std_logic_vector(7 downto 0); + pci_exp_txp : out std_logic_vector(7 downto 0); + + port0_read : out std_logic; + port0_rd_data : in std_logic_vector(63 downto 0); + port0_rd_empty : in std_logic; + port0_rd_count : in std_logic_vector(BITS downto 0); + + port0_write : out std_logic; + port0_wr_data : out std_logic_vector(63 downto 0); + port0_wr_full : in std_logic; + port0_wr_count : in std_logic_vector(BITS downto 0); + + port1_read : out std_logic; + port1_rd_data : in std_logic_vector(63 downto 0); + port1_rd_empty : in std_logic; + port1_rd_count : in std_logic_vector(BITS downto 0); + + port1_write : out std_logic; + port1_wr_data : out std_logic_vector(63 downto 0); + port1_wr_full : in std_logic; + port1_wr_count : in std_logic_vector(BITS downto 0); + + port2_read : out std_logic; + port2_rd_data : in std_logic_vector(63 downto 0); + port2_rd_empty : in std_logic; + port2_rd_count : in std_logic_vector(BITS downto 0); + + port2_write : out std_logic; + port2_wr_data : out std_logic_vector(63 downto 0); + port2_wr_full : in std_logic; + port2_wr_count : in std_logic_vector(BITS downto 0); + + port3_read : out std_logic; + port3_rd_data : in std_logic_vector(63 downto 0); + port3_rd_empty : in std_logic; + port3_rd_count : in std_logic_vector(BITS downto 0); + + port3_write : out std_logic; + port3_wr_data : out std_logic_vector(63 downto 0); + port3_wr_full : in std_logic; + port3_wr_count : in std_logic_vector(BITS downto 0); + + mdio_command : out std_logic_vector(0 to 27); + mdio_data : in std_logic_vector(0 to 15); + mdio_enable : out std_logic; + mdio_done : in std_logic; + + leds : out std_logic_vector(2 downto 0) +); +end pcie; + +architecture arch of pcie is + signal clk125 : std_logic; + signal reset125 : std_logic; + + signal rx_frame : std_logic_vector(63 downto 0); + signal rx_sof : std_logic; + signal rx_eof : std_logic; + signal rx_valid : std_logic; + + signal rx_read : std_logic; + signal rx_write : std_logic; + signal rx_complete : std_logic; + signal rx_data : std_logic_vector(63 downto 0); + signal rx_address : std_logic_vector(28 downto 0); + + signal tx_frame : std_logic_vector(63 downto 0); + signal tx_sof : std_logic; + signal tx_eof : std_logic; + signal tx_half : std_logic; + signal tx_valid : std_logic; + signal tx_ready : std_logic; + + signal tx_read : std_logic; + signal tx_write : std_logic; + signal tx_complete : std_logic; + signal tx_data : std_logic_vector(63 downto 0); + signal tx_address : std_logic_vector(28 downto 0); + signal tx_length : std_logic_vector(8 downto 0); + signal tx_accept : std_logic; + signal tx_done : std_logic; + + signal bus_dev_func : std_logic_vector(15 downto 0); + signal transaction_id : std_logic_vector(23 downto 0); + + signal max_read : std_logic_vector(2 downto 0); + signal max_write : std_logic_vector(2 downto 0); + + signal interrupt : std_logic; + signal interrupt_rdy : std_logic; + + signal bar0 : std_logic; +begin + clk125_out <= clk125; + reset125_out <= reset125; + + pcie_wrapper : entity work.pcie_wrapper port map ( + pcie_clk_p => pcie_clk_p, + pcie_clk_n => pcie_clk_n, + reset25 => reset25, + + clk125 => clk125, + reset125 => reset125, + + pci_exp_rxn => pci_exp_rxn, + pci_exp_rxp => pci_exp_rxp, + pci_exp_txn => pci_exp_txn, + pci_exp_txp => pci_exp_txp, + + rx_frame => rx_frame, + rx_sof => rx_sof, + rx_eof => rx_eof, + rx_valid => rx_valid, + + tx_frame => tx_frame, + tx_sof => tx_sof, + tx_eof => tx_eof, + tx_half => tx_half, + tx_valid => tx_valid, + tx_ready => tx_ready, + + bus_dev_func => bus_dev_func, + + max_read => max_read, + max_write => max_write, + + interrupt => interrupt, + interrupt_rdy => interrupt_rdy, + + bar0 => bar0 + ); + + pcie_rx : entity work.pcie_rx port map ( + clk => clk125, + reset => reset125, + + frame => rx_frame, + sof => rx_sof, + eof => rx_eof, + valid => rx_valid, + + read => rx_read, + write => rx_write, + complete => rx_complete, + data => rx_data, + address => rx_address, + + transaction_id => transaction_id, + bar0 => bar0 + ); + + pcie_tx : entity work.pcie_tx port map ( + clk => clk125, + reset => reset125, + + frame => tx_frame, + sof => tx_sof, + eof => tx_eof, + half => tx_half, + valid => tx_valid, + ready => tx_ready, + + read => tx_read, + write => tx_write, + complete => tx_complete, + data => tx_data, + address => tx_address, + length => tx_length, + accept => tx_accept, + done => tx_done, + + transaction_id => transaction_id, + bus_dev_func => bus_dev_func + ); + + dma : entity work.dma port map ( + clk => clk125, + reset => reset125, + + rx_read => rx_read, + rx_write => rx_write, + rx_complete => rx_complete, + rx_data => rx_data, + rx_address => rx_address, + + tx_read => tx_read, + tx_write => tx_write, + tx_complete => tx_complete, + tx_data => tx_data, + tx_address => tx_address, + tx_length => tx_length, + tx_accept => tx_accept, + tx_done => tx_done, + + port0_read => port0_read, + port0_rd_data => port0_rd_data, + port0_rd_empty => port0_rd_empty, + port0_rd_count => port0_rd_count, + + port0_write => port0_write, + port0_wr_data => port0_wr_data, + port0_wr_full => port0_wr_full, + port0_wr_count => port0_wr_count, + + port1_read => port1_read, + port1_rd_data => port1_rd_data, + port1_rd_empty => port1_rd_empty, + port1_rd_count => port1_rd_count, + + port1_write => port1_write, + port1_wr_data => port1_wr_data, + port1_wr_full => port1_wr_full, + port1_wr_count => port1_wr_count, + + port2_read => port2_read, + port2_rd_data => port2_rd_data, + port2_rd_empty => port2_rd_empty, + port2_rd_count => port2_rd_count, + + port2_write => port2_write, + port2_wr_data => port2_wr_data, + port2_wr_full => port2_wr_full, + port2_wr_count => port2_wr_count, + + port3_read => port3_read, + port3_rd_data => port3_rd_data, + port3_rd_empty => port3_rd_empty, + port3_rd_count => port3_rd_count, + + port3_write => port3_write, + port3_wr_data => port3_wr_data, + port3_wr_full => port3_wr_full, + port3_wr_count => port3_wr_count, + + max_read => max_read, + max_write => max_write, + + interrupt => interrupt, + interrupt_rdy => interrupt_rdy, + + mdio_command => mdio_command, + mdio_data => mdio_data, + mdio_enable => mdio_enable, + mdio_done => mdio_done, + + leds => leds + ); +end arch; + diff --git a/netfpga10g/hdl/pcie_rx.vhd b/netfpga10g/hdl/pcie_rx.vhd new file mode 100644 index 0000000..c4ee177 --- /dev/null +++ b/netfpga10g/hdl/pcie_rx.vhd @@ -0,0 +1,98 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity pcie_rx is port ( + clk : in std_logic; + + frame : in std_logic_vector(63 downto 0); + sof : in std_logic; + eof : in std_logic; + valid : in std_logic; + + read : out std_logic := '0'; + write : out std_logic := '0'; + complete : out std_logic := '0'; + data : out std_logic_vector(63 downto 0) := (others => '0'); + address : out std_logic_vector(63 downto 3) := (others => '0'); + tag : out std_logic_vector(4 downto 0) := (others => '0'); + remote : out std_logic_vector(23 downto 0) := (others => '0'); + + bar0 : in std_logic +); +end pcie_rx; + +architecture arch of pcie_rx is + type state_t is (state_idle, state_read, state_write, state_write_head, + state_complete, state_complete_head); + + signal fmt : std_logic_vector(1 downto 0); + signal typ : std_logic_vector(4 downto 0); + signal status : std_logic_vector(2 downto 0); +begin + fmt <= frame(62 downto 61); + typ <= frame(60 downto 56); + status <= frame(15 downto 13); + + process (clk) + variable state : state_t := state_idle; + variable extra : std_logic_vector(31 downto 0) := (others => '0'); + begin + if rising_edge(clk) then + read <= '0'; + write <= '0'; + complete <= '0'; + + if valid = '0' then + -- nothing + + elsif state = state_idle and sof = '1' then + data <= (others => '0'); + address <= (others => '0'); + tag <= (others => '0'); + + if fmt = "00" and typ = "00000" and bar0 = '1' then + state := state_read; + remote <= frame(31 downto 8); + + elsif fmt = "10" and typ = "00000" and bar0 = '1' then + state := state_write_head; + + elsif fmt = "10" and typ = "01010" and status = "000" then + state := state_complete_head; + end if; + + elsif state = state_read then + state := state_idle; + read <= '1'; + address <= x"00000000" & frame(63 downto 35); + + elsif state = state_write_head then + state := state_write; + address <= x"00000000" & frame(63 downto 35); + extra := frame(31 downto 0); + + elsif state = state_write then + state := state_idle; + write <= '1'; + data <= extra & frame(63 downto 32); + + elsif state = state_complete_head then + state := state_complete; + tag <= frame(44 downto 40); + extra := frame(31 downto 0); + + elsif state = state_complete then + complete <= '1'; + data <= extra & frame(63 downto 32); + extra := frame(31 downto 0); + end if; + + if valid = '1' and eof = '1' then + state := state_idle; + end if; + end if; + end process; +end arch; + diff --git a/netfpga10g/hdl/pcie_tx.vhd b/netfpga10g/hdl/pcie_tx.vhd new file mode 100644 index 0000000..dc892b4 --- /dev/null +++ b/netfpga10g/hdl/pcie_tx.vhd @@ -0,0 +1,178 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity pcie_tx is port ( + clk : in std_logic; + + frame : out std_logic_vector(63 downto 0) := (others => '0'); + sof : out std_logic := '0'; + eof : out std_logic := '0'; + half : out std_logic := '0'; + valid : out std_logic := '0'; + ready : in std_logic; + + read : in std_logic; + write : in std_logic; + complete : in std_logic; + data : in std_logic_vector(63 downto 0); + address : in std_logic_vector(63 downto 3); + length : in std_logic_vector(8 downto 0); + tag : in std_logic_vector(4 downto 0); + local : in std_logic_vector(15 downto 0); + remote : in std_logic_vector(23 downto 0); + accept : out std_logic; + done : out std_logic +); +end pcie_tx; + +architecture arch of pcie_tx is + type state_t is (state_idle, state_read_32, state_read_64, + state_write_32, state_write_64, + state_write_end_32, state_write_head_64, + state_complete, state_complete_head, state_done); + signal state : state_t := state_idle; +begin + accept <= ready when state = state_write_32 or state = state_write_64 else '0'; + done <= ready when state = state_done else '0'; + + process (clk) + variable extra : std_logic_vector(31 downto 0) := (others => '0'); + variable remain : unsigned(8 downto 0) := (others => '0'); + begin + if rising_edge(clk) and (ready = '1' or state = state_idle) then + frame <= (others => '0'); + sof <= '0'; + eof <= '0'; + half <= '0'; + valid <= '0'; + + -- read + if state = state_idle and read = '1' then + if unsigned(length) = 0 then + state <= state_done; + else + if address(63 downto 32) = x"00000000" then + state <= state_read_32; + frame <= "0" & "00" & "00000" & x"00" & + "000000" & + length & "0" & + local & + "000" & tag & x"FF"; + else + state <= state_read_64; + frame <= "0" & "01" & "00000" & x"00" & + "000000" & + length & "0" & + local & + "000" & tag & x"FF"; + end if; + sof <= '1'; + valid <= '1'; + end if; + + elsif state = state_read_32 then + state <= state_done; + frame <= address(31 downto 3) & "000" & x"00000000"; + eof <= '1'; + half <= '1'; + valid <= '1'; + + elsif state = state_read_64 then + state <= state_done; + frame <= address & "000"; + eof <= '1'; + valid <= '1'; + + -- write + elsif state = state_idle and write = '1' then + if unsigned(length) = 0 then + state <= state_done; + else + if address(63 downto 32) = x"00000000" then + state <= state_write_32; + frame <= "0" & "10" & "00000" & x"00" & + "000000" & + length & "0" & + local & + x"00" & x"FF"; + extra := address(31 downto 3) & "000"; + else + state <= state_write_head_64; + frame <= "0" & "11" & "00000" & x"00" & + "000000" & + length & "0" & + local & + x"00" & x"FF"; + end if; + sof <= '1'; + valid <= '1'; + remain := unsigned(length); + end if; + + elsif state = state_write_32 then + frame <= extra & data(63 downto 32); + extra := data(31 downto 0); + valid <= '1'; + + remain := remain - 1; + + if remain = 0 then + state <= state_write_end_32; + end if; + + elsif state = state_write_end_32 then + state <= state_done; + frame <= extra & x"00000000"; + eof <= '1'; + half <= '1'; + valid <= '1'; + + elsif state = state_write_head_64 then + state <= state_write_64; + frame <= address & "000"; + valid <= '1'; + + elsif state = state_write_64 then + frame <= data; + valid <= '1'; + + remain := remain - 1; + + if remain = 0 then + state <= state_done; + eof <= '1'; + end if; + + -- complete + elsif state = state_idle and complete = '1' then + state <= state_complete_head; + frame <= "0" & "10" & "01010" & x"00" & + x"0002" & + local & + x"0008"; + sof <= '1'; + valid <= '1'; + + elsif state = state_complete_head then + state <= state_complete; + frame <= remote & "0" & address(6 downto 3) & "000" & + data(63 downto 32); + valid <= '1'; + + elsif state = state_complete then + state <= state_done; + frame <= data(31 downto 0) & x"00000000"; + eof <= '1'; + half <= '1'; + valid <= '1'; + + -- done + elsif state = state_done then + state <= state_idle; + end if; + end if; + end process; +end arch; + diff --git a/netfpga10g/hdl/pcie_wrapper.vhd b/netfpga10g/hdl/pcie_wrapper.vhd new file mode 100644 index 0000000..35c6047 --- /dev/null +++ b/netfpga10g/hdl/pcie_wrapper.vhd @@ -0,0 +1,358 @@ + +library ieee; +use ieee.std_logic_1164.all; + +library unisim; +use unisim.vcomponents.all; + +entity pcie_wrapper is port ( + pcie_clk_p : in std_logic; + pcie_clk_n : in std_logic; + reset25 : in std_logic; + + clk125 : out std_logic; + reset125 : out std_logic; + + pci_exp_rxn : in std_logic_vector(7 downto 0); + pci_exp_rxp : in std_logic_vector(7 downto 0); + pci_exp_txn : out std_logic_vector(7 downto 0); + pci_exp_txp : out std_logic_vector(7 downto 0); + + rx_frame : out std_logic_vector(63 downto 0); + rx_sof : out std_logic; + rx_eof : out std_logic; + rx_valid : out std_logic; + + tx_frame : in std_logic_vector(63 downto 0); + tx_sof : in std_logic; + tx_eof : in std_logic; + tx_half : in std_logic; + tx_valid : in std_logic; + tx_ready : out std_logic; + + bus_dev_func : out std_logic_vector(15 downto 0); + + max_read : out std_logic_vector(2 downto 0); + max_write : out std_logic_vector(2 downto 0); + + interrupt : in std_logic; + interrupt_rdy : out std_logic; + + bar0 : out std_logic +); +end pcie_wrapper; + +architecture arch of pcie_wrapper is + + component pcie_core port ( + pci_exp_rxn : in std_logic_vector(7 downto 0); + pci_exp_rxp : in std_logic_vector(7 downto 0); + pci_exp_txn : out std_logic_vector(7 downto 0); + pci_exp_txp : out std_logic_vector(7 downto 0); + + sys_clk : in std_logic; + sys_reset_n : in std_logic; + + refclkout : out std_logic; + + trn_clk : out std_logic; + trn_reset_n : out std_logic; + trn_lnk_up_n : out std_logic; + + trn_rd : out std_logic_vector(63 downto 0); + trn_rrem_n : out std_logic_vector(7 downto 0); + trn_rsof_n : out std_logic; + trn_reof_n : out std_logic; + trn_rsrc_dsc_n : out std_logic; + trn_rsrc_rdy_n : out std_logic; + trn_rbar_hit_n : out std_logic_vector(6 downto 0); + trn_rdst_rdy_n : in std_logic; + trn_rerrfwd_n : out std_logic; + trn_rnp_ok_n : in std_logic; + trn_rfc_npd_av : out std_logic_vector(11 downto 0); + trn_rfc_nph_av : out std_logic_vector(7 downto 0); + trn_rfc_pd_av : out std_logic_vector(11 downto 0); + trn_rfc_ph_av : out std_logic_vector(7 downto 0); + trn_rcpl_streaming_n : in std_logic; + + trn_td : in std_logic_vector(63 downto 0); + trn_trem_n : in std_logic_vector(7 downto 0); + trn_tsof_n : in std_logic; + trn_teof_n : in std_logic; + trn_tsrc_dsc_n : in std_logic; + trn_tsrc_rdy_n : in std_logic; + trn_tdst_dsc_n : out std_logic; + trn_tdst_rdy_n : out std_logic; + trn_terrfwd_n : in std_logic ; + trn_tbuf_av : out std_logic_vector(3 downto 0); + + cfg_do : out std_logic_vector(31 downto 0); + cfg_rd_wr_done_n : out std_logic; + cfg_di : in std_logic_vector(31 downto 0); + cfg_byte_en_n : in std_logic_vector(3 downto 0); + cfg_dwaddr : in std_logic_vector(9 downto 0); + cfg_wr_en_n : in std_logic; + cfg_rd_en_n : in std_logic; + + cfg_err_cor_n : in std_logic; + cfg_err_cpl_abort_n : in std_logic; + cfg_err_cpl_timeout_n : in std_logic; + cfg_err_cpl_unexpect_n : in std_logic; + cfg_err_ecrc_n : in std_logic; + cfg_err_posted_n : in std_logic; + cfg_err_tlp_cpl_header : in std_logic_vector(47 downto 0); + cfg_err_ur_n : in std_logic; + cfg_err_cpl_rdy_n : out std_logic; + cfg_err_locked_n : in std_logic; + cfg_interrupt_n : in std_logic; + cfg_interrupt_rdy_n : out std_logic; + cfg_pm_wake_n : in std_logic; + cfg_pcie_link_state_n : out std_logic_vector(2 downto 0); + cfg_to_turnoff_n : out std_logic; + cfg_interrupt_assert_n : in std_logic; + cfg_interrupt_di : in std_logic_vector(7 downto 0); + cfg_interrupt_do : out std_logic_vector(7 downto 0); + cfg_interrupt_mmenable : out std_logic_vector(2 downto 0); + cfg_interrupt_msienable : out std_logic; + + cfg_trn_pending_n : in std_logic; + cfg_bus_number : out std_logic_vector(7 downto 0); + cfg_device_number : out std_logic_vector(4 downto 0); + cfg_function_number : out std_logic_vector(2 downto 0); + cfg_status : out std_logic_vector(15 downto 0); + cfg_command : out std_logic_vector(15 downto 0); + cfg_dstatus : out std_logic_vector(15 downto 0); + cfg_dcommand : out std_logic_vector(15 downto 0); + cfg_lstatus : out std_logic_vector(15 downto 0); + cfg_lcommand : out std_logic_vector(15 downto 0); + cfg_dsn : in std_logic_vector(63 downto 0); + + fast_train_simulation_only : in std_logic + ); + end component; + + signal sys_reset_n : std_logic; + + signal trn_clk : std_logic; + signal trn_reset_n : std_logic; + signal trn_lnk_up_n : std_logic; + + signal trn_rd : std_logic_vector(63 downto 0); + signal trn_rrem_n : std_logic_vector(7 downto 0); + signal trn_rsof_n : std_logic; + signal trn_reof_n : std_logic; + signal trn_rsrc_dsc_n : std_logic; + signal trn_rsrc_rdy_n : std_logic; + signal trn_rbar_hit_n : std_logic_vector(6 downto 0); + signal trn_rdst_rdy_n : std_logic; + signal trn_rerrfwd_n : std_logic; + signal trn_rnp_ok_n : std_logic; + signal trn_rfc_npd_av : std_logic_vector(11 downto 0); + signal trn_rfc_nph_av : std_logic_vector(7 downto 0); + signal trn_rfc_pd_av : std_logic_vector(11 downto 0); + signal trn_rfc_ph_av : std_logic_vector(7 downto 0); + signal trn_rcpl_streaming_n : std_logic; + + signal trn_td : std_logic_vector(63 downto 0); + signal trn_trem_n : std_logic_vector(7 downto 0); + signal trn_tsof_n : std_logic; + signal trn_teof_n : std_logic; + signal trn_tsrc_dsc_n : std_logic; + signal trn_tsrc_rdy_n : std_logic; + signal trn_tdst_dsc_n : std_logic; + signal trn_tdst_rdy_n : std_logic; + signal trn_terrfwd_n : std_logic; + signal trn_tbuf_av : std_logic_vector(3 downto 0); + + signal cfg_do : std_logic_vector(31 downto 0); + signal cfg_rd_wr_done_n : std_logic; + signal cfg_di : std_logic_vector(31 downto 0); + signal cfg_byte_en_n : std_logic_vector(3 downto 0); + signal cfg_dwaddr : std_logic_vector(9 downto 0); + signal cfg_wr_en_n : std_logic; + signal cfg_rd_en_n : std_logic; + + signal cfg_err_cor_n : std_logic; + signal cfg_err_cpl_abort_n : std_logic; + signal cfg_err_cpl_timeout_n : std_logic; + signal cfg_err_cpl_unexpect_n : std_logic; + signal cfg_err_ecrc_n : std_logic; + signal cfg_err_posted_n : std_logic; + signal cfg_err_tlp_cpl_header : std_logic_vector(47 downto 0); + signal cfg_err_ur_n : std_logic; + signal cfg_err_cpl_rdy_n : std_logic; + signal cfg_err_locked_n : std_logic; + signal cfg_interrupt_n : std_logic; + signal cfg_interrupt_rdy_n : std_logic; + signal cfg_pm_wake_n : std_logic; + signal cfg_pcie_link_state_n : std_logic_vector(2 downto 0); + signal cfg_to_turnoff_n : std_logic; + signal cfg_interrupt_assert_n : std_logic; + signal cfg_interrupt_di : std_logic_vector(7 downto 0); + signal cfg_interrupt_do : std_logic_vector(7 downto 0); + signal cfg_interrupt_mmenable : std_logic_vector(2 downto 0); + signal cfg_interrupt_msienable : std_logic; + + signal cfg_trn_pending_n : std_logic; + signal cfg_bus_number : std_logic_vector(7 downto 0); + signal cfg_device_number : std_logic_vector(4 downto 0); + signal cfg_function_number : std_logic_vector(2 downto 0); + signal cfg_status : std_logic_vector(15 downto 0); + signal cfg_command : std_logic_vector(15 downto 0); + signal cfg_dstatus : std_logic_vector(15 downto 0); + signal cfg_dcommand : std_logic_vector(15 downto 0); + signal cfg_lstatus : std_logic_vector(15 downto 0); + signal cfg_lcommand : std_logic_vector(15 downto 0); + signal cfg_dsn : std_logic_vector(63 downto 0); + + signal pcie_clk : std_logic; +begin + pcie_clk_ibuf : IBUFDS port map ( + O => pcie_clk, + I => pcie_clk_p, + IB => pcie_clk_n + ); + + sys_reset_n <= not reset25; + + trn_rdst_rdy_n <= '0'; + trn_rnp_ok_n <= '0'; + trn_rcpl_streaming_n <= '1'; + + trn_tsrc_dsc_n <= '1'; + trn_terrfwd_n <= '1'; + + cfg_di <= (others => '0'); + cfg_byte_en_n <= (others => '1'); + cfg_dwaddr <= (others => '0'); + cfg_wr_en_n <= '1'; + cfg_rd_en_n <= '1'; + + cfg_err_cor_n <= '1'; + cfg_err_cpl_abort_n <= '1'; + cfg_err_cpl_timeout_n <= '1'; + cfg_err_cpl_unexpect_n <= '1'; + cfg_err_ecrc_n <= '1'; + cfg_err_posted_n <= '1'; + cfg_err_tlp_cpl_header <= (others => '0'); + cfg_err_ur_n <= '1'; + cfg_err_locked_n <= '1'; + cfg_interrupt_n <= not interrupt; + cfg_pm_wake_n <= '1'; + cfg_interrupt_assert_n <= '1'; + cfg_interrupt_di <= (others => '0'); + interrupt_rdy <= not cfg_interrupt_rdy_n; + + cfg_trn_pending_n <= '1'; + cfg_dsn <= (others => '0'); + + ep : pcie_core port map ( + pci_exp_rxn => pci_exp_rxn, + pci_exp_rxp => pci_exp_rxp, + pci_exp_txn => pci_exp_txn, + pci_exp_txp => pci_exp_txp, + + sys_clk => pcie_clk, + sys_reset_n => sys_reset_n, + + refclkout => open, + + trn_clk => trn_clk, + trn_reset_n => trn_reset_n, + trn_lnk_up_n => trn_lnk_up_n, + + trn_rd => trn_rd, + trn_rrem_n => trn_rrem_n, + trn_rsof_n => trn_rsof_n, + trn_reof_n => trn_reof_n, + trn_rsrc_dsc_n => trn_rsrc_dsc_n, + trn_rsrc_rdy_n => trn_rsrc_rdy_n, + trn_rbar_hit_n => trn_rbar_hit_n, + trn_rdst_rdy_n => trn_rdst_rdy_n, + trn_rerrfwd_n => trn_rerrfwd_n, + trn_rnp_ok_n => trn_rnp_ok_n, + trn_rfc_npd_av => trn_rfc_npd_av, + trn_rfc_nph_av => trn_rfc_nph_av, + trn_rfc_pd_av => trn_rfc_pd_av, + trn_rfc_ph_av => trn_rfc_ph_av, + trn_rcpl_streaming_n => trn_rcpl_streaming_n, + + trn_td => trn_td, + trn_trem_n => trn_trem_n, + trn_tsof_n => trn_tsof_n, + trn_teof_n => trn_teof_n, + trn_tsrc_dsc_n => trn_tsrc_dsc_n, + trn_tsrc_rdy_n => trn_tsrc_rdy_n, + trn_tdst_dsc_n => trn_tdst_dsc_n, + trn_tdst_rdy_n => trn_tdst_rdy_n, + trn_terrfwd_n => trn_terrfwd_n, + trn_tbuf_av => trn_tbuf_av, + + cfg_do => cfg_do, + cfg_rd_wr_done_n => cfg_rd_wr_done_n, + cfg_di => cfg_di, + cfg_byte_en_n => cfg_byte_en_n, + cfg_dwaddr => cfg_dwaddr, + cfg_wr_en_n => cfg_wr_en_n, + cfg_rd_en_n => cfg_rd_en_n, + + cfg_err_cor_n => cfg_err_cor_n, + cfg_err_cpl_abort_n => cfg_err_cpl_abort_n, + cfg_err_cpl_timeout_n => cfg_err_cpl_timeout_n, + cfg_err_cpl_unexpect_n => cfg_err_cpl_unexpect_n, + cfg_err_ecrc_n => cfg_err_ecrc_n, + cfg_err_posted_n => cfg_err_posted_n, + cfg_err_tlp_cpl_header => cfg_err_tlp_cpl_header, + cfg_err_ur_n => cfg_err_ur_n, + cfg_err_cpl_rdy_n => cfg_err_cpl_rdy_n, + cfg_err_locked_n => cfg_err_locked_n, + cfg_interrupt_n => cfg_interrupt_n, + cfg_interrupt_rdy_n => cfg_interrupt_rdy_n, + cfg_pm_wake_n => cfg_pm_wake_n, + cfg_pcie_link_state_n => cfg_pcie_link_state_n, + cfg_to_turnoff_n => cfg_to_turnoff_n, + cfg_interrupt_assert_n => cfg_interrupt_assert_n, + cfg_interrupt_di => cfg_interrupt_di, + cfg_interrupt_do => cfg_interrupt_do, + cfg_interrupt_mmenable => cfg_interrupt_mmenable, + cfg_interrupt_msienable => cfg_interrupt_msienable, + + cfg_trn_pending_n => cfg_trn_pending_n, + cfg_bus_number => cfg_bus_number, + cfg_device_number => cfg_device_number, + cfg_function_number => cfg_function_number, + cfg_status => cfg_status, + cfg_command => cfg_command, + cfg_dstatus => cfg_dstatus, + cfg_dcommand => cfg_dcommand, + cfg_lstatus => cfg_lstatus, + cfg_lcommand => cfg_lcommand, + cfg_dsn => cfg_dsn, + + fast_train_simulation_only => '0' + ); + + clk125 <= trn_clk; + reset125 <= not trn_reset_n; + + rx_frame <= trn_rd; + rx_sof <= not trn_rsof_n; + rx_eof <= not trn_reof_n; + rx_valid <= not trn_rsrc_rdy_n; + + trn_td <= tx_frame; + trn_tsof_n <= not tx_sof; + trn_teof_n <= not tx_eof; + trn_tsrc_rdy_n <= not tx_valid; + trn_trem_n <= x"0F" when tx_half = '1' else x"00"; + + tx_ready <= not trn_tdst_rdy_n; + + bus_dev_func <= cfg_bus_number & cfg_device_number & cfg_function_number; + + max_read <= cfg_dcommand(14 downto 12); + max_write <= cfg_dcommand(7 downto 5); + + bar0 <= not trn_rbar_hit_n(0); +end arch; + diff --git a/netfpga10g/hdl/port_fifo.vhd b/netfpga10g/hdl/port_fifo.vhd new file mode 100644 index 0000000..ff8c93a --- /dev/null +++ b/netfpga10g/hdl/port_fifo.vhd @@ -0,0 +1,94 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity port_fifo is +generic ( + BITS : integer := 14 +); +port ( + reset : in std_logic; + + rd_clk : in std_logic; + rd_read : in std_logic; + rd_data : out std_logic_vector(63 downto 0); + rd_empty : out std_logic; + rd_count : out std_logic_vector(BITS downto 0); + + wr_clk : in std_logic; + wr_write : in std_logic; + wr_data : in std_logic_vector(63 downto 0); + wr_full : out std_logic; + wr_count : out std_logic_vector(BITS downto 0) +); +end port_fifo; + +architecture arch of port_fifo is + + component data_fifo port ( + rst : in std_logic; + rd_clk : in std_logic; + rd_en : in std_logic; + dout : out std_logic_vector(63 downto 0); + empty : out std_logic; + rd_data_count : out std_logic_vector(BITS downto 0); + wr_clk : in std_logic; + wr_en : in std_logic; + din : in std_logic_vector(63 downto 0); + full : out std_logic; + wr_data_count : out std_logic_vector(BITS downto 0) + ); + end component; + + signal raw_read : std_logic; + signal raw_data : std_logic_vector(63 downto 0); + signal raw_empty : std_logic; + signal raw_count : std_logic_vector(BITS downto 0); + + signal has_extra : std_logic; + signal extra : std_logic_vector(63 downto 0); +begin + rd_data <= extra when has_extra = '1' and rd_read = '0' else raw_data; + rd_empty <= '0' when has_extra = '1' and rd_read = '0' else '1'; + rd_count <= std_logic_vector(unsigned(raw_count) + 1) when has_extra = '1' and rd_read = '0' else raw_count; + + raw_read <= '0' when has_extra = '1' and rd_read = '0' else '1'; + + process (rd_clk, reset) + begin + if reset = '1' then + has_extra <= '0'; + extra <= (others => '0'); + + elsif rising_edge(rd_clk) then + if has_extra = '1' then + if rd_read = '1' then + has_extra <= not raw_empty; + extra <= raw_data; + end if; + else + if rd_read = '0' then + has_extra <= not raw_empty; + extra <= raw_data; + end if; + end if; + end if; + end process; + + fifo : data_fifo port map ( + rst => reset, + + rd_clk => rd_clk, + rd_en => raw_read, + dout => raw_data, + empty => raw_empty, + rd_data_count => raw_count, + + wr_clk => wr_clk, + wr_en => wr_write, + din => wr_data, + full => wr_full, + wr_data_count => wr_count + ); +end arch; diff --git a/netfpga10g/hdl/recv_mux.vhd b/netfpga10g/hdl/recv_mux.vhd new file mode 100644 index 0000000..42932af --- /dev/null +++ b/netfpga10g/hdl/recv_mux.vhd @@ -0,0 +1,86 @@ + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity recv_mux is +generic ( + BUFF_COUNT : integer := 16; + BUFF_BITS : integer := 4 -- 2^4 = 16 +); +port ( + rd_clk : in std_logic; + rd_buff : in std_logic_vector (BUFF_BITS - 1 downto 0); + rd_en : in std_logic; + rd_data : out std_logic_vector (63 downto 0) := (others => '0'); + rd_length : out std_logic_vector (8 downto 0) := (others => '0'); + rd_valid : out std_logic_vector (BUFF_COUNT - 1 downto 0) := (others => '0'); + + wr_clk : in std_logic; + wr_en : in std_logic; + wr_data : in std_logic_vector (63 downto 0); + wr_done : in std_logic; + wr_accept : out std_logic := '0' +); +end recv_mux; + +architecture arch of recv_mux is + type rd_data_t is array (0 to BUFF_COUNT - 1) of std_logic_vector(63 downto 0); + type rd_length_t is array (0 to BUFF_COUNT - 1) of std_logic_vector(8 downto 0); + + signal wr_en_i : std_logic_vector(BUFF_COUNT - 1 downto 0) := (others => '0'); + signal wr_done_i : std_logic_vector(BUFF_COUNT - 1 downto 0) := (others => '0'); + signal wr_accept_i : std_logic_vector(BUFF_COUNT - 1 downto 0) := (others => '0'); + signal wr_buff : integer range 0 to BUFF_COUNT - 1 := 0; + + signal rd_en_i : std_logic_vector(BUFF_COUNT - 1 downto 0) := (others => '0'); + signal rd_data_i : rd_data_t := (others => (others => '0')); + signal rd_length_i : rd_length_t := (others => (others => '0')); + signal rd_buff_i : integer range 0 to BUFF_COUNT - 1 := 0; +begin + rd_buff_i <= to_integer(unsigned(rd_buff)); + + recv_gen: for i in 0 to BUFF_COUNT - 1 generate + recv_buff : entity work.buff port map ( + wr_clk => wr_clk, + wr_en => wr_en_i(i), + wr_data => wr_data, + wr_done => wr_done_i(i), + wr_accept => wr_accept_i(i), + + rd_clk => rd_clk, + rd_en => rd_en_i(i), + rd_data => rd_data_i(i), + rd_length => rd_length_i(i), + rd_valid => rd_valid(i) + ); + + wr_en_i(i) <= wr_en when wr_buff = i else '0'; + wr_done_i(i) <= wr_done when wr_buff = i else '0'; + + rd_en_i(i) <= rd_en when rd_buff_i = i else '0'; + end generate recv_gen; + + rd_data <= rd_data_i(rd_buff_i); + rd_length <= rd_length_i(rd_buff_i); + + wr_accept <= wr_accept_i(wr_buff); + + process (wr_clk) + variable tmp_buff : integer range 0 to BUFF_COUNT - 1; + begin + if rising_edge(wr_clk) then + if wr_accept_i(wr_buff) = '0' then + for i in 0 to BUFF_COUNT - 1 loop + tmp_buff := (i + wr_buff) mod BUFF_COUNT; + + if wr_accept_i(tmp_buff) = '1' then + wr_buff <= tmp_buff; + exit; + end if; + end loop; + end if; + end if; + end process; +end arch; + diff --git a/netfpga10g/hdl/rx_eth.vhd b/netfpga10g/hdl/rx_eth.vhd new file mode 100644 index 0000000..fe6e65e --- /dev/null +++ b/netfpga10g/hdl/rx_eth.vhd @@ -0,0 +1,168 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity rx_eth is port ( + clk : in std_logic; + reset : in std_logic; + + xgmii_rxd : in std_logic_vector(63 downto 0); + xgmii_rxc : in std_logic_vector(7 downto 0); + + rx_data : out std_logic_vector(63 downto 0); + rx_start : out std_logic; + rx_end : out std_logic; + rx_rem : out integer range 0 to 7; + + start_count_out : out std_logic_vector(31 downto 0); + end_count_out : out std_logic_vector(31 downto 0) +); +end rx_eth; + +architecture arch of rx_eth is + constant IDLE : std_logic_vector(7 downto 0) := x"07"; + constant START : std_logic_vector(7 downto 0) := x"FB"; + constant TERMINATE : std_logic_vector(7 downto 0) := x"FD"; + constant ERR : std_logic_vector(7 downto 0) := x"FE"; + + constant PREAMBLE : std_logic_vector(7 downto 0) := "01010101"; + constant SFD : std_logic_vector(7 downto 0) := "11010101"; + + type lanes_t is array (0 to 7) of std_logic_vector(7 downto 0); + signal lanes_a : lanes_t; + signal lanes_b : lanes_t; + + signal control_a : std_logic_vector(7 downto 0); + signal control_b : std_logic_vector(7 downto 0); + + signal use_a : std_logic; + + signal start_count : unsigned(31 downto 0); + signal end_count : unsigned(31 downto 0); +begin + start_count_out <= std_logic_vector(start_count); + end_count_out <= std_logic_vector(end_count); + + rx_lanes_gen : for i in 0 to 7 generate + lanes_a(i) <= xgmii_rxd(7+8*i downto 8*i); + end generate rx_lanes_gen; + + control_a <= xgmii_rxc; + lanes_b(4) <= lanes_a(0); + lanes_b(5) <= lanes_a(1); + lanes_b(6) <= lanes_a(2); + lanes_b(7) <= lanes_a(3); + control_b(4) <= control_a(0); + control_b(5) <= control_a(1); + control_b(6) <= control_a(2); + control_b(7) <= control_a(3); + + rx_logic : process (clk, reset) begin + if reset = '1' then + rx_data <= (others => '0'); + rx_start <= '0'; + rx_end <= '0'; + rx_rem <= 0; + start_count <= (others => '0'); + end_count <= (others => '0'); + lanes_b(0) <= (others => '0'); + lanes_b(1) <= (others => '0'); + lanes_b(2) <= (others => '0'); + lanes_b(3) <= (others => '0'); + control_b(3 downto 0) <= (others => '0'); + use_a <= '1'; + + elsif rising_edge(clk) then + rx_start <= '0'; + rx_end <= '0'; + rx_rem <= 0; + + lanes_b(0) <= lanes_a(4); + lanes_b(1) <= lanes_a(5); + lanes_b(2) <= lanes_a(6); + lanes_b(3) <= lanes_a(7); + control_b(3 downto 0) <= control_a(7 downto 4); + + for i in 0 to 7 loop + if use_a = '1' then + rx_data(63-8*i downto 56-8*i) <= lanes_a(i); + else + rx_data(63-8*i downto 56-8*i) <= lanes_b(i); + end if; + end loop; + + if control_a(0) = '1' and lanes_a(0) = START then + rx_start <= '1'; + use_a <= '1'; + elsif control_b(0) = '1' and lanes_b(0) = START then + rx_start <= '1'; + use_a <= '0'; + start_count <= start_count + 1; + end if; + + if use_a = '1' then + if control_a(0) = '1' and (lanes_a(0) = TERMINATE or lanes_a(0) = ERR) then + rx_end <= '1'; + rx_rem <= 0; + elsif control_a(1) = '1' and (lanes_a(1) = TERMINATE or lanes_a(1) = ERR) then + rx_end <= '1'; + rx_rem <= 1; + elsif control_a(2) = '1' and (lanes_a(2) = TERMINATE or lanes_a(2) = ERR) then + rx_end <= '1'; + rx_rem <= 2; + elsif control_a(3) = '1' and (lanes_a(3) = TERMINATE or lanes_a(3) = ERR) then + rx_end <= '1'; + rx_rem <= 3; + elsif control_a(4) = '1' and (lanes_a(4) = TERMINATE or lanes_a(4) = ERR) then + rx_end <= '1'; + rx_rem <= 4; + elsif control_a(5) = '1' and (lanes_a(5) = TERMINATE or lanes_a(5) = ERR) then + rx_end <= '1'; + rx_rem <= 5; + elsif control_a(6) = '1' and (lanes_a(6) = TERMINATE or lanes_a(6) = ERR) then + rx_end <= '1'; + rx_rem <= 6; + elsif control_a(7) = '1' and (lanes_a(7) = TERMINATE or lanes_a(7) = ERR) then + rx_end <= '1'; + rx_rem <= 7; + end if; + else + if control_b(0) = '1' and (lanes_b(0) = TERMINATE or lanes_b(0) = ERR) then + rx_end <= '1'; + rx_rem <= 0; + end_count <= end_count + 1; + elsif control_b(1) = '1' and (lanes_b(1) = TERMINATE or lanes_b(1) = ERR) then + rx_end <= '1'; + rx_rem <= 1; + end_count <= end_count + 1; + elsif control_b(2) = '1' and (lanes_b(2) = TERMINATE or lanes_b(2) = ERR) then + rx_end <= '1'; + rx_rem <= 2; + end_count <= end_count + 1; + elsif control_b(3) = '1' and (lanes_b(3) = TERMINATE or lanes_b(3) = ERR) then + rx_end <= '1'; + rx_rem <= 3; + end_count <= end_count + 1; + elsif control_b(4) = '1' and (lanes_b(4) = TERMINATE or lanes_b(4) = ERR) then + rx_end <= '1'; + rx_rem <= 4; + end_count <= end_count + 1; + elsif control_b(5) = '1' and (lanes_b(5) = TERMINATE or lanes_b(5) = ERR) then + rx_end <= '1'; + rx_rem <= 5; + end_count <= end_count + 1; + elsif control_b(6) = '1' and (lanes_b(6) = TERMINATE or lanes_b(6) = ERR) then + rx_end <= '1'; + rx_rem <= 6; + end_count <= end_count + 1; + elsif control_b(7) = '1' and (lanes_b(7) = TERMINATE or lanes_b(7) = ERR) then + rx_end <= '1'; + rx_rem <= 7; + end_count <= end_count + 1; + end if; + end if; + end if; + end process; +end arch; + diff --git a/netfpga10g/hdl/send_mux.vhd b/netfpga10g/hdl/send_mux.vhd new file mode 100644 index 0000000..8d9f667 --- /dev/null +++ b/netfpga10g/hdl/send_mux.vhd @@ -0,0 +1,77 @@ + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity send_mux is +generic ( + BUFF_COUNT : integer := 16; + BUFF_BITS : integer := 4 -- 2^4 = 16 +); + Port ( wr_clk : in STD_LOGIC; + wr_buff : in STD_LOGIC_VECTOR (BUFF_BITS - 1 downto 0); + wr_en : in STD_LOGIC; + wr_data : in STD_LOGIC_VECTOR (63 downto 0); + wr_done : in STD_LOGIC; + wr_cancel : in STD_LOGIC_VECTOR (BUFF_COUNT - 1 downto 0); + wr_accept : out STD_LOGIC_VECTOR (BUFF_COUNT - 1 downto 0) := (others => '0'); + rd_clk : in STD_LOGIC; + rd_en : in STD_LOGIC; + rd_data : out STD_LOGIC_VECTOR (63 downto 0) := (others => '0'); + rd_valid : out STD_LOGIC := '0'); +end send_mux; + +architecture arch of send_mux is + type rd_data_t is array (0 to BUFF_COUNT - 1) of std_logic_vector(63 downto 0); + + signal wr_en_i : std_logic_vector(BUFF_COUNT - 1 downto 0) := (others => '0'); + signal wr_done_i : std_logic_vector(BUFF_COUNT - 1 downto 0) := (others => '0'); + + signal rd_en_i : std_logic_vector(BUFF_COUNT - 1 downto 0) := (others => '0'); + signal rd_data_i : rd_data_t := (others => (others => '0')); + signal rd_valid_i : std_logic_vector(BUFF_COUNT - 1 downto 0) := (others => '0'); + signal rd_buff : integer range 0 to BUFF_COUNT - 1 := 0; +begin + send_gen: for i in 0 to BUFF_COUNT - 1 generate + send_buff : entity work.buff port map ( + wr_clk => wr_clk, + wr_en => wr_en_i(i), + wr_data => wr_data, + wr_done => wr_done_i(i), + wr_cancel => wr_cancel(i), + wr_accept => wr_accept(i), + + rd_clk => rd_clk, + rd_en => rd_en_i(i), + rd_data => rd_data_i(i), + rd_length => open, + rd_valid => rd_valid_i(i) + ); + + wr_en_i(i) <= wr_en when to_integer(unsigned(wr_buff)) = i else '0'; + wr_done_i(i) <= wr_done when to_integer(unsigned(wr_buff)) = i else '0'; + + rd_en_i(i) <= rd_en when rd_buff = i else '0'; + end generate send_gen; + + rd_data <= rd_data_i(rd_buff); + rd_valid <= rd_valid_i(rd_buff); + + process (rd_clk) + variable tmp_buff : integer range 0 to BUFF_COUNT - 1; + begin + if rising_edge(rd_clk) then + if rd_valid_i(rd_buff) = '0' then + for i in 0 to BUFF_COUNT - 1 loop + tmp_buff := (i + rd_buff) mod BUFF_COUNT; + + if rd_valid_i(tmp_buff) = '1' then + rd_buff <= tmp_buff; + exit; + end if; + end loop; + end if; + end if; + end process; +end arch; + diff --git a/netfpga10g/hdl/system_loop.vhd b/netfpga10g/hdl/system_loop.vhd new file mode 100644 index 0000000..79031c3 --- /dev/null +++ b/netfpga10g/hdl/system_loop.vhd @@ -0,0 +1,253 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +library unisim; +use unisim.vcomponents.all; + +entity system_loop is +generic ( + BUFF_COUNT : integer := 16; + BUFF_BITS : integer := 4 -- 2^4 = 16 +); +port ( + eth_clk : in std_logic; + pcie_clk : in std_logic; + + rx_frame : in std_logic_vector(63 downto 0); + rx_sof : in std_logic; + rx_eof : in std_logic; + rx_valid : in std_logic; + rx_bar0 : in std_logic; + + tx_frame : out std_logic_vector(63 downto 0); + tx_sof : out std_logic; + tx_eof : out std_logic; + tx_half : out std_logic; + tx_valid : out std_logic; + tx_ready : in std_logic; + + interrupt : out std_logic; + interrupt_rdy : in std_logic; + + max_read : in std_logic_vector(2 downto 0); + max_write : in std_logic_vector(2 downto 0); + + local : in std_logic_vector(15 downto 0); + + xgmii_rxd : in std_logic_vector(63 downto 0); + xgmii_rxc : in std_logic_vector(7 downto 0); + + xgmii_txd : out std_logic_vector(63 downto 0); + xgmii_txc : out std_logic_vector(7 downto 0); + + mdio_command : out std_logic_vector(0 to 27); + mdio_data : in std_logic_vector(0 to 15); + mdio_enable : out std_logic; + mdio_done : in std_logic +); +end system_loop; + +architecture arch of system_loop is + -- send mux + signal send_rd_en : std_logic; + signal send_rd_data : std_logic_vector (63 downto 0); + signal send_rd_valid : std_logic; + + signal send_wr_buff : std_logic_vector (BUFF_BITS - 1 downto 0) := (others => '0'); + signal send_wr_en : std_logic := '0'; + signal send_wr_data : std_logic_vector (63 downto 0) := (others => '0'); + signal send_wr_done : std_logic := '0'; + signal send_wr_cancel : std_logic_vector (BUFF_COUNT - 1 downto 0); + signal send_wr_accept : std_logic_vector (BUFF_COUNT - 1 downto 0); + + -- recv mux + signal recv_wr_en : std_logic; + signal recv_wr_data : std_logic_vector (63 downto 0); + signal recv_wr_done : std_logic; + signal recv_wr_accept : std_logic; + + signal recv_rd_buff : std_logic_vector (BUFF_BITS - 1 downto 0) := (others => '0'); + signal recv_rd_en : std_logic := '0'; + signal recv_rd_data : std_logic_vector (63 downto 0); + signal recv_rd_length : std_logic_vector (8 downto 0); + signal recv_rd_valid : std_logic_vector (BUFF_COUNT - 1 downto 0); + + -- pcie_rx + signal rx_read : std_logic; + signal rx_write : std_logic; + signal rx_complete : std_logic; + signal rx_data : std_logic_vector(63 downto 0); + signal rx_address : std_logic_vector(63 downto 3); + signal rx_tag : std_logic_vector(4 downto 0); + + signal remote : std_logic_vector(23 downto 0); + + -- pcie_tx + signal tx_read : std_logic; + signal tx_write : std_logic; + signal tx_complete : std_logic; + signal tx_data : std_logic_vector(63 downto 0); + signal tx_address : std_logic_vector(63 downto 3); + signal tx_length : std_logic_vector(8 downto 0); + signal tx_tag : std_logic_vector(4 downto 0); + signal tx_accept : std_logic; + signal tx_done : std_logic; +begin + eth_rx : entity work.eth_rx port map ( + clk => eth_clk, + + wr_en => recv_wr_en, + wr_data => recv_wr_data, + wr_done => recv_wr_done, + wr_accept => recv_wr_accept, + + xgmii_rxd => xgmii_rxd, + xgmii_rxc => xgmii_rxc + ); + + eth_tx : entity work.eth_tx port map ( + clk => eth_clk, + + rd_en => send_rd_en, + rd_data => send_rd_data, + rd_valid => send_rd_valid, + + xgmii_txd => xgmii_txd, + xgmii_txc => xgmii_txc + ); + + send_mux : entity work.send_mux + generic map ( + BUFF_COUNT => BUFF_COUNT, + BUFF_BITS => BUFF_BITS + ) + port map ( + wr_clk => pcie_clk, + wr_buff => send_wr_buff, + wr_en => send_wr_en, + wr_data => send_wr_data, + wr_done => send_wr_done, + wr_cancel => send_wr_cancel, + wr_accept => send_wr_accept, + + rd_clk => eth_clk, + rd_en => send_rd_en, + rd_data => send_rd_data, + rd_valid => send_rd_valid + ); + + recv_mux : entity work.recv_mux + generic map ( + BUFF_COUNT => BUFF_COUNT, + BUFF_BITS => BUFF_BITS + ) + port map ( + rd_clk => pcie_clk, + rd_buff => recv_rd_buff, + rd_en => recv_rd_en, + rd_data => recv_rd_data, + rd_length => recv_rd_length, + rd_valid => recv_rd_valid, + + wr_clk => eth_clk, + wr_en => recv_wr_en, + wr_data => recv_wr_data, + wr_done => recv_wr_done, + wr_accept => recv_wr_accept + ); + + engine : entity work.engine + generic map ( + BUFF_COUNT => BUFF_COUNT, + BUFF_BITS => BUFF_BITS + ) + port map ( + clk => pcie_clk, + + rd_buff => recv_rd_buff, + rd_en => recv_rd_en, + rd_data => recv_rd_data, + rd_length => recv_rd_length, + rd_valid => recv_rd_valid, + + wr_buff => send_wr_buff, + wr_en => send_wr_en, + wr_data => send_wr_data, + wr_done => send_wr_done, + wr_cancel => send_wr_cancel, + wr_accept => send_wr_accept, + + rx_read => rx_read, + rx_write => rx_write, + rx_complete => rx_complete, + rx_data => rx_data, + rx_address => rx_address, + rx_tag => rx_tag, + + tx_read => tx_read, + tx_write => tx_write, + tx_complete => tx_complete, + tx_data => tx_data, + tx_address => tx_address, + tx_length => tx_length, + tx_tag => tx_tag, + tx_accept => tx_accept, + tx_done => tx_done, + + interrupt => interrupt, + interrupt_rdy => interrupt_rdy, + + max_read => max_read, + max_write => max_write, + + mdio_command => mdio_command, + mdio_data => mdio_data, + mdio_enable => mdio_enable, + mdio_done => mdio_done + ); + + pcie_rx : entity work.pcie_rx port map ( + clk => pcie_clk, + + frame => rx_frame, + sof => rx_sof, + eof => rx_eof, + valid => rx_valid, + + read => rx_read, + write => rx_write, + complete => rx_complete, + data => rx_data, + address => rx_address, + tag => rx_tag, + remote => remote, + + bar0 => rx_bar0 + ); + + pcie_tx : entity work.pcie_tx port map ( + clk => pcie_clk, + + frame => tx_frame, + sof => tx_sof, + eof => tx_eof, + half => tx_half, + valid => tx_valid, + ready => tx_ready, + + read => tx_read, + write => tx_write, + complete => tx_complete, + data => tx_data, + address => tx_address, + length => tx_length, + tag => tx_tag, + local => local, + remote => remote, + accept => tx_accept, + done => tx_done + ); + +end arch; + diff --git a/netfpga10g/hdl/top.vhd b/netfpga10g/hdl/top.vhd new file mode 100644 index 0000000..83a5002 --- /dev/null +++ b/netfpga10g/hdl/top.vhd @@ -0,0 +1,243 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +Library UNISIM; +use UNISIM.vcomponents.all; + +entity top is port ( + led1 : out std_logic; + led2 : out std_logic; + led3 : out std_logic; + + pcie_clk_p : in std_logic; + pcie_clk_n : in std_logic; + clk25 : in std_logic; + clk100 : in std_logic; + + pci_exp_rxn : in std_logic_vector(7 downto 0); + pci_exp_rxp : in std_logic_vector(7 downto 0); + pci_exp_txn : out std_logic_vector(7 downto 0); + pci_exp_txp : out std_logic_vector(7 downto 0); + + mdio : inout std_logic; + mdc : out std_logic; + phy_reset_n : out std_logic; + + xaui0_clk_p : in std_logic; + xaui0_clk_n : in std_logic; + xaui0_tx_l0_p : out std_logic; + xaui0_tx_l0_n : out std_logic; + xaui0_tx_l1_p : out std_logic; + xaui0_tx_l1_n : out std_logic; + xaui0_tx_l2_p : out std_logic; + xaui0_tx_l2_n : out std_logic; + xaui0_tx_l3_p : out std_logic; + xaui0_tx_l3_n : out std_logic; + xaui0_rx_l0_p : in std_logic; + xaui0_rx_l0_n : in std_logic; + xaui0_rx_l1_p : in std_logic; + xaui0_rx_l1_n : in std_logic; + xaui0_rx_l2_p : in std_logic; + xaui0_rx_l2_n : in std_logic; + xaui0_rx_l3_p : in std_logic; + xaui0_rx_l3_n : in std_logic +); +end top; + +architecture arch of top is + signal clk125 : std_logic; + signal reset125 : std_logic; + + signal count25 : unsigned(6 downto 0) := (others => '0'); + signal reset25 : std_logic := '1'; + + signal clk50 : std_logic; + signal clk156 : std_logic; + + signal rx_frame : std_logic_vector(63 downto 0); + signal rx_sof : std_logic; + signal rx_eof : std_logic; + signal rx_valid : std_logic; + signal rx_bar0 : std_logic; + + signal tx_frame : std_logic_vector(63 downto 0); + signal tx_sof : std_logic; + signal tx_eof : std_logic; + signal tx_half : std_logic; + signal tx_valid : std_logic; + signal tx_ready : std_logic; + + signal interrupt : std_logic; + signal interrupt_rdy : std_logic; + + signal max_read : std_logic_vector(2 downto 0); + signal max_write : std_logic_vector(2 downto 0); + + signal local : std_logic_vector(15 downto 0); + + signal xgmii_rxd : std_logic_vector(63 downto 0); + signal xgmii_rxc : std_logic_vector(7 downto 0); + signal xgmii_txd : std_logic_vector(63 downto 0); + signal xgmii_txc : std_logic_vector(7 downto 0); + + signal mdio_command : std_logic_vector(0 to 27); + signal mdio_data : std_logic_vector(0 to 15); + signal mdio_enable : std_logic; + signal mdio_done : std_logic; + + signal mdio_in : std_logic; + signal mdio_out : std_logic; + signal mdio_Z : std_logic; +begin + led1 <= '1'; + led2 <= '0'; + led3 <= '1'; + + process (clk25) begin + if rising_edge(clk25) then + if count25 = 100 then + reset25 <= '0'; + else + count25 <= count25 + 1; + end if; + end if; + end process; + + process (clk100, reset125) begin + if reset125 = '1' then + clk50 <= '0'; + elsif rising_edge(clk100) then + clk50 <= not clk50; + end if; + end process; + + pcie_wrapper : entity work.pcie_wrapper port map ( + pcie_clk_p => pcie_clk_p, + pcie_clk_n => pcie_clk_n, + reset25 => reset25, + + clk125 => clk125, + reset125 => reset125, + + pci_exp_rxn => pci_exp_rxn, + pci_exp_rxp => pci_exp_rxp, + pci_exp_txn => pci_exp_txn, + pci_exp_txp => pci_exp_txp, + + rx_frame => rx_frame, + rx_sof => rx_sof, + rx_eof => rx_eof, + rx_valid => rx_valid, + + tx_frame => tx_frame, + tx_sof => tx_sof, + tx_eof => tx_eof, + tx_half => tx_half, + tx_valid => tx_valid, + tx_ready => tx_ready, + + bus_dev_func => local, + + max_read => max_read, + max_write => max_write, + + interrupt => interrupt, + interrupt_rdy => interrupt_rdy, + + bar0 => rx_bar0 + ); + + system_loop: entity work.system_loop port map ( + eth_clk => clk156, + pcie_clk => clk125, + + rx_frame => rx_frame, + rx_sof => rx_sof, + rx_eof => rx_eof, + rx_valid => rx_valid, + rx_bar0 => rx_bar0, + + tx_frame => tx_frame, + tx_sof => tx_sof, + tx_eof => tx_eof, + tx_half => tx_half, + tx_valid => tx_valid, + tx_ready => tx_ready, + + interrupt => interrupt, + interrupt_rdy => interrupt_rdy, + + max_read => max_read, + max_write => max_write, + + local => local, + + xgmii_rxd => xgmii_rxd, + xgmii_rxc => xgmii_rxc, + + xgmii_txd => xgmii_txd, + xgmii_txc => xgmii_txc, + + mdio_command => mdio_command, + mdio_data => mdio_data, + mdio_enable => mdio_enable, + mdio_done => mdio_done + ); + + xaui : entity work.xaui_top + generic map ( + REVERSE_LANES => '1' + ) + port map ( + dclk => clk50, + reset => reset125, + xgmii_txd => xgmii_txd, + xgmii_txc => xgmii_txc, + xgmii_rxd => xgmii_rxd, + xgmii_rxc => xgmii_rxc, + clk156_out => clk156, + refclk_p => xaui0_clk_p, + refclk_n => xaui0_clk_n, + xaui_tx_l0_p => xaui0_tx_l0_p, + xaui_tx_l0_n => xaui0_tx_l0_n, + xaui_tx_l1_p => xaui0_tx_l1_p, + xaui_tx_l1_n => xaui0_tx_l1_n, + xaui_tx_l2_p => xaui0_tx_l2_p, + xaui_tx_l2_n => xaui0_tx_l2_n, + xaui_tx_l3_p => xaui0_tx_l3_p, + xaui_tx_l3_n => xaui0_tx_l3_n, + xaui_rx_l0_p => xaui0_rx_l0_p, + xaui_rx_l0_n => xaui0_rx_l0_n, + xaui_rx_l1_p => xaui0_rx_l1_p, + xaui_rx_l1_n => xaui0_rx_l1_n, + xaui_rx_l2_p => xaui0_rx_l2_p, + xaui_rx_l2_n => xaui0_rx_l2_n, + xaui_rx_l3_p => xaui0_rx_l3_p, + xaui_rx_l3_n => xaui0_rx_l3_n + ); + + mdio_iobuf : IOBUF port map ( + O => mdio_in, + IO => mdio, + I => mdio_out, + T => mdio_Z + ); + + mdio_module : entity work.mdio port map ( + clk125 => clk125, + reset125 => reset125, + + command => mdio_command, + data_out => mdio_data, + enable => mdio_enable, + done => mdio_done, + + mdio_in => mdio_in, + mdio_out => mdio_out, + mdio_Z => mdio_Z, + mdc => mdc, + phy_reset_n => phy_reset_n + ); +end arch; diff --git a/netfpga10g/hdl/tx_eth.vhd b/netfpga10g/hdl/tx_eth.vhd new file mode 100644 index 0000000..fab9cac --- /dev/null +++ b/netfpga10g/hdl/tx_eth.vhd @@ -0,0 +1,96 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity tx_eth is port ( + clk : in std_logic; + reset : in std_logic; + + xgmii_txd : out std_logic_vector(63 downto 0); + xgmii_txc : out std_logic_vector(7 downto 0); + + tx_data : in std_logic_vector(63 downto 0); + tx_start : in std_logic; + tx_end : in std_logic; + tx_rem : in integer range 0 to 7; + + start_count_out : out std_logic_vector(31 downto 0); + end_count_out : out std_logic_vector(31 downto 0) +); +end tx_eth; + +architecture arch of tx_eth is + constant IDLE : std_logic_vector(7 downto 0) := x"07"; + constant START : std_logic_vector(7 downto 0) := x"FB"; + constant TERMINATE : std_logic_vector(7 downto 0) := x"FD"; + + constant PREAMBLE : std_logic_vector(7 downto 0) := "01010101"; + constant SFD : std_logic_vector(7 downto 0) := "11010101"; + + type lanes_t is array (0 to 7) of std_logic_vector(7 downto 0); + signal lanes : lanes_t; + + signal in_packet : std_logic; + + signal start_count : unsigned(31 downto 0); + signal end_count : unsigned(31 downto 0); +begin + start_count_out <= std_logic_vector(start_count); + end_count_out <= std_logic_vector(end_count); + + tx_lanes_gen : for i in 0 to 7 generate + xgmii_txd(7+8*i downto 8*i) <= lanes(i); + end generate tx_lanes_gen; + + tx_logic : process (clk, reset) begin + if reset = '1' then + in_packet <= '0'; + start_count <= (others => '0'); + end_count <= (others => '0'); + + for i in 0 to 7 loop + lanes(i) <= IDLE; + xgmii_txc(i) <= '1'; + end loop; + + elsif rising_edge(clk) then + for i in 0 to 7 loop + lanes(i) <= IDLE; + xgmii_txc(i) <= '1'; + end loop; + + if tx_start = '1' then + in_packet <= '1'; + lanes(0) <= START; + xgmii_txc(0) <= '1'; + lanes(1 to 6) <= (others => PREAMBLE); + xgmii_txc(6 downto 1) <= (others => '0'); + lanes(7) <= SFD; + xgmii_txc(7) <= '0'; + start_count <= start_count + 1; + + elsif tx_end = '1' then + in_packet <= '0'; + end_count <= end_count + 1; + + for i in 0 to 7 loop + if i < tx_rem then + lanes(i) <= tx_data(63-8*i downto 56-8*i); + xgmii_txc(i) <= '0'; + elsif i = tx_rem then + lanes(i) <= TERMINATE; + xgmii_txc(i) <= '1'; + end if; + end loop; + + elsif in_packet = '1' then + for i in 0 to 7 loop + lanes(i) <= tx_data(63-8*i downto 56-8*i); + xgmii_txc(i) <= '0'; + end loop; + end if; + end if; + end process; +end arch; + diff --git a/netfpga10g/tests/buff_test.vhd b/netfpga10g/tests/buff_test.vhd new file mode 100644 index 0000000..d9f4a0a --- /dev/null +++ b/netfpga10g/tests/buff_test.vhd @@ -0,0 +1,151 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY buff_test IS +END buff_test; + +ARCHITECTURE behavior OF buff_test IS + + -- Component Declaration for the Unit Under Test (UUT) + + COMPONENT buff + PORT( + wr_clk : IN std_logic; + wr_en : IN std_logic; + wr_data : IN std_logic_vector(63 downto 0); + wr_done : IN std_logic; + wr_accept : OUT std_logic; + rd_clk : IN std_logic; + rd_en : IN std_logic; + rd_data : OUT std_logic_vector(63 downto 0); + rd_length : OUT std_logic_vector(8 downto 0); + rd_valid : OUT std_logic + ); + END COMPONENT; + + + signal wr_clk : std_logic := '0'; + signal wr_en : std_logic := '0'; + signal wr_data : std_logic_vector(63 downto 0) := (others => '0'); + signal wr_done : std_logic := '0'; + signal wr_accept : std_logic; + + signal rd_clk : std_logic := '0'; + signal rd_en : std_logic := '0'; + signal rd_data : std_logic_vector(63 downto 0); + signal rd_length : std_logic_vector(8 downto 0); + signal rd_valid : std_logic; + + -- Clock period definitions + constant wr_clk_period : time := 10 ns; + constant rd_clk_period : time := 7 ns; + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: buff PORT MAP ( + wr_clk => wr_clk, + wr_en => wr_en, + wr_data => wr_data, + wr_done => wr_done, + wr_accept => wr_accept, + rd_clk => rd_clk, + rd_en => rd_en, + rd_data => rd_data, + rd_length => rd_length, + rd_valid => rd_valid + ); + + -- Clock process definitions + wr_clk_process :process + begin + wr_clk <= '0'; + wait for wr_clk_period/2; + wr_clk <= '1'; + wait for wr_clk_period/2; + end process; + + rd_clk_process :process + begin + rd_clk <= '0'; + wait for rd_clk_period/2; + rd_clk <= '1'; + wait for rd_clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + begin + wait for wr_clk_period; + + wr_en <= '1'; + wr_data <= x"0123456789ABCDEF"; + + wait for wr_clk_period; + + wr_en <= '1'; + wr_data <= x"FEDCBA9876543210"; + + wait for wr_clk_period; + + wr_en <= '0'; + wr_data <= x"0000000000000000"; + wr_done <= '1'; + + wait for wr_clk_period; + + wr_done <= '0'; + + wait until wr_accept = '1'; + wait for wr_clk_period / 2; + + wr_en <= '1'; + wr_data <= x"AAAAAAAAAAAAAAAA"; + wait for wr_clk_period; + wr_data <= x"BBBBBBBBBBBBBBBB"; + wait for wr_clk_period; + wr_data <= x"CCCCCCCCCCCCCCCC"; + wait for wr_clk_period; + wr_data <= x"DDDDDDDDDDDDDDDD"; + wait for wr_clk_period; + wr_en <= '0'; + wr_data <= x"0000000000000000"; + wr_done <= '1'; + wait for wr_clk_period; + wr_done <= '0'; + + wait until wr_accept = '1'; + wait for wr_clk_period / 2; + wait for wr_clk_period; + + wr_en <= '1'; + wr_data <= x"0123456789ABCDEF"; + wait for wr_clk_period; + wr_data <= x"FEDCBA9876543210"; + wait for wr_clk_period; + wr_data <= x"0123456789ABCDEF"; + wait for wr_clk_period; + wr_data <= x"FEDCBA9876543210"; + wait for wr_clk_period; + + wr_en <= '0'; + wr_data <= x"0000000000000000"; + wr_done <= '1'; + wait for wr_clk_period; + wr_done <= '0'; + + wait; + end process; + + process + begin + rd_en <= '0'; + wait for rd_clk_period; + rd_en <= '1'; + wait for rd_clk_period * 2; + end process; + +END; diff --git a/netfpga10g/tests/engine_test.vhd b/netfpga10g/tests/engine_test.vhd new file mode 100644 index 0000000..bf1b3c3 --- /dev/null +++ b/netfpga10g/tests/engine_test.vhd @@ -0,0 +1,1123 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY engine_test IS +END engine_test; + +ARCHITECTURE behavior OF engine_test IS + + COMPONENT engine + PORT( + clk : IN std_logic; + rd_buff : OUT std_logic_vector(3 downto 0); + rd_en : OUT std_logic; + rd_data : IN std_logic_vector(63 downto 0); + rd_length : IN std_logic_vector(8 downto 0); + rd_valid : IN std_logic_vector(15 downto 0); + wr_buff : OUT std_logic_vector(3 downto 0); + wr_en : OUT std_logic; + wr_data : OUT std_logic_vector(63 downto 0); + wr_done : OUT std_logic; + wr_accept : IN std_logic_vector(15 downto 0); + rx_read : IN std_logic; + rx_write : IN std_logic; + rx_complete : IN std_logic; + rx_data : IN std_logic_vector(63 downto 0); + rx_address : IN std_logic_vector(63 downto 3); + rx_tag : IN std_logic_vector(4 downto 0); + tx_read : OUT std_logic; + tx_write : OUT std_logic; + tx_complete : OUT std_logic; + tx_data : OUT std_logic_vector(63 downto 0); + tx_address : OUT std_logic_vector(63 downto 3); + tx_length : OUT std_logic_vector(8 downto 0); + tx_tag : OUT std_logic_vector(4 downto 0); + tx_accept : IN std_logic; + tx_done : IN std_logic; + interrupt : OUT std_logic; + interrupt_rdy : IN std_logic; + max_read : IN std_logic_vector(2 downto 0); + max_write : IN std_logic_vector(2 downto 0) + ); + END COMPONENT; + + signal clk : std_logic := '0'; + + signal rd_buff : std_logic_vector(3 downto 0); + signal rd_en : std_logic; + signal rd_data : std_logic_vector(63 downto 0) := (others => '0'); + signal rd_length : std_logic_vector(8 downto 0) := (others => '0'); + signal rd_valid : std_logic_vector(15 downto 0) := (others => '0'); + + signal wr_buff : std_logic_vector(3 downto 0); + signal wr_en : std_logic; + signal wr_data : std_logic_vector(63 downto 0); + signal wr_done : std_logic; + signal wr_accept : std_logic_vector(15 downto 0) := (others => '0'); + + signal rx_read : std_logic := '0'; + signal rx_write : std_logic := '0'; + signal rx_complete : std_logic := '0'; + signal rx_data : std_logic_vector(63 downto 0) := (others => '0'); + signal rx_address : std_logic_vector(63 downto 3) := (others => '0'); + signal rx_tag : std_logic_vector(4 downto 0) := (others => '0'); + + signal tx_read : std_logic; + signal tx_write : std_logic; + signal tx_complete : std_logic; + signal tx_data : std_logic_vector(63 downto 0); + signal tx_address : std_logic_vector(63 downto 3); + signal tx_length : std_logic_vector(8 downto 0); + signal tx_tag : std_logic_vector(4 downto 0); + signal tx_accept : std_logic := '0'; + signal tx_done : std_logic := '0'; + + signal interrupt : std_logic; + signal interrupt_rdy : std_logic := '0'; + + signal max_read : std_logic_vector(2 downto 0) := (others => '0'); + signal max_write : std_logic_vector(2 downto 0) := (others => '0'); + + constant clk_period : time := 10 ns; + + signal test_fail : std_logic := '0'; + + constant CMD_STATUS : std_logic_vector(1 downto 0) := "00"; + constant CMD_SEND : std_logic_vector(1 downto 0) := "01"; + constant CMD_RECV : std_logic_vector(1 downto 0) := "10"; + constant CMD_MDIO : std_logic_vector(1 downto 0) := "11"; + + constant ADDR_31 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(31, 61)); + constant ADDR_32 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(32, 61)); + constant ADDR_4 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(4, 61)); + + constant LEN_3 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(3, 9)); + constant LEN_2 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(2, 9)); + constant LEN_1 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(1, 9)); + + constant BUFF_0 : std_logic_vector(3 downto 0) := std_logic_vector(to_unsigned(0, 4)); + constant BUFF_2 : std_logic_vector(3 downto 0) := std_logic_vector(to_unsigned(2, 4)); + constant BUFF_5 : std_logic_vector(3 downto 0) := std_logic_vector(to_unsigned(5, 4)); + + constant TAG_2 : std_logic_vector(4 downto 0) := std_logic_vector(to_unsigned(2, 5)); + constant TAG_5 : std_logic_vector(4 downto 0) := std_logic_vector(to_unsigned(5, 5)); + + constant EMPTY : std_logic_vector(1 downto 0) := "00"; + constant ADDR : std_logic_vector(1 downto 0) := "01"; + constant DATA : std_logic_vector(1 downto 0) := "10"; + constant FULL : std_logic_vector(1 downto 0) := "11"; + + constant DATA_A : std_logic_vector(63 downto 0) := x"123AAAAAAAAAAAAA"; + constant DATA_B : std_logic_vector(63 downto 0) := x"123BBBBBBBBBBBBB"; + constant DATA_C : std_logic_vector(63 downto 0) := x"123CCCCCCCCCCCCC"; + constant DATA_D : std_logic_vector(63 downto 0) := x"123DDDDDDDDDDDDD"; + constant DATA_E : std_logic_vector(63 downto 0) := x"123EEEEEEEEEEEEE"; +BEGIN + + uut: engine PORT MAP ( + clk => clk, + rd_buff => rd_buff, + rd_en => rd_en, + rd_data => rd_data, + rd_length => rd_length, + rd_valid => rd_valid, + wr_buff => wr_buff, + wr_en => wr_en, + wr_data => wr_data, + wr_done => wr_done, + wr_accept => wr_accept, + rx_read => rx_read, + rx_write => rx_write, + rx_complete => rx_complete, + rx_data => rx_data, + rx_address => rx_address, + rx_tag => rx_tag, + tx_read => tx_read, + tx_write => tx_write, + tx_complete => tx_complete, + tx_data => tx_data, + tx_address => tx_address, + tx_length => tx_length, + tx_tag => tx_tag, + tx_accept => tx_accept, + tx_done => tx_done, + interrupt => interrupt, + interrupt_rdy => interrupt_rdy, + max_read => max_read, + max_write => max_write + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + begin + wr_accept <= (others => '1'); + + wait for clk_period; + + -- read status + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + + wait for clk_period; + + if tx_complete /= '1' then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + + wait for clk_period; + + if tx_complete /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- send page: addr = 31, len = 3, data = ABC, buff = 2 + -- expecting two reads: + -- first: addr = 31, len = 1, tag = 2 + -- second: addr = 32, len = 2, tag = 2 + + rx_write <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_SEND; + rx_address(8 downto 5) <= BUFF_2; + rx_address(18 downto 10) <= LEN_3; + rx_data <= ADDR_31 & "000"; + + wait for clk_period * 3; + + if tx_read /= '1' or + tx_address /= ADDR_31 or + tx_length /= LEN_1 or + tx_tag /= TAG_2 then + test_fail <= '1'; + end if; + + rx_write <= '0'; + rx_address <= (others => '0'); + rx_data <= (others => '0'); + tx_done <= '1'; + + wait for clk_period; + + if tx_read /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- read status again + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + + wait for clk_period; + + if tx_complete /= '1' or + tx_data(2*4 + 1 downto 2*4 + 0) /= DATA or + tx_data(2*4 + 3 downto 2*4 + 2) /= EMPTY then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + + wait for clk_period; + + if tx_complete /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- answer the previous read with completions + -- data = A, tag = 2, len = 1 + rx_complete <= '1'; + rx_data <= DATA_A; + rx_tag <= TAG_2; + + wait for clk_period; + + -- expect wr_en (buff = 2, data = A) + if wr_buff /= BUFF_2 or + wr_en /= '1' or + wr_data /= DATA_A or + wr_done /= '0' or + tx_read /= '0' then + test_fail <= '1'; + end if; + + rx_complete <= '0'; + rx_data <= (others => '0'); + rx_tag <= (others => '0'); + + wait for clk_period * 2; + + -- expect new tx_read (tag 2, len 2, addr 32) + if wr_en /= '0' or + tx_read /= '1' or + tx_tag /= TAG_2 or + tx_length /= LEN_2 or + tx_address /= ADDR_32 then + test_fail <= '1'; + end if; + + tx_done <= '1'; + + wait for clk_period; + + if tx_read /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + -- answer read with completions + -- data = B and C, tag = 2, len = 2 + rx_complete <= '1'; + rx_data <= DATA_B; + rx_tag <= TAG_2; + + wait for clk_period; + + -- expect wr_en (buff = 2, data = B) and no tx action + if wr_buff /= BUFF_2 or + wr_en /= '1' or + wr_data /= DATA_B or + wr_done /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + rx_complete <= '1'; + rx_data <= DATA_C; + rx_tag <= TAG_2; + + wait for clk_period; + + -- expect wr_en (buff = 2, data = C) and no tx action + if wr_buff /= BUFF_2 or + wr_en /= '1' or + wr_data /= DATA_C or + wr_done /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + rx_complete <= '0'; + rx_data <= (others => '0'); + rx_tag <= (others => '0'); + + wait for clk_period; + + -- expect wr_done and no tx action + if wr_done /= '1' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- buff will respond to wr_done with wr_accept = 0 + wr_accept(2) <= '0'; + + wait for clk_period; + + -- read status again + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + + wait for clk_period; + + if tx_complete /= '1' or + tx_data(2*4 + 1 downto 2*4 + 0) /= FULL or + tx_data(2*4 + 3 downto 2*4 + 2) /= EMPTY then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + + wait for clk_period; + + if tx_complete /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + wr_accept(2) <= '1'; + + wait for clk_period; + + -- read status again, but this time buff must be EMPTY + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + + wait for clk_period; + + if tx_complete /= '1' or + tx_data(2*4 + 1 downto 2*4 + 0) /= EMPTY or + tx_data(2*4 + 3 downto 2*4 + 2) /= EMPTY then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + + wait for clk_period; + + -- EMPTY buff doesn't result in interrupt, because status is just read + if tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- RECEIVE PACKET + -- the buff will say there is data to read (rd_valid) + -- interrupt will be send + -- status is read + -- addr will be gotten via rx_write + -- data will be send via tx_write + -- interrupt will be send + + -- no reading and no tx actions + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- buff 5 becomes valid + rd_valid(5) <= '1'; + + wait for clk_period * 2; + + -- expect interrupt + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '1' then + test_fail <= '1'; + end if; + + -- read status again + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + interrupt_rdy <= '1'; + + wait for clk_period; + + -- expect complete, no interrupt + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '1' or + interrupt /= '0' or + tx_data(5*4 + 1 downto 5*4 + 0) /= EMPTY or + tx_data(5*4 + 3 downto 5*4 + 2) /= FULL then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + interrupt_rdy <= '0'; + + wait for clk_period; + + if tx_complete /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- no reading and no tx actions + if rd_en /= '0' or + rd_buff /= BUFF_0 or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- recv page: addr = 4, buff = 5 + rx_write <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_RECV; + rx_address(8 downto 5) <= BUFF_5; + rx_data <= ADDR_4 & "000"; + + wait for clk_period; + + -- no reading and no tx actions + if rd_en /= '0' or + rd_buff /= BUFF_0 or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + rx_write <= '0'; + rx_address <= (others => '0'); + rx_data <= (others => '0'); + + wait for clk_period; + + -- expect to read buff 5, but no tx actions yet + if rd_en /= '0' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- data = D and E, length = 2 + rd_data <= DATA_D; + rd_length <= LEN_2; + + wait for clk_period; + + -- tx_write: data = D, addr = 4, length = 2 + if rd_en /= '0' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '1' or + tx_complete /= '0' or + interrupt /= '0' or + tx_data /= DATA_D or + tx_address /= ADDR_4 or + tx_length /= LEN_2 then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- same + if rd_en /= '0' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '1' or + tx_complete /= '0' or + interrupt /= '0' or + tx_data /= DATA_D or + tx_address /= ADDR_4 or + tx_length /= LEN_2 then + test_fail <= '1'; + end if; + + tx_accept <= '1'; + + wait for clk_period; + + -- data D + if rd_en /= '1' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '1' or + tx_complete /= '0' or + interrupt /= '0' or + tx_data /= DATA_D or + tx_address /= ADDR_4 or + tx_length /= LEN_2 then + test_fail <= '1'; + end if; + + rd_data <= DATA_E; + + wait for clk_period; + + -- data E + if rd_en /= '1' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '1' or + tx_complete /= '0' or + interrupt /= '0' or + tx_data /= DATA_E or + tx_address /= ADDR_4 or + tx_length /= LEN_2 then + test_fail <= '1'; + end if; + + rd_valid(5) <= '0'; + rd_data <= (others => '0'); + rd_length <= (others => '0'); + tx_accept <= '0'; + tx_done <= '1'; + + wait for clk_period; + + -- nothing + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- interrupt because writing is done + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '1' then + test_fail <= '1'; + end if; + + interrupt_rdy <= '1'; + + wait for clk_period; + + -- nothing + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + interrupt_rdy <= '0'; + + wait for clk_period * 5; + + + + -- ====================== + -- LETS GO AGAIN !!!!!!! + -- ====================== + + + + -- read status + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + + wait for clk_period; + + if tx_complete /= '1' then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + + wait for clk_period; + + if tx_complete /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- send page: addr = 31, len = 3, data = ABC, buff = 2 + -- expecting two reads: + -- first: addr = 31, len = 1, tag = 2 + -- second: addr = 32, len = 2, tag = 2 + + rx_write <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_SEND; + rx_address(8 downto 5) <= BUFF_2; + rx_address(18 downto 10) <= LEN_3; + rx_data <= ADDR_31 & "000"; + + wait for clk_period * 3; + + if tx_read /= '1' or + tx_address /= ADDR_31 or + tx_length /= LEN_1 or + tx_tag /= TAG_2 then + test_fail <= '1'; + end if; + + rx_write <= '0'; + rx_address <= (others => '0'); + rx_data <= (others => '0'); + tx_done <= '1'; + + wait for clk_period; + + if tx_read /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- read status again + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + + wait for clk_period; + + if tx_complete /= '1' or + tx_data(2*4 + 1 downto 2*4 + 0) /= DATA or + tx_data(2*4 + 3 downto 2*4 + 2) /= EMPTY then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + + wait for clk_period; + + if tx_complete /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- answer the previous read with completions + -- data = A, tag = 2, len = 1 + rx_complete <= '1'; + rx_data <= DATA_A; + rx_tag <= TAG_2; + + wait for clk_period; + + -- expect wr_en (buff = 2, data = A) + if wr_buff /= BUFF_2 or + wr_en /= '1' or + wr_data /= DATA_A or + wr_done /= '0' or + tx_read /= '0' then + test_fail <= '1'; + end if; + + rx_complete <= '0'; + rx_data <= (others => '0'); + rx_tag <= (others => '0'); + + wait for clk_period * 2; + + -- expect new tx_read (tag 2, len 2, addr 32) + if wr_en /= '0' or + tx_read /= '1' or + tx_tag /= TAG_2 or + tx_length /= LEN_2 or + tx_address /= ADDR_32 then + test_fail <= '1'; + end if; + + tx_done <= '1'; + + wait for clk_period; + + if tx_read /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + -- answer read with completions + -- data = B and C, tag = 2, len = 2 + rx_complete <= '1'; + rx_data <= DATA_B; + rx_tag <= TAG_2; + + wait for clk_period; + + -- expect wr_en (buff = 2, data = B) and no tx action + if wr_buff /= BUFF_2 or + wr_en /= '1' or + wr_data /= DATA_B or + wr_done /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + rx_complete <= '1'; + rx_data <= DATA_C; + rx_tag <= TAG_2; + + wait for clk_period; + + -- expect wr_en (buff = 2, data = C) and no tx action + if wr_buff /= BUFF_2 or + wr_en /= '1' or + wr_data /= DATA_C or + wr_done /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + rx_complete <= '0'; + rx_data <= (others => '0'); + rx_tag <= (others => '0'); + + wait for clk_period; + + -- expect wr_done and no tx action + if wr_done /= '1' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- buff will respond to wr_done with wr_accept = 0 + wr_accept(2) <= '0'; + + wait for clk_period; + + -- read status again + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + + wait for clk_period; + + if tx_complete /= '1' or + tx_data(2*4 + 1 downto 2*4 + 0) /= FULL or + tx_data(2*4 + 3 downto 2*4 + 2) /= EMPTY then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + + wait for clk_period; + + if tx_complete /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + wr_accept(2) <= '1'; + + wait for clk_period; + + -- read status again, but this time buff must be EMPTY + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + + wait for clk_period; + + if tx_complete /= '1' or + tx_data(2*4 + 1 downto 2*4 + 0) /= EMPTY or + tx_data(2*4 + 3 downto 2*4 + 2) /= EMPTY then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + + wait for clk_period; + + -- EMPTY buff doesn't result in interrupt, because status is just read + if tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- RECEIVE PACKET + -- the buff will say there is data to read (rd_valid) + -- interrupt will be send + -- status is read + -- addr will be gotten via rx_write + -- data will be send via tx_write + -- interrupt will be send + + -- no reading and no tx actions + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- buff 5 becomes valid + rd_valid(5) <= '1'; + + wait for clk_period * 2; + + -- expect interrupt + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '1' then + test_fail <= '1'; + end if; + + -- read status again + rx_read <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_STATUS; + interrupt_rdy <= '1'; + + wait for clk_period; + + -- expect complete, no interrupt + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '1' or + interrupt /= '0' or + tx_data(5*4 + 1 downto 5*4 + 0) /= EMPTY or + tx_data(5*4 + 3 downto 5*4 + 2) /= FULL then + test_fail <= '1'; + end if; + + rx_read <= '0'; + tx_done <= '1'; + interrupt_rdy <= '0'; + + wait for clk_period; + + if tx_complete /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- no reading and no tx actions + if rd_en /= '0' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- recv page: addr = 4, buff = 5 + rx_write <= '1'; + rx_address <= (others => '0'); + rx_address(4 downto 3) <= CMD_RECV; + rx_address(8 downto 5) <= BUFF_5; + rx_data <= ADDR_4 & "000"; + + wait for clk_period; + + -- no reading and no tx actions + if rd_en /= '0' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + rx_write <= '0'; + rx_address <= (others => '0'); + rx_data <= (others => '0'); + + wait for clk_period; + + -- expect to read buff 5, but no tx actions yet + if rd_en /= '0' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- data = D and E, length = 2 + rd_data <= DATA_D; + rd_length <= LEN_2; + + wait for clk_period; + + -- tx_write: data = D, addr = 4, length = 2 + if rd_en /= '0' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '1' or + tx_complete /= '0' or + interrupt /= '0' or + tx_data /= DATA_D or + tx_address /= ADDR_4 or + tx_length /= LEN_2 then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- same + if rd_en /= '0' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '1' or + tx_complete /= '0' or + interrupt /= '0' or + tx_data /= DATA_D or + tx_address /= ADDR_4 or + tx_length /= LEN_2 then + test_fail <= '1'; + end if; + + tx_accept <= '1'; + + wait for clk_period; + + -- data D + if rd_en /= '1' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '1' or + tx_complete /= '0' or + interrupt /= '0' or + tx_data /= DATA_D or + tx_address /= ADDR_4 or + tx_length /= LEN_2 then + test_fail <= '1'; + end if; + + rd_data <= DATA_E; + + wait for clk_period; + + -- data E + if rd_en /= '1' or + rd_buff /= BUFF_5 or + tx_read /= '0' or + tx_write /= '1' or + tx_complete /= '0' or + interrupt /= '0' or + tx_data /= DATA_E or + tx_address /= ADDR_4 or + tx_length /= LEN_2 then + test_fail <= '1'; + end if; + + rd_valid(5) <= '0'; + rd_data <= (others => '0'); + rd_length <= (others => '0'); + tx_accept <= '0'; + tx_done <= '1'; + + wait for clk_period; + + -- nothing + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + tx_done <= '0'; + + wait for clk_period; + + -- interrupt because writing is done + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '1' then + test_fail <= '1'; + end if; + + interrupt_rdy <= '1'; + + wait for clk_period; + + -- nothing + if rd_en /= '0' or + tx_read /= '0' or + tx_write /= '0' or + tx_complete /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + interrupt_rdy <= '0'; + + wait for clk_period * 5; + + + + + + + + + wait; + end process; + +END; diff --git a/netfpga10g/tests/eth_buff_loop_test.vhd b/netfpga10g/tests/eth_buff_loop_test.vhd new file mode 100644 index 0000000..b8c5902 --- /dev/null +++ b/netfpga10g/tests/eth_buff_loop_test.vhd @@ -0,0 +1,173 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY eth_buff_loop_test IS +END eth_buff_loop_test; + +ARCHITECTURE behavior OF eth_buff_loop_test IS + + signal eth_clk : std_logic := '0'; + signal pcie_clk: std_logic := '0'; + + signal eth_rd_en : std_logic := '0'; + signal eth_rd_data : std_logic_vector(63 downto 0); + signal eth_rd_length : std_logic_vector(8 downto 0); + signal eth_rd_valid : std_logic; + + signal eth_wr_en : std_logic := '0'; + signal eth_wr_data : std_logic_vector(63 downto 0) := (others => '0'); + signal eth_wr_done : std_logic := '0'; + signal eth_wr_accept : std_logic; + + signal pcie_rd_en : std_logic := '0'; + signal pcie_rd_data : std_logic_vector(63 downto 0); + signal pcie_rd_length : std_logic_vector(8 downto 0); + signal pcie_rd_valid : std_logic; + + signal pcie_wr_en : std_logic := '0'; + signal pcie_wr_data : std_logic_vector(63 downto 0) := (others => '0'); + signal pcie_wr_done : std_logic := '0'; + signal pcie_wr_accept : std_logic; + + constant eth_clk_period : time := 7 ns; + constant pcie_clk_period : time := 10 ns; + + signal xgmii_data : std_logic_vector(63 downto 0); + signal xgmii_control : std_logic_vector(7 downto 0); + + signal test_fail : std_logic := '0'; + +BEGIN + + buff_tx : entity work.buff port map ( + wr_clk => pcie_clk, + wr_en => pcie_wr_en, + wr_data => pcie_wr_data, + wr_done => pcie_wr_done, + wr_accept => pcie_wr_accept, + rd_clk => eth_clk, + rd_en => eth_rd_en, + rd_data => eth_rd_data, + rd_length => eth_rd_length, + rd_valid => eth_rd_valid + ); + + buff_rx : entity work.buff port map ( + wr_clk => eth_clk, + wr_en => eth_wr_en, + wr_data => eth_wr_data, + wr_done => eth_wr_done, + wr_accept => eth_wr_accept, + rd_clk => pcie_clk, + rd_en => pcie_rd_en, + rd_data => pcie_rd_data, + rd_length => pcie_rd_length, + rd_valid => pcie_rd_valid + ); + + eth_rx: entity work.eth_rx port map( + clk => eth_clk, + wr_en => eth_wr_en, + wr_data => eth_wr_data, + wr_done => eth_wr_done, + wr_accept => eth_wr_accept, + xgmii_rxd => xgmii_data, + xgmii_rxc => xgmii_control + ); + + eth_tx: entity work.eth_tx port map ( + clk => eth_clk, + rd_en => eth_rd_en, + rd_data => eth_rd_data, + rd_valid => eth_rd_valid, + xgmii_txd => xgmii_data, + xgmii_txc => xgmii_control + ); + + -- Clock process definitions + eth_clk_process : process + begin + eth_clk <= '0'; + wait for eth_clk_period/2; + eth_clk <= '1'; + wait for eth_clk_period/2; + end process; + + pcie_clk_process :process + begin + pcie_clk <= '0'; + wait for pcie_clk_period/2; + pcie_clk <= '1'; + wait for pcie_clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + begin + wait for pcie_clk_period; + + if pcie_wr_accept /= '1' then + test_fail <= '1'; + end if; + + pcie_wr_en <= '1'; + pcie_wr_data <= x"0123456789ABCDEF"; + + wait for pcie_clk_period; + + pcie_wr_en <= '1'; + pcie_wr_data <= x"AAAAAAAAAAAAAAAA"; + + wait for pcie_clk_period; + + pcie_wr_en <= '0'; + pcie_wr_data <= (others => '0'); + pcie_wr_done <= '1'; + + wait for pcie_clk_period; + + pcie_wr_done <= '0'; + + wait until pcie_rd_valid = '1'; + wait for pcie_clk_period / 2; + + if pcie_rd_data /= x"0123456789ABCDEF" or + pcie_rd_length /= "000000010" then + test_fail <= '1'; + end if; + + pcie_rd_en <= '1'; + + wait for pcie_clk_period; + + if pcie_rd_data /= x"AAAAAAAAAAAAAAAA" then + test_fail <= '1'; + end if; + + pcie_rd_en <= '1'; + + wait for pcie_clk_period; + + if pcie_rd_valid /= '0' or + pcie_rd_data /= x"0000000000000000" or + pcie_rd_length /= "000000000" then + test_fail <= '1'; + end if; + + pcie_rd_en <= '0'; + + wait for pcie_clk_period; + + if pcie_rd_valid /= '0' or + pcie_rd_data /= x"0000000000000000" or + pcie_rd_length /= "000000000" then + test_fail <= '1'; + end if; + + wait; + end process; + +END; diff --git a/netfpga10g/tests/eth_rx_test.vhd b/netfpga10g/tests/eth_rx_test.vhd new file mode 100644 index 0000000..7497a97 --- /dev/null +++ b/netfpga10g/tests/eth_rx_test.vhd @@ -0,0 +1,225 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY eth_rx_test IS +END eth_rx_test; + +ARCHITECTURE behavior OF eth_rx_test IS + + COMPONENT eth_rx + PORT( + clk : IN std_logic; + wr_en : OUT std_logic; + wr_data : OUT std_logic_vector(63 downto 0); + wr_done : OUT std_logic; + wr_accept : IN std_logic; + xgmii_rxd : IN std_logic_vector(63 downto 0); + xgmii_rxc : IN std_logic_vector(7 downto 0) + ); + END COMPONENT; + + signal clk : std_logic := '0'; + + signal wr_en : std_logic; + signal wr_data : std_logic_vector(63 downto 0); + signal wr_done : std_logic; + signal wr_accept : std_logic := '0'; + + signal xgmii_rxd : std_logic_vector(63 downto 0) := (others => '0'); + signal xgmii_rxc : std_logic_vector(7 downto 0) := (others => '0'); + + constant clk_period : time := 10 ns; + + constant IDLE : std_logic_vector(7 downto 0) := x"07"; + constant START : std_logic_vector(7 downto 0) := x"FB"; + constant TERM : std_logic_vector(7 downto 0) := x"FD"; + constant ERR : std_logic_vector(7 downto 0) := x"FE"; + + constant PRE : std_logic_vector(7 downto 0) := "01010101"; + constant SFD : std_logic_vector(7 downto 0) := "11010101"; + + signal test_fail : std_logic := '0'; +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: eth_rx PORT MAP ( + clk => clk, + wr_en => wr_en, + wr_data => wr_data, + wr_done => wr_done, + wr_accept => wr_accept, + xgmii_rxd => xgmii_rxd, + xgmii_rxc => xgmii_rxc + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + begin + xgmii_rxd <= IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE; + xgmii_rxc <= "00000000"; + + wait for clk_period; + + if wr_en /= '0' or + wr_data /= x"0000000000000000" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= SFD & PRE & PRE & PRE & PRE & PRE & PRE & START; + xgmii_rxc <= "00000001"; + wr_accept <= '1'; + + wait for clk_period; + + if wr_en /= '0' or + wr_data /= x"0000000000000000" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= x"EFCDAB8967452301"; + xgmii_rxc <= "00000000"; + + wait for clk_period; + + if wr_en /= '1' or + wr_data /= x"0123456789ABCDEF" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & TERM; + xgmii_rxc <= "11111111"; + + wait for clk_period; + + if wr_done /= '1' then + test_fail <= '1'; + end if; + + xgmii_rxd <= IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE; + xgmii_rxc <= "11111111"; + + wait for clk_period; + + if wr_en /= '0' or + wr_data /= x"0000000000000000" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= SFD & PRE & PRE & PRE & PRE & PRE & PRE & START; + xgmii_rxc <= "00000001"; + wr_accept <= '0'; + + wait for clk_period; + + if wr_en /= '0' or + wr_data /= x"0000000000000000" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= x"EFCDAB8967452301"; + xgmii_rxc <= "00000000"; + + wait for clk_period; + + if wr_en /= '0' or + wr_data /= x"0000000000000000" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= SFD & PRE & PRE & PRE & PRE & PRE & PRE & START; + xgmii_rxc <= "00000001"; + wr_accept <= '1'; + + wait for clk_period; + + if wr_en /= '0' or + wr_data /= x"0000000000000000" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= x"ABCDABCDABCDABCD"; + xgmii_rxc <= "00000000"; + + wait for clk_period; + + if wr_en /= '1' or + wr_data /= x"CDABCDABCDABCDAB" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= IDLE & IDLE & IDLE & ERR & IDLE & IDLE & IDLE & IDLE; + xgmii_rxc <= "00010000"; + + wait for clk_period; + + if wr_done /= '1' then + test_fail <= '1'; + end if; + + xgmii_rxd <= PRE & PRE & PRE & START & IDLE & IDLE & IDLE & IDLE; + xgmii_rxc <= "00011111"; + wr_accept <= '1'; + + wait for clk_period; + + if wr_en /= '0' or + wr_data /= x"0000000000000000" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= x"67452311" & SFD & PRE & PRE & PRE; + xgmii_rxc <= "00000000"; + + wait for clk_period; + + if wr_en /= '0' or + wr_data /= x"0000000000000000" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= IDLE & IDLE & IDLE & TERM & x"EFCDAB89"; + xgmii_rxc <= "11110000"; + + wait for clk_period; + + if wr_en /= '1' or + wr_data /= x"1123456789ABCDEF" or + wr_done /= '0' then + test_fail <= '1'; + end if; + + xgmii_rxd <= IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE; + xgmii_rxc <= "11111111"; + + wait for clk_period; + + if wr_done /= '1' then + test_fail <= '1'; + end if; + + wait; + end process; + +END; diff --git a/netfpga10g/tests/eth_tx_test.vhd b/netfpga10g/tests/eth_tx_test.vhd new file mode 100644 index 0000000..0697b84 --- /dev/null +++ b/netfpga10g/tests/eth_tx_test.vhd @@ -0,0 +1,126 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY eth_tx_test IS +END eth_tx_test; + +ARCHITECTURE behavior OF eth_tx_test IS + + -- Component Declaration for the Unit Under Test (UUT) + + COMPONENT eth_tx + PORT( + clk : IN std_logic; + rd_en : OUT std_logic; + rd_data : IN std_logic_vector(63 downto 0); + rd_valid : IN std_logic; + xgmii_txd : OUT std_logic_vector(63 downto 0); + xgmii_txc : OUT std_logic_vector(7 downto 0) + ); + END COMPONENT; + + signal clk : std_logic := '0'; + signal rd_en : std_logic; + signal rd_data : std_logic_vector(63 downto 0) := (others => '0'); + signal rd_valid : std_logic := '0'; + + signal xgmii_txd : std_logic_vector(63 downto 0); + signal xgmii_txc : std_logic_vector(7 downto 0); + + -- Clock period definitions + constant clk_period : time := 10 ns; + + signal test_fail : std_logic := '0'; + + constant IDLE : std_logic_vector(7 downto 0) := x"07"; + constant START : std_logic_vector(7 downto 0) := x"FB"; + constant TERM : std_logic_vector(7 downto 0) := x"FD"; + + constant PRE : std_logic_vector(7 downto 0) := "01010101"; + constant SFD : std_logic_vector(7 downto 0) := "11010101"; +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: eth_tx PORT MAP ( + clk => clk, + rd_en => rd_en, + rd_data => rd_data, + rd_valid => rd_valid, + xgmii_txd => xgmii_txd, + xgmii_txc => xgmii_txc + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + begin + for i in 1 to 5 loop + + if i = 1 or i = 2 then + wait for clk_period; + + if rd_en /= '0' or + xgmii_txd /= IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE or + xgmii_txc /= "11111111" then + test_fail <= '1'; + end if; + end if; + + rd_valid <= '1'; + rd_data <= x"0123456789ABCDEF"; + + wait for clk_period; + + if rd_en /= '1' or + xgmii_txd /= SFD & PRE & PRE & PRE & PRE & PRE & PRE & START or + xgmii_txc /= "00000001" then + test_fail <= '1'; + end if; + + wait for clk_period; + + if rd_en /= '1' or + xgmii_txd /= x"EFCDAB8967452301" or + xgmii_txc /= "00000000" then + test_fail <= '1'; + end if; + + rd_valid <= '1'; + rd_data <= x"BBBBBBBBBBBBBBBB"; + + wait for clk_period; + + if rd_en /= '1' or + xgmii_txd /= x"BBBBBBBBBBBBBBBB" or + xgmii_txc /= "00000000" then + test_fail <= '1'; + end if; + + rd_valid <= '0'; + rd_data <= x"0000000000000000"; + + wait for clk_period; + + if rd_en /= '0' or + xgmii_txd /= IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & IDLE & TERM or + xgmii_txc /= "11111111" then + test_fail <= '1'; + end if; + + end loop; + + wait; + end process; + +END; diff --git a/netfpga10g/tests/pcie_rx_test.vhd b/netfpga10g/tests/pcie_rx_test.vhd new file mode 100644 index 0000000..4180b81 --- /dev/null +++ b/netfpga10g/tests/pcie_rx_test.vhd @@ -0,0 +1,322 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY pcie_rx_test IS +END pcie_rx_test; + +ARCHITECTURE behavior OF pcie_rx_test IS + + COMPONENT pcie_rx + PORT( + clk : IN std_logic; + frame : IN std_logic_vector(63 downto 0); + sof : IN std_logic; + eof : IN std_logic; + valid : IN std_logic; + read : OUT std_logic; + write : OUT std_logic; + complete : OUT std_logic; + data : OUT std_logic_vector(63 downto 0); + address : OUT std_logic_vector(63 downto 3); + tag : OUT std_logic_vector(4 downto 0); + remote : OUT std_logic_vector(15 downto 0); + bar0 : IN std_logic + ); + END COMPONENT; + + + signal clk : std_logic := '0'; + + signal frame : std_logic_vector(63 downto 0) := (others => '0'); + signal sof : std_logic := '0'; + signal eof : std_logic := '0'; + signal valid : std_logic := '0'; + + signal read : std_logic; + signal write : std_logic; + signal complete : std_logic; + signal data : std_logic_vector(63 downto 0); + signal address : std_logic_vector(63 downto 3); + signal tag : std_logic_vector(4 downto 0); + signal remote : std_logic_vector(15 downto 0); + signal bar0 : std_logic := '0'; + + constant clk_period : time := 10 ns; + + constant ADDR_0 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(0, 61)); + constant ADDR_1 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(1, 61)); + constant ADDR_2 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(2, 61)); + + constant TAG_0 : std_logic_vector(4 downto 0) := "0" & x"0"; + constant TAG_A : std_logic_vector(4 downto 0) := "0" & x"A"; + constant TAG_B : std_logic_vector(4 downto 0) := "0" & x"B"; + + constant ID_0 : std_logic_vector(15 downto 0) := x"0000"; + constant ID_A : std_logic_vector(15 downto 0) := x"AAAA"; + constant ID_B : std_logic_vector(15 downto 0) := x"BBBB"; + + constant DATA_0 : std_logic_vector(63 downto 0) := x"0000000000000000"; + constant DATA_A : std_logic_vector(63 downto 0) := x"AAAAAAAAAAAAAAAA"; + constant DATA_B : std_logic_vector(63 downto 0) := x"BBBBBBBBBBBBBBBB"; + + signal test_fail : std_logic := '0'; + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: pcie_rx PORT MAP ( + clk => clk, + frame => frame, + sof => sof, + eof => eof, + valid => valid, + read => read, + write => write, + complete => complete, + data => data, + address => address, + tag => tag, + remote => remote, + bar0 => bar0 + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + begin + bar0 <= '1'; + + wait for clk_period; + + -- expect nothing + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_0 then + test_fail <= '1'; + end if; + + -- read: addr = 1, tag = A, remote = A + frame <= "0" & "00" & "00000" & + x"00" & + "000000" & "0000000010" & + ID_A & "000" & TAG_A & x"FF"; + sof <= '1'; + eof <= '0'; + valid <= '1'; + + wait for clk_period; + + -- remote = A + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= ADDR_1(31 downto 3) & "000" & x"00000000"; + sof <= '0'; + eof <= '1'; + valid <= '1'; + + wait for clk_period; + + -- read: addr = 1, tag = A, remote = A + if read /= '1' or + write /= '0' or + complete /= '0' or + data /= DATA_0 or + address /= ADDR_1 or + tag /= TAG_A or + remote /= ID_A then + test_fail <= '1'; + end if; + + -- write: data = A, addr = 2 + frame <= "0" & "10" & "00000" & + x"00" & + "000000" & "0000000010" & + ID_B & x"00" & x"FF"; + sof <= '1'; + eof <= '0'; + valid <= '1'; + + wait for clk_period; + + -- remote stays A + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= ADDR_2(31 downto 3) & "000" & DATA_A(63 downto 32); + sof <= '0'; + eof <= '0'; + valid <= '1'; + + wait for clk_period; + + -- expect nothing + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= DATA_A(31 downto 0) & x"00000000"; + sof <= '0'; + eof <= '1'; + valid <= '1'; + + wait for clk_period; + + -- write: data = A, addr = 2 + if read /= '0' or + write /= '1' or + complete /= '0' or + data /= DATA_A or + address /= ADDR_2 or + tag /= TAG_0 or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= (others => '0'); + sof <= '0'; + eof <= '0'; + valid <= '0'; + + wait for clk_period; + + -- expect nothing + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_A then + test_fail <= '1'; + end if; + + -- complete: length = 2x32b, data = A + B, tag = B + frame <= "0" & "10" & "01010" & + x"00" & + "000000" & "0000000100" & + ID_B & x"0004"; + sof <= '1'; + eof <= '0'; + valid <= '1'; + + wait for clk_period; + + -- expect nothing + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= ID_B & "000" & TAG_B & x"00" & + DATA_A(63 downto 32); + sof <= '0'; + eof <= '0'; + valid <= '1'; + + wait for clk_period; + + -- nothing + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= DATA_A(31 downto 0) & DATA_B(63 downto 32); + sof <= '0'; + eof <= '0'; + valid <= '1'; + + wait for clk_period; + + -- completion: data = A, tag = B + if read /= '0' or + write /= '0' or + complete /= '1' or + data /= DATA_A or + address /= ADDR_0 or + tag /= TAG_B or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= (others => '0'); + sof <= '0'; + eof <= '0'; + valid <= '0'; + + wait for clk_period; + + -- nothing + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= DATA_B(31 downto 0) & x"01234567"; + sof <= '0'; + eof <= '1'; + valid <= '1'; + + wait for clk_period; + + -- completion: data = B, tag = B + if read /= '0' or + write /= '0' or + complete /= '1' or + data /= DATA_B or + address /= ADDR_0 or + tag /= TAG_B or + remote /= ID_A then + test_fail <= '1'; + end if; + + frame <= (others => '0'); + sof <= '0'; + eof <= '0'; + valid <= '0'; + + wait for clk_period; + + -- nothing + if read /= '0' or + write /= '0' or + complete /= '0' or + remote /= ID_A then + test_fail <= '1'; + end if; + + + + + + wait; + end process; + +END; diff --git a/netfpga10g/tests/pcie_tx_test.vhd b/netfpga10g/tests/pcie_tx_test.vhd new file mode 100644 index 0000000..4f9e091 --- /dev/null +++ b/netfpga10g/tests/pcie_tx_test.vhd @@ -0,0 +1,561 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY pcie_tx_test IS +END pcie_tx_test; + +ARCHITECTURE behavior OF pcie_tx_test IS + + COMPONENT pcie_tx + PORT( + clk : IN std_logic; + frame : OUT std_logic_vector(63 downto 0); + sof : OUT std_logic; + eof : OUT std_logic; + half : OUT std_logic; + valid : OUT std_logic; + ready : IN std_logic; + read : IN std_logic; + write : IN std_logic; + complete : IN std_logic; + data : IN std_logic_vector(63 downto 0); + address : IN std_logic_vector(63 downto 3); + length : IN std_logic_vector(8 downto 0); + tag : IN std_logic_vector(4 downto 0); + local : IN std_logic_vector(15 downto 0); + remote : IN std_logic_vector(15 downto 0); + accept : OUT std_logic; + done : OUT std_logic + ); + END COMPONENT; + + + signal clk : std_logic := '0'; + + signal read : std_logic := '0'; + signal write : std_logic := '0'; + signal complete : std_logic := '0'; + signal data : std_logic_vector(63 downto 0) := (others => '0'); + signal address : std_logic_vector(63 downto 3) := (others => '0'); + signal length : std_logic_vector(8 downto 0) := (others => '0'); + signal tag : std_logic_vector(4 downto 0) := (others => '0'); + signal local : std_logic_vector(15 downto 0) := (others => '0'); + signal remote : std_logic_vector(15 downto 0) := (others => '0'); + signal accept : std_logic; + signal done : std_logic; + + signal frame : std_logic_vector(63 downto 0); + signal sof : std_logic; + signal eof : std_logic; + signal half : std_logic; + signal valid : std_logic; + signal ready : std_logic := '0'; + + constant clk_period : time := 10 ns; + + signal test_fail : std_logic := '0'; + + constant FRAME_0 : std_logic_vector(63 downto 0) := (others => '0'); + + constant DATA_A : std_logic_vector(63 downto 0) := x"AAAAAAAAAAAAAAAA"; + constant DATA_B : std_logic_vector(63 downto 0) := x"BBBBBBBBBBBBBBBB"; + constant DATA_C : std_logic_vector(63 downto 0) := x"CCCCCCCCCCCCCCCC"; + + constant ADDR_1 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(1, 61)); + constant ADDR_2 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(2, 61)); + constant ADDR_3 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(3, 61)); + constant ADDR_HIGH : std_logic_vector(63 downto 3) := x"100000000000000" & "0"; + + constant LEN_1 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(1, 9)); + constant LEN_2 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(2, 9)); + constant LEN_3 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(3, 9)); + + constant TAG_A : std_logic_vector(4 downto 0) := "0" & x"A"; + constant TAG_B : std_logic_vector(4 downto 0) := "0" & x"B"; + constant TAG_C : std_logic_vector(4 downto 0) := "0" & x"C"; + + constant ID_A : std_logic_vector(15 downto 0) := x"AAAA"; + constant ID_B : std_logic_vector(15 downto 0) := x"BBBB"; + constant ID_C : std_logic_vector(15 downto 0) := x"CCCC"; + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: pcie_tx PORT MAP ( + clk => clk, + frame => frame, + sof => sof, + eof => eof, + half => half, + valid => valid, + ready => ready, + read => read, + write => write, + complete => complete, + data => data, + address => address, + length => length, + tag => tag, + local => local, + remote => remote, + accept => accept, + done => done + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + variable expect : std_logic_vector(63 downto 0) := (others => '0'); + begin + wait for clk_period; + + -- expect nothing + if frame /= FRAME_0 or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '0' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + -- read: addr = 1, len = 1, tag = A, local = A + read <= '1'; + address <= ADDR_1; + length <= LEN_1; + tag <= TAG_A; + local <= ID_A; + + wait for clk_period; + + -- expect 32 bit read: sof valid + expect := "0" & "00" & "00000" & x"00" & + "000000" & "0000000010" & + ID_A & "000" & TAG_A & x"0F"; + + if frame /= expect or + sof /= '1' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period * 3 / 4; + ready <= '1'; + wait for clk_period / 4; + + -- same thing, because ready was 0 during clk + if frame /= expect or + sof /= '1' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period * 3 / 4; + ready <= '0'; + wait for clk_period / 4; + + -- read address: eof half valid + expect := ADDR_1(31 downto 3) & "000" & x"00000000"; + + if frame /= expect or + sof /= '0' or + eof /= '1' or + half /= '1' or + valid /= '1' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period * 3 / 4; + ready <= '1'; + wait for clk_period / 4; + + -- same thing, because ready was 0 + -- but ready now, so done next time + if frame /= expect or + sof /= '0' or + eof /= '1' or + half /= '1' or + valid /= '1' or + accept /= '0' or + done /= '1' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- done, so... + read <= '0'; + write <= '0'; + complete <= '0'; + data <= (others => '0'); + address <= (others => '0'); + length <= (others => '0'); + tag <= (others => '0'); + local <= (others => '0'); + remote <= (others => '0'); + + -- expect nothing + if frame /= FRAME_0 or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '0' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- expect nothing + if frame /= FRAME_0 or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '0' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + -- write: data = B+C, addr = 2, length = 2, local = B + write <= '1'; + data <= DATA_B; + address <= ADDR_2; + length <= LEN_2; + local <= ID_B; + + wait for clk_period; + + -- write: sof valid + expect := "0" & "10" & "00000" & x"00" & + x"0004" & + ID_B & x"00" & x"FF"; + + if frame /= expect or + sof /= '1' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '1' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- write 32bit address + data: valid + expect := ADDR_2(31 downto 3) & "000" & DATA_B(63 downto 32); + + if frame /= expect or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '1' or + done /= '0' then + test_fail <= '1'; + end if; + + data <= DATA_C; + + wait for clk_period; + + -- write data: valid + expect := DATA_B(31 downto 0) & DATA_C(63 downto 32); + + if frame /= expect or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + data <= (others => '0'); + + wait for clk_period; + + -- write half data: eof half valid done + expect := DATA_C(31 downto 0) & x"00000000"; + + if frame /= expect or + sof /= '0' or + eof /= '1' or + half /= '1' or + valid /= '1' or + accept /= '0' or + done /= '1' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- expect nothing + if frame /= FRAME_0 or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '0' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + -- done, so... + read <= '0'; + write <= '0'; + complete <= '0'; + data <= (others => '0'); + address <= (others => '0'); + length <= (others => '0'); + tag <= (others => '0'); + local <= (others => '0'); + remote <= (others => '0'); + + -- complete: data = C, addr = 3, tag = C, local = A, remote = B + complete <= '1'; + data <= DATA_C; + address <= ADDR_3; + tag <= TAG_C; + local <= ID_A; + remote <= ID_B; + + wait for clk_period; + + -- expect completion 64bit + expect := "0" & "10" & "01010" & x"00" & + x"0002" & ID_A & x"0008"; + + if frame /= expect or + sof /= '1' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- compl header + data(higher 32b) + expect := ID_B & "000" & TAG_C & "0" & x"3" & "000" & + DATA_C(63 downto 32); + + if frame /= expect or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- read of compl data: eof half valid done + expect := DATA_C(31 downto 0) & x"00000000"; + + if frame /= expect or + sof /= '0' or + eof /= '1' or + half /= '1' or + valid /= '1' or + accept /= '0' or + done /= '1' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- expect nothing + if frame /= FRAME_0 or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '0' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + -- done, so... + read <= '0'; + write <= '0'; + complete <= '0'; + data <= (others => '0'); + address <= (others => '0'); + length <= (others => '0'); + tag <= (others => '0'); + local <= (others => '0'); + remote <= (others => '0'); + + -- 64bit read: addr = HIGH, length = 3, tag = C, local = C + read <= '1'; + address <= ADDR_HIGH; + length <= LEN_3; + tag <= TAG_C; + local <= ID_C; + + wait for clk_period; + + -- expect 64bit read + expect := "0" & "01" & "00000" & x"00" & x"0006" & + ID_C & "000" & TAG_C & x"FF"; + + if frame /= expect or + sof /= '1' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- expect 64bit address: eof valid done + expect := ADDR_HIGH & "000"; + + if frame /= expect or + sof /= '0' or + eof /= '1' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '1' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- expect nothing + if frame /= FRAME_0 or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '0' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + -- done, so... + read <= '0'; + write <= '0'; + complete <= '0'; + data <= (others => '0'); + address <= (others => '0'); + length <= (others => '0'); + tag <= (others => '0'); + local <= (others => '0'); + remote <= (others => '0'); + + -- 64bit write: addr = HIGH, length = 1, data = A, local = A + write <= '1'; + address <= ADDR_HIGH; + length <= LEN_1; + data <= DATA_A; + local <= ID_A; + + wait for clk_period; + + -- expect 64bit write header; sof valid + expect := "0" & "11" & "00000" & x"00" & x"0002" & + ID_A & x"00" & x"0F"; + + if frame /= expect or + sof /= '1' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- expect addr HIGH: valid accept + expect := ADDR_HIGH & "000"; + + if frame /= expect or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '1' or + accept /= '1' or + done /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- expect data A: eof valid done + expect := DATA_A; + + if frame /= expect or + sof /= '0' or + eof /= '1' or + half /= '0' or + valid /= '1' or + accept /= '0' or + done /= '1' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- expect nothing + if frame /= FRAME_0 or + sof /= '0' or + eof /= '0' or + half /= '0' or + valid /= '0' or + accept /= '0' or + done /= '0' then + test_fail <= '1'; + end if; + + -- done, so... + read <= '0'; + write <= '0'; + complete <= '0'; + data <= (others => '0'); + address <= (others => '0'); + length <= (others => '0'); + tag <= (others => '0'); + local <= (others => '0'); + remote <= (others => '0'); + + wait; + end process; + +END; diff --git a/netfpga10g/tests/queue_test.vhd b/netfpga10g/tests/queue_test.vhd new file mode 100644 index 0000000..dc53ea0 --- /dev/null +++ b/netfpga10g/tests/queue_test.vhd @@ -0,0 +1,149 @@ +-------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 17:42:12 02/23/2017 +-- Design Name: +-- Module Name: /home/alexander/Code/raptor2/hw/tests/queue_test.vhd +-- Project Name: raptor2 +-- Target Device: +-- Tool versions: +-- Description: +-- +-- VHDL Test Bench Created by ISE for module: queue +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- +-- Notes: +-- This testbench has been automatically generated using types std_logic and +-- std_logic_vector for the ports of the unit under test. Xilinx recommends +-- that these types always be used for the top-level I/O of a design in order +-- to guarantee that the testbench will bind correctly to the post-implementation +-- simulation model. +-------------------------------------------------------------------------------- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; + +-- Uncomment the following library declaration if using +-- arithmetic functions with Signed or Unsigned values +--USE ieee.numeric_std.ALL; + +ENTITY queue_test IS +END queue_test; + +ARCHITECTURE behavior OF queue_test IS + + -- Component Declaration for the Unit Under Test (UUT) + + COMPONENT queue + PORT( + clk : IN std_logic; + reset : IN std_logic; + in_data : IN std_logic_vector(63 downto 0); + in_valid : in std_logic; + in_end : IN std_logic; + in_cancel : IN std_logic; + out_data : OUT std_logic_vector(63 downto 0); + out_valid : OUT std_logic; + out_next : IN std_logic + ); + END COMPONENT; + + + --Inputs + signal clk : std_logic := '0'; + signal reset : std_logic := '0'; + signal in_data : std_logic_vector(63 downto 0) := (others => '0'); + signal in_valid : std_logic := '0'; + signal in_end : std_logic := '0'; + signal in_cancel : std_logic := '0'; + signal out_next : std_logic := '0'; + + --Outputs + signal out_data : std_logic_vector(63 downto 0); + signal out_valid : std_logic; + + -- Clock period definitions + constant clk_period : time := 10 ns; + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: queue PORT MAP ( + clk => clk, + reset => reset, + in_data => in_data, + in_valid => in_valid, + in_end => in_end, + in_cancel => in_cancel, + out_data => out_data, + out_valid => out_valid, + out_next => out_next + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + -- TESTS + process begin + reset <= '1'; + wait for 5 ns; + reset <= '0'; + wait; + end process; + + process begin + wait for clk_period * 2; + in_data <= x"AAAAAAAAAAAAAAAA"; + in_valid <= '1'; + wait for clk_period; + in_data <= x"BBBBBBBBBBBBBBBB"; + in_valid <= '0'; + wait for clk_period; + in_data <= x"CCCCCCCCCCCCCCCC"; + in_valid <= '1'; + wait for clk_period; + in_data <= x"DDDDDDDDDDDDDDDD"; + in_valid <= '1'; + in_end <= '1'; + wait for clk_period; + in_valid <= '0'; + in_end <= '0'; + + wait for clk_period * 2; + in_data <= x"AAAAAAAAAAAAAAAA"; + in_valid <= '1'; + wait for clk_period; + in_data <= x"BBBBBBBBBBBBBBBB"; + in_valid <= '1'; + wait for clk_period; + in_data <= x"CCCCCCCCCCCCCCCC"; + in_valid <= '1'; + wait for clk_period; + in_data <= x"DDDDDDDDDDDDDDDD"; + in_valid <= '1'; + in_cancel <= '1'; + wait for clk_period; + in_valid <= '0'; + in_cancel <= '0'; + end process; + + process begin + wait for clk_period * 15; + out_next <= '1'; + wait for clk_period * 2; + out_next <= '0'; + wait for clk_period * 2; + out_next <= '1'; + end process; +END; diff --git a/netfpga10g/tests/send_mux_test.vhd b/netfpga10g/tests/send_mux_test.vhd new file mode 100644 index 0000000..f737ca9 --- /dev/null +++ b/netfpga10g/tests/send_mux_test.vhd @@ -0,0 +1,199 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY send_mux_test IS +END send_mux_test; + +ARCHITECTURE behavior OF send_mux_test IS + + COMPONENT send_mux + PORT( + wr_clk : IN std_logic; + wr_buff : IN std_logic_vector(3 downto 0); + wr_en : IN std_logic; + wr_data : IN std_logic_vector(63 downto 0); + wr_done : IN std_logic; + wr_accept : OUT std_logic_vector(15 downto 0); + rd_clk : IN std_logic; + rd_en : IN std_logic; + rd_data : OUT std_logic_vector(63 downto 0); + rd_valid : OUT std_logic + ); + END COMPONENT; + + signal wr_clk : std_logic := '0'; + signal wr_buff : std_logic_vector(3 downto 0) := (others => '0'); + signal wr_en : std_logic := '0'; + signal wr_data : std_logic_vector(63 downto 0) := (others => '0'); + signal wr_done : std_logic := '0'; + signal wr_accept : std_logic_vector(15 downto 0); + + signal rd_clk : std_logic := '0'; + signal rd_en : std_logic := '0'; + signal rd_data : std_logic_vector(63 downto 0); + signal rd_valid : std_logic; + + constant wr_clk_period : time := 10 ns; + constant rd_clk_period : time := 7 ns; + + constant DATA_A : std_logic_vector(63 downto 0) := x"AAAAAAAAAAAAAAAA"; + constant DATA_B : std_logic_vector(63 downto 0) := x"BBBBBBBBBBBBBBBB"; + constant DATA_C : std_logic_vector(63 downto 0) := x"CCCCCCCCCCCCCCCC"; + + constant BUFF_1 : std_logic_vector (3 downto 0) := x"1"; + constant BUFF_2 : std_logic_vector (3 downto 0) := x"2"; + constant BUFF_3 : std_logic_vector (3 downto 0) := x"3"; + + signal test_fail : std_logic := '0'; + signal test_done : std_logic := '0'; + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: send_mux PORT MAP ( + wr_clk => wr_clk, + wr_buff => wr_buff, + wr_en => wr_en, + wr_data => wr_data, + wr_done => wr_done, + wr_accept => wr_accept, + rd_clk => rd_clk, + rd_en => rd_en, + rd_data => rd_data, + rd_valid => rd_valid + ); + + -- Clock process definitions + wr_clk_process :process + begin + wr_clk <= '0'; + wait for wr_clk_period/2; + wr_clk <= '1'; + wait for wr_clk_period/2; + end process; + + rd_clk_process :process + begin + rd_clk <= '0'; + wait for rd_clk_period/2; + rd_clk <= '1'; + wait for rd_clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + begin + wait for wr_clk_period; + + if rd_valid /= '0' or + wr_accept /= x"FFFF" then + test_fail <= '1'; + end if; + + wr_buff <= BUFF_1; + wr_en <= '1'; + wr_data <= DATA_A; + wr_done <= '0'; + + wait for wr_clk_period; + + if rd_valid /= '0' or + wr_accept /= x"FFFF" then + test_fail <= '1'; + end if; + + wr_buff <= BUFF_2; + wr_en <= '1'; + wr_data <= DATA_A; + wr_done <= '0'; + + wait for wr_clk_period; + + if rd_valid /= '0' or + wr_accept /= x"FFFF" then + test_fail <= '1'; + end if; + + wr_buff <= BUFF_3; + wr_en <= '1'; + wr_data <= DATA_A; + wr_done <= '0'; + + wait for wr_clk_period; + + if rd_valid /= '0' or + wr_accept /= x"FFFF" then + test_fail <= '1'; + end if; + + wr_buff <= BUFF_1; + wr_en <= '1'; + wr_data <= DATA_B; + wr_done <= '0'; + + wait for wr_clk_period; + + if rd_valid /= '0' or + wr_accept /= x"FFFF" then + test_fail <= '1'; + end if; + + wr_buff <= BUFF_1; + wr_en <= '0'; + wr_data <= (others => '0'); + wr_done <= '1'; + + wait for wr_clk_period; + + if rd_valid /= '0' or + wr_accept /= x"FFFD" then + test_fail <= '1'; + end if; + + wr_buff <= BUFF_1; + wr_en <= '0'; + wr_data <= (others => '0'); + wr_done <= '0'; + + wait until rd_valid = '1'; + wait for rd_clk_period / 2; + + if rd_valid /= '1' or + rd_data /= DATA_A or + wr_accept /= x"FFFD" then + test_fail <= '1'; + end if; + + rd_en <= '1'; + + wait for rd_clk_period; + + if rd_valid /= '1' or + rd_data /= DATA_B or + wr_accept /= x"FFFD" then + test_fail <= '1'; + end if; + + rd_en <= '1'; + + wait for rd_clk_period; + + if rd_valid /= '0' or + wr_accept /= x"FFFD" then + test_fail <= '1'; + end if; + + rd_en <= '0'; + + wait until wr_accept(1) = '1'; + + report "done"; + test_done <= '1'; + + wait; + end process; + +END; diff --git a/netfpga10g/tests/system_loop_test.vhd b/netfpga10g/tests/system_loop_test.vhd new file mode 100644 index 0000000..81a4f6e --- /dev/null +++ b/netfpga10g/tests/system_loop_test.vhd @@ -0,0 +1,285 @@ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY system_loop_test IS +END system_loop_test; + +ARCHITECTURE behavior OF system_loop_test IS + + COMPONENT system_loop + PORT( + clk : IN std_logic; + + rx_frame : IN std_logic_vector(63 downto 0); + rx_sof : IN std_logic; + rx_eof : IN std_logic; + rx_valid : IN std_logic; + rx_bar0 : IN std_logic; + + tx_frame : OUT std_logic_vector(63 downto 0); + tx_sof : OUT std_logic; + tx_eof : OUT std_logic; + tx_half : OUT std_logic; + tx_valid : OUT std_logic; + tx_ready : IN std_logic; + + interrupt : OUT std_logic; + interrupt_rdy : IN std_logic; + max_read : IN std_logic_vector(2 downto 0); + max_write : IN std_logic_vector(2 downto 0); + local : IN std_logic_vector(15 downto 0) + ); + END COMPONENT; + + signal clk : std_logic := '0'; + + signal rx_frame : std_logic_vector(63 downto 0) := (others => '0'); + signal rx_sof : std_logic := '0'; + signal rx_eof : std_logic := '0'; + signal rx_valid : std_logic := '0'; + signal rx_bar0 : std_logic := '0'; + + signal tx_frame : std_logic_vector(63 downto 0); + signal tx_sof : std_logic; + signal tx_eof : std_logic; + signal tx_half : std_logic; + signal tx_valid : std_logic; + signal tx_ready : std_logic := '0'; + + signal interrupt : std_logic; + signal interrupt_rdy : std_logic := '0'; + + signal max_read : std_logic_vector(2 downto 0) := (others => '0'); + signal max_write : std_logic_vector(2 downto 0) := (others => '0'); + signal local : std_logic_vector(15 downto 0) := (others => '0'); + + constant clk_period : time := 10 ns; + + signal test_fail : std_logic := '0'; + + constant LEN_1 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(1, 9)); + constant LEN_2 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(2, 9)); + constant LEN_3 : std_logic_vector(8 downto 0) := std_logic_vector(to_unsigned(3, 9)); + + constant TAG_1 : std_logic_vector(4 downto 0) := std_logic_vector(to_unsigned(1, 5)); + constant TAG_2 : std_logic_vector(4 downto 0) := std_logic_vector(to_unsigned(2, 5)); + constant TAG_3 : std_logic_vector(4 downto 0) := std_logic_vector(to_unsigned(3, 5)); + + constant ADDR_1 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(1, 61)); + constant ADDR_2 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(2, 61)); + constant ADDR_3 : std_logic_vector(63 downto 3) := std_logic_vector(to_unsigned(3, 61)); + + constant DATA_A : std_logic_vector(63 downto 0) := x"AAAAAAAAAAAAAAAA"; + constant DATA_B : std_logic_vector(63 downto 0) := x"BBBBBBBBBBBBBBBB"; + constant DATA_C : std_logic_vector(63 downto 0) := x"CCCCCCCCCCCCCCCC"; + + constant ID_A : std_logic_vector(15 downto 0) := x"AAAA"; + constant ID_B : std_logic_vector(15 downto 0) := x"BBBB"; + constant ID_C : std_logic_vector(15 downto 0) := x"CCCC"; + + constant BUFF_1 : std_logic_vector(3 downto 0) := x"1"; + constant BUFF_2 : std_logic_vector(3 downto 0) := x"2"; + constant BUFF_3 : std_logic_vector(3 downto 0) := x"3"; + + constant CMD_STATUS : std_logic_vector(1 downto 0) := "00"; + constant CMD_SEND : std_logic_vector(1 downto 0) := "01"; + constant CMD_RECV : std_logic_vector(1 downto 0) := "10"; + constant CMD_MDIO : std_logic_vector(1 downto 0) := "11"; + + constant FRAME_0 : std_logic_vector(63 downto 0) := (others => '0'); + +BEGIN + + -- Instantiate the Unit Under Test (UUT) + uut: system_loop PORT MAP ( + clk => clk, + rx_frame => rx_frame, + rx_sof => rx_sof, + rx_eof => rx_eof, + rx_valid => rx_valid, + rx_bar0 => rx_bar0, + tx_frame => tx_frame, + tx_sof => tx_sof, + tx_eof => tx_eof, + tx_half => tx_half, + tx_valid => tx_valid, + tx_ready => tx_ready, + interrupt => interrupt, + interrupt_rdy => interrupt_rdy, + max_read => max_read, + max_write => max_write, + local => local + ); + + -- Clock process definitions + clk_process :process + begin + clk <= '0'; + wait for clk_period/2; + clk <= '1'; + wait for clk_period/2; + end process; + + + -- Stimulus process + stim_proc: process + variable bar_addr : std_logic_vector(31 downto 0); + variable bar_data : std_logic_vector(63 downto 0); + variable expect : std_logic_vector(63 downto 0); + variable remote : std_logic_vector(15 downto 0); + begin + -- local = A + -- remote = B + local <= ID_A; + remote := ID_B; + + -- always bar0 + rx_bar0 <= '1'; + + wait for clk_period; + + -- nothing + if tx_frame /= FRAME_0 or + tx_sof /= '0' or + tx_eof /= '0' or + tx_half /= '0' or + tx_valid /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- rx_write of 64 bits to bar + rx_frame <= "0" & "10" & "00000" & x"00" & x"0002" & + remote & x"00" & x"0F"; + rx_sof <= '1'; + rx_eof <= '0'; + rx_valid <= '1'; + + wait for clk_period; + + -- nothing + if tx_frame /= FRAME_0 or + tx_sof /= '0' or + tx_eof /= '0' or + tx_half /= '0' or + tx_valid /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + -- rx_write: + -- bar_addr: cmd = SEND, buff = 2, len = 2 + -- bar_data: addr = 2 + bar_addr := (others => '0'); + bar_addr(4 downto 3) := CMD_SEND; + bar_addr(8 downto 5) := BUFF_2; + bar_addr(18 downto 10) := LEN_2; + bar_data := ADDR_2 & "000"; + + rx_frame <= bar_addr & bar_data(63 downto 32); + rx_sof <= '0'; + rx_eof <= '0'; + rx_valid <= '1'; + + wait for clk_period; + + -- nothing + if tx_frame /= FRAME_0 or + tx_sof /= '0' or + tx_eof /= '0' or + tx_half /= '0' or + tx_valid /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + rx_frame <= bar_data(31 downto 0) & x"00000000"; + rx_sof <= '0'; + rx_eof <= '1'; + rx_valid <= '1'; + + wait for clk_period; + + -- nothing + if tx_frame /= FRAME_0 or + tx_sof /= '0' or + tx_eof /= '0' or + tx_half /= '0' or + tx_valid /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + rx_frame <= (others => '0'); + rx_sof <= '0'; + rx_eof <= '0'; + rx_valid <= '0'; + + wait for clk_period; + + -- nothing + if tx_frame /= FRAME_0 or + tx_sof /= '0' or + tx_eof /= '0' or + tx_half /= '0' or + tx_valid /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + wait for clk_period; + + -- tx_read: addr = 2, len = 2, tag = 2 + expect := "0" & "00" & "00000" & x"00" & "000000" & LEN_2 & "0" & + local & "000" & TAG_2 & x"FF"; + + if tx_frame /= expect or + tx_sof /= '1' or + tx_eof /= '0' or + tx_half /= '0' or + tx_valid /= '1' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + tx_ready <= '1'; + + wait for clk_period; + + expect := ADDR_2(31 downto 3) & "000" & x"00000000"; + + if tx_frame /= expect or + tx_sof /= '0' or + tx_eof /= '1' or + tx_half /= '1' or + tx_valid /= '1' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + tx_ready <= '1'; + + wait for clk_period; + + -- nothing + if tx_frame /= FRAME_0 or + tx_sof /= '0' or + tx_eof /= '0' or + tx_half /= '0' or + tx_valid /= '0' or + interrupt /= '0' then + test_fail <= '1'; + end if; + + tx_ready <= '0'; + + + + + + wait; + end process; + +END; -- cgit v1.2.3