В данном проекте мы создадим систему на основе софт процессора Nios II, ядро Ethernet-интерфейса с поддержкой скоростей 10/100/1000, контроллер SGDMA, контроллер SDRAM и другие аппаратные компоненты для передачи и приема TCP пакетов. В дизайн добавлены два модуля фазовой автоподстройки частоты для генерации тактовых сигналов с различными частотами, чтобы тактировать трехскоростную систему Ethernet (которая реализует функцию MAC) для работы на скорости 10/100/1000 Мбит/с. После сборки аппаратной системы и загрузки схемы в ПЛИС, мы запустим прикладную программу, написанную на языке Си. На основе входных сигналов от платы наша программа устанавливает и закрывает TCP-соединение, передает и принимает кадры данных от порта Ethernet платы. Кадры Ethernet передаются на основе протокола Stop and Wait, а таймер процессора NIOS используется для повторной передачи кадров после таймаута.
На рисунке ниже, представлена схема получившейся SOPC:
Рассмотрим компоненты, составляющие нашу SOPC:
Компонент sys_clk (Clock Source) Входной буфер для сигнала частоты и сброса.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
clock_source | Clock frequency | 100000000 | Hz |
clock_source | Clock frequency is known | Yes | |
clock_source | Reset synchronus edges | None |
Компонент nios2_gen2_0 (Nios II Processor) основной процессор системы. окне настроек выбрать NiosII/f, остальные настройки описаны в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Main | Nios II Core | Nios II/e | |
Reset Vector | Reset vector memory | onchip_memory0_0.s1 | |
Reset Vector | Reset vector offset | 0x00000000 | |
Reset Vector | Reset vector | 0x01000000 | |
Exeption Vector | Exeption vector memory | onchip_memory0_0.s1 | |
Exeption Vector | Exeption vector offset | 0x00000020 | |
Exeption Vector | Exeption vector | 0x01000020 | |
Fast TLB Miss Exeption Vector | Fast TLB Miss Exeption vector memory | nios2_gen2_0.debug_mem_slave | |
Fast TLB Miss Exeption Vector | Fast TLB Miss Exeption vector offset | 0x00000040 | |
Fast TLB Miss Exeption Vector | Fast TLB Miss Exeption vector | 0x00000000 |
Компонент new_sdram_controller_0 (SDRAM Controller Intel FPGA IP) Контроллер SDRAM памяти. В данном случае в SDRAM будет размещаться память программ и буфера для приема/передачи TCP пакеты. Настройки контроллера приведены в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Data Width | Bits | 8 | |
Architecture | Chip select | 1 | |
Architecture | Banks | 4 | |
Address Width | Row | 12 | |
Address Width | Column | 10 | |
Timing | Cas latency cycles | 2 | |
Timing | Initialization refresh cycles | 8 | |
Timing | Issue one refresh command every | 7.8125 | uS |
Timing | Delay after powerup, before initialization | 200.0 | uS |
Timing | Duration of refresh command (t_rfc) | 70.0 | nS |
Timing | Duration of precharge command (t_rp) | 20.0 | nS |
Timing | ACTIVE to READ or WRITE delay (t_rcd) | 20.0 | nS |
Timing | Access time (t_ac) | 5.5 | nS |
Timing | Write recovery time (t_wr, no auto precharge) | 14.0 | nS |
Компонент jtag_usart_0 (JTAG UART Intel FPGA IP) интерфейс отладчика системы. Компонент, предназначенный для передачи данных из Nios в IDE (аналог semihosting в ARM). Полезен для отладки.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Write FIFA (Data from Avalon to JTAG | Buffer depth (bytes) | 64 | bytes |
Write FIFA (Data from Avalon to JTAG | IRQ threshold | 8 | |
Write FIFA (Data from Avalon to JTAG | Constuct using registers | No | |
Read FIFA (Data from JTAG to Avalon | Buffer depth (bytes) | 64 | bytes |
Read FIFA (Data from JTAG to Avalon | IRQ threshold | 8 | |
Read FIFA (Data from JTAG to Avalon | Constuct using registers | No |
Компонент tse (Triple-Speed Ethernet Intel FPGA IP) Контроллер трехскоростного драйвера MAC. Настройки контроллера приведены в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Core Variations | Core Variations | 10/100/1000Mb Ethernet MAC | |
10/100/1000Mb Ethernet MAC | Interface | RGMII | |
10/100/1000Mb Ethernet MAC | Use clock enable for MAC | No | |
10/100/1000Mb Ethernet MAC | Use internal FIFO | Yes | |
10/100/1000Mb Ethernet MAC | Number of ports | 1 | ; |
Ethernet MAC Options | Enable MAC 10/100 half duplex support | Yes | |
Ethernet MAC Options | Enable local loopback on MII/GMII/RGMII | No | |
Ethernet MAC Options | Enable supplemental MAC unicast addresses | No | |
Ethernet MAC Options | Include statistics counters | Yes | |
Ethernet MAC Options | Enable 64-bit statistics byte counters | Yes | |
Ethernet MAC Options | Incluse multicast hashtable | No | |
Ethernet MAC Options | Align packet headers to 32-bit boundary | Yes | |
Ethernet MAC Options | Enable full-duplex flow control | Yes | |
Ethernet MAC Options | Enable VLAN detection | No | |
Ethernet MAC Options | Enable magic packet detection | No | |
MDIO Module | Include MDIO module (MDC/MDIO) | Yes | |
MDIO Module | Host clock divisor | 40 | |
FIFO Options Width | Width | 32 | bits |
FIFO Options Depth | Transmit | 4096*32 | bits |
FIFO Options Depth | Receive | 4096*32 | bits |
Компонент sgdma_rx (Scatter-Gather DMA Controller Intel FPGA IP) Контроллер DMA для приема данных. Настройки контроллера приведены в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Transfer options | Transfer mode | Stream To Memory | |
Data and error widths | Data width | 32 | |
Data and error widths | Source error width | 0 | |
Data and error widths | Sink error width | 6 | |
FIFO depth | Data transfer FIFO depth | 64 |
Компонент sgdma_tx (Scatter-Gather DMA Controller Intel FPGA IP) Контроллер DMA для передачи данных. Настройки контроллера приведены в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Transfer options | Transfer mode | Memory To Stream | |
Data and error widths | Data width | 32 | |
Data and error widths | Source error width | 1 | |
Data and error widths | Sink error width | 0 | |
FIFO depth | Data transfer FIFO depth | 64 |
Компонент descriptor_memory (On-Chip Memory (RAM or ROM) Intel FPGA IP) Контроллер набортной памяти для хранения дескрипторов передаваемых данных. Настройки контроллера приведены в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Size | Slave S1 Data width | 8 | |
Size | Total memory size | 4096 | bytes |
В настройках компонентов led и switch нет ни чего интересного. это обычные компоненты ввода/вывода дискретных сигналов.
Компонент timer_0 (Interval Timer Intel FPGA IP) Таймер для создания интервалов времени. Настройки контроллера приведены в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Timeout period | Period | 30 | |
Timeout period | Units | uS | |
Timer counter size | Counter Size | 32 | |
Registers | No Start/Stop controls bits | No | |
Registers | Fixed period | No | |
Registers | Readeable snapshot | Yes | |
Output signals | System reset on timeout (Watchdog) | No | |
Output signals | Timeout pulse (1 clock wide) | No |
Верхний уровень системы:
Verilog Code:
module simplified_tcp( // module and port declaration: fill the gaps input CLOCK_50, // KEY input [3:0]KEY, //input KEY , verify if needed. //LED output [7:0] S1_LED, // Ethernet : the signals used are: //the RGMII transmit clock, //the MDC reference, //the MDIO, //the hardware reset, //the RGMII receive clock, //the receive data, //the receive data valid, //the transmit data and //the transmit enable (check the manual) output ENET_GTX_CLK, input ENET_RX_CLK, output ENET_MDC, inout ENET_MDIO, //input ENET_TX_CLK, output [3:0]ENET_TX_DATA, output ENET_RST_N, input [3:0]ENET_RX_DATA, input ENET_RX_DV, output ENET_TX_EN, //sdram memory inout [7:0]dq, output [11:0]addr, output [1:0]ba, output cas_n, output dqm, output ras_n, output we_n, output clk_n ); wire sys_clk, clk_125, clk_25, clk_2p5; wire clk_sdram,clk1_125,clk1_25,clk1_2p5; wire rx_clk, tx_clk; wire core_reset_n; wire mdc, mdio_in, mdio_oen, mdio_out; wire eth_mode, ena_10; wire chpScpClk; wire [3:0]ENET_RX_DATA_BUF; assign rx_clk = ENET_RX_CLK; // Assign MDIO and MDC signals assign mdio_in = ENET_MDIO; assign ENET_MDC = mdc; assign ENET_MDIO = mdio_oen ? 1'bz : mdio_out; //Assign reset assign ENET_RST_N = core_reset_n; //Assign SDRAM CLK assign clk_n = clk_sdram; //BUF instances in_buf in_buf_inst ( .datain ( ENET_RX_DATA ), .dataout ( ENET_RX_DATA_BUF ) ); //PLL instances my_pll pll_inst( .areset (1'b0), .inclk0 (CLOCK_50), .c0 (sys_clk), .c1 (clk_125), .c2 (clk_25), .c3 (clk_2p5), .locked (core_reset_n) ); pll_clock_PHY1 pll_inst1( .areset (1'b0), .inclk0 (CLOCK_50), .c0 (clk_sdram), .c1 (clk1_125), .c2 (clk1_25), .c3 (clk1_2p5) ); // Transmission Clock in FPGA (TSE IP core) //assign tx_clk1 = 5; assign tx_clk = eth_mode ? clk_125 : ena_10 ? clk_2p5 : clk_25 ; // GbE Mode = 125MHz clock // ena_10? : // 10Mb Mode = 2.5MHz clock // ; // 100Mb Mode = 25 MHz clock // Clock for transmission in PHY chip //assign gtx_clk1 = ; assign ENET_GTX_CLK= eth_mode ? clk1_125 : ena_10 ? clk1_2p5 : clk1_25; // GbE Mode = 125MHz clock // ena_10? : // 10Mb Mode = 2.5MHz clock // ; // 100Mb Mode = 25 MHz clock // Nios II system instance nios_system system_inst ( .clk_clk (sys_clk), // system clock (input) .led_export (S1_LED), // led (output) .new_sdram_controller_0_wire_addr (addr), // new_sdram_controller_0_wire.addr .new_sdram_controller_0_wire_ba (ba), // new_sdram_controller_0_wire.ba .new_sdram_controller_0_wire_cas_n (cas_n), // new_sdram_controller_0_wire.cas_n .new_sdram_controller_0_wire_cke (), // new_sdram_controller_0_wire.cke .new_sdram_controller_0_wire_cs_n (), // new_sdram_controller_0_wire.cs_n .new_sdram_controller_0_wire_dq (dq), // new_sdram_controller_0_wire.dq .new_sdram_controller_0_wire_dqm (dqm), // new_sdram_controller_0_wire.dqm .new_sdram_controller_0_wire_ras_n (ras_n), // new_sdram_controller_0_wire.ras_n .new_sdram_controller_0_wire_we_n (we_n), // new_sdram_controller_0_wire.we_n .reset_reset_n (core_reset_n), // system reset (input) .switch_export (KEY), // swicht button (input) .tse_mac_mdio_connection_mdc (mdc), // mdc (output) .tse_mac_mdio_connection_mdio_in (mdio_in), // mdio_in (input) .tse_mac_mdio_connection_mdio_out (mdio_out), // mdio_out (output) .tse_mac_mdio_connection_mdio_oen (mdio_oen), // mdio_oen (output) .tse_mac_rgmii_connection_rgmii_in (ENET_RX_DATA_BUF), // rgmii_in (rx data, input) .tse_mac_rgmii_connection_rgmii_out (ENET_TX_DATA), // gmii_out (tx data, output) .tse_mac_rgmii_connection_rx_control (ENET_RX_DV), // rx_control (receive data valid, input) .tse_mac_rgmii_connection_tx_control (ENET_TX_EN), // tx_control (tx enable, output) .tse_mac_status_connection_set_10 (), // tse_mac_status_connection.set_10 .tse_mac_status_connection_set_1000 (), // set_1000 .tse_mac_status_connection_eth_mode (eth_mode), // eth_mode (output) .tse_mac_status_connection_ena_10 (ena_10), // ena_10 (output) .tse_pcs_mac_rx_clock_connection_clk (rx_clk), // receive clock (input) .tse_pcs_mac_tx_clock_connection_clk (tx_clk) // transmit clock (input) ); endmodule
Основными частями нашей системы являются:
- nios_system- созданная нами SOPC. Содержит процессор NIOS, контроллер TSE, каналы DMA, контроллер SDRAM, таймер, устройства ввода/вывода.
- in_buf- входной буфер для сигналов приемника RGMII.
- my_pll- синтезатор часты с опорными сигналами для SOPC и режимов 10/100/1000 Мбит/С.
- pll_clock- синтезатор часты с опорными сигналами для SDRAM памяти и сдвинутых по фазе частот для режимов 10/100/1000 Мбит/С.
- assign tx_clk- схема выбора частоты для внутренней логики, в зависимости от режима 10/100/1000 Мбит/С.
- assign ENET_GTX_CLK- схема выбора частоты для внешней микросхемы PHY, в зависимости от режима 10/100/1000 Мбит/С.
Управляющая программа:
C++ Code:
/* * main.c * * Created on: Dec 8, 2016 * Author: Darshan,Avinash,Aravind */ /*** NOTE : please interchange the MAC addresses and PORT numbers on the other board before running the C code in eclipse ***/ #include "system.h" #include #include #include #include //include the sgdma descriptor #include //include the sgdma registers #include //include the PIO registers #include "sys/alt_stdio.h" #include "sys/alt_irq.h" #include #include #include <sys/alt_cache.h> #include #include #include /********* Initialize variables *****************/ //uint8_t n = 0; uint8_t loss_count = 0; uint8_t loss_flag = 0; int pckt_rxed = 0; int succ_rxed = 0; uint8_t flag_syn = 0; uint8_t retr_count = 0; int in=0; uint8_t data_flag; /********** Function Prototypes ******************/ void statistics_counter(); void rx_ethernet_isr (void *context); void create_pkt(); void add_phy_to_profile() { /* supported PHY definition */ /* ------------------------------ */ /* KSZ9031 */ /* ------------------------------ */ enum { KSZ9031_OUI = 0x10A1, KSZ9031_MODEL = 0x22, KSZ9031_REV = 0x02 }; alt_tse_phy_profile KSZ9031 = { "KSZ9031", /* Micrel KSZ9031 */ KSZ9031_OUI, /* OUI */ KSZ9031_MODEL, /* Vender Model Number */ KSZ9031_REV, /* Model Revision Number */ 0x1F, /* Location of Status Register */ 5, /* Location of Speed Status */ 3, /* Location of Duplex Status */ 0 /* Location of Link Status */ /*&KSZ9031_phy_cfg,*/ /* function pointer to configure Micrel KSZ9031 */ /*&KSZ9031_link_status_read*/ /* Function pointer to read from PHY specific status register */ }; /* add supported PHY to profile */ alt_tse_phy_add_profile(&KSZ9031); } /*********** STRUCTS *******************************/ struct tcp_conn { uint8_t link; unsigned char dest_mac[6]; unsigned char source_mac[6]; unsigned short source_port ; unsigned short dest_port; unsigned short ack_num; unsigned short seq_num; }; /*********** Create a receive frame ****************/ unsigned char rx_frame[1518] = { 0 }; unsigned char tx_frame[1518] = { 0 }; /************* Create sgdma transmit and receive devices **************/ alt_sgdma_dev * sgdma_tx_dev; alt_sgdma_dev * sgdma_rx_dev; /************** Allocate descriptors in the descriptor_memory (onchip memory) *************/ alt_sgdma_descriptor tx_descriptor __attribute__ (( section ( ".descriptor_memory" ))); alt_sgdma_descriptor tx_descriptor_end __attribute__ (( section ( ".descriptor_memory" ))); alt_sgdma_descriptor rx_descriptor __attribute__ (( section ( ".descriptor_memory" ))); alt_sgdma_descriptor rx_descriptor_end __attribute__ (( section ( ".descriptor_memory" ))); /************* Tcp connection structures *********************/ struct tcp_conn TCP[2]; /********************* Triple-sp **********************************************/ volatile int *tse = (int *)TSE_BASE; /******* MAIN BLOCK STARTS HERE ********************************/ int main(void){ loss_flag=0; loss_count=0; /**** Initializing timer status and control values *************/ IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x0000); IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x0000); /****** copying TCP header values to structure ****************************/ memmove(&TCP[0].dest_mac,"\x60\xe3\x27\x04\xd5\xe2",6); memmove(&TCP[0].source_mac,"\x60\xe3\x27\x04\xd5\xe3",6); memmove(&TCP[0].source_port, "\x00\x10", 2); memmove(&TCP[0].dest_port, "\x00\x20", 2); memmove(&TCP[0].seq_num, "\x00\x00", 2); memmove(&TCP[0].ack_num, "\x00\x00", 2); data_flag = 0; /*********** Open the sgdma transmit device ********************/ sgdma_tx_dev = alt_avalon_sgdma_open ("/dev/sgdma_tx"); if (sgdma_tx_dev == NULL) { alt_printf ("Error: could not open scatter-gather dma transmit device\n"); //return -1; } else alt_printf ("Opened scatter-gather dma transmit device\n"); /*********** Open the sgdma receive device *************************/ sgdma_rx_dev = alt_avalon_sgdma_open ("/dev/sgdma_rx"); if (sgdma_rx_dev == NULL) { alt_printf ("Error: could not open scatter-gather dma receive device\n"); //return -1; } else alt_printf ("Opened scatter-gather dma receive device\n"); /**************** Set interrupts for the sgdma receive device , Create sgdma receive descriptor & Set up non-blocking transfer of sgdma receive descriptor **********/ alt_avalon_sgdma_register_callback( sgdma_rx_dev, (alt_avalon_sgdma_callback) rx_ethernet_isr, 0x00000014, NULL ); alt_avalon_sgdma_construct_stream_to_mem_desc( &rx_descriptor, &rx_descriptor_end, (alt_u32 *)rx_frame, 0, 0 ); alt_avalon_sgdma_do_async_transfer( sgdma_rx_dev, &rx_descriptor ); add_phy_to_profile(); // Specify the addresses of the PHY devices to be accessed through MDIO interface *(tse + 0x0F) = 0x00; // Read PHY registers by MDIO interface int regPhy[31]; for(unsigned char i=0;i<32;i++) { regPhy[i]=*(tse + 0x80 + i); alt_printf("PHY %x : %x \n",i,regPhy[i]); } int phyid1 = regPhy[2]; int phyid2 = regPhy[3]; printf ("Phy found:id1 %x, id2 %x\n", phyid1, phyid2); /************ Disable read and write transfers and wait**************************/ *(tse + 0x02 ) = *(tse + 0x02) | 0x00800220; while ( *(tse + 0x02 ) != ( *(tse + 0x02 ) | 0x00800220 )) alt_printf("n0"); /****************MAC FIFO Configuration*****************************************/ *(tse + 0x09) = TSE_TRANSMIT_FIFO_DEPTH-16; *(tse + 0x0E) = 3; *(tse + 0x0D) = 8; *(tse + 0x07) =TSE_RECEIVE_FIFO_DEPTH-16; *(tse + 0x0C) = 8; *(tse + 0x0B) = 8; *(tse + 0x0A) = 0; *(tse + 0x08) = 0; /***************** Initialize the MAC address************************************/ *(tse + 0x03 ) = 0x0427E360; //mac_0 *(tse + 0x04) = 0x0000E3D5; //mac_1 /****************** MAC function configuration**********************************/ *(tse + 0x05) = 1518 ; *(tse + 0x17) = 12; *(tse + 0x06 ) = 0xFFFF; *(tse + 0x02 ) = 0x00800220; //command config /*************** Software reset the PHY chip and wait***************************/ *(tse + 0x02 ) = 0x00802220; while ( *(tse + 0x02 ) != ( 0x00800220 ) ) alt_printf("n1"); /*** Enable read and write transfers, gigabit Ethernet operation and promiscuous mode*/ *(tse + 0x02 ) = *(tse + 0x02 ) | 0x0080023B; while ( *(tse + 0x02 ) != ( *(tse + 0x02) | 0x0080023B ) ) alt_printf("n2") ; uint8_t data = 0x00; uint8_t flag_a = 0; int delay = 0; int n; //variable to read timer status //MMD register access example //Write MMD - Device Address 2h, Register 10h = 0001h to enable link-up detection to trigger PME for WOL. //1. Write Register Dh with 0002h // Set up register address for MMD – Device Address 2h. //2. Write Register Eh with 0010h // Select Register 10h of MMD – Device Address 2h. //3. Write Register Dh with 4002h // Select register data for MMD – Device Address 2h, Register 10h. //4. Write Register Eh with 0001h // Write value 0001h to MMD – Device Address 2h, Register 10h. *(tse + 0x80 + 0x0D)=0x0002; *(tse + 0x80 + 0x0E)=0x0008; *(tse + 0x80 + 0x0D)=0x4002; *(tse + 0x80 + 0x0E)=0x01EF; //Read MMD - Device Address 2h, Register 11h – 13h for the magic packet’s MAC address. //1. Write Register Dh with 0002h // Set up register address for MMD – Device Address 2h. //2. Write Register Eh with 0011h // Select Register 11h of MMD – Device Address 2h. //3. Write Register Dh with 8002h // Select register data for MMD – Device Address 2h, Register 11h. //4. Read Register Eh // Read data in MMD – Device Address 2h, Register 11h. //5. Read Register Eh // Read data in MMD – Device Address 2h, Register 12h. //6. Read Register Eh // Read data in MMD – Device Address 2h, Register 13h. *(tse + 0x80 + 0x0D)=0x0002; *(tse + 0x80 + 0x0E)=0x0008; *(tse + 0x80 + 0x0D)=0x8002; int txRxDelay=*(tse + 0x80 + 0x0E); alt_printf("Tx Rx delay %x \n",txRxDelay); /********** Infinite Loop ******************************/ while (1) { in = IORD_ALTERA_AVALON_PIO_DATA(SWITCH_BASE); //read the input from the switch /**** Check if 3 way handshake already established *********************/ if((TCP[0].link == 1) && (flag_syn == 0) && (in & 0x01)==1){ flag_syn = 1; alt_printf("\nConnection already established, send data"); } if ((in & 0x01)== 1){// Syn if switch 1 is on //IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,0x01); //switch on or switch off the LED if(flag_syn == 0){ flag_syn = 1; //setting flag bit to send only 1 syn packet when switch is ON flag_a = 1; /******** Creating and Sending SYN packet******************************/ /** SYN = 1 , SYN-ACK = 5 , ACK = 4 , FIN = 2 , FIN-ACK = 6 **** DATA = 8 , DATA ACK = 0X0C*****************************************/ create_pkt(); memmove(tx_frame+24, "\x01", 1); alt_printf(" timer started for SYN, status is : %x",IORD_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE)); /***** Transmitting the packet ***************************************/ alt_printf("\nSYN TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); /********** Starting Timer for SYN packet *************************************/ IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x0002); IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_0_BASE , 0xFFFF); IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_0_BASE , 0xFFFF); IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x0007); /********** increment sequence number **************************************/ TCP[0].seq_num++; } } /****** Condition for sending FIN Packet when key 1 is OFF **********************************/ else if((flag_a == 1 )&& (in & 0x01) == 0){ data_flag = 0; flag_syn = 0; flag_a=0; /******** Sending Fin packet ***************************************************/; create_pkt(); memcpy(tx_frame+24, "\x02", 1); alt_printf("\nFIN TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); /************ Starting Timer for FIN Packet *******************************/ IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x0002); IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_0_BASE , 0xAAAA); IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_0_BASE , 0xFFFF); IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x0007); TCP[0].seq_num++; } /********* condition to check DATA transmission if key 2 are ON *************/ if((in & 0x02) == 0x00){ delay++; /***** setting delay to display LED blinking *******************************/ if(data_flag == 1 && delay == 1000000){ delay = 0; data_flag = 0; create_pkt(); data++; memcpy(tx_frame+24, "\x08",1); memcpy(tx_frame+25, &data, 1); alt_printf("\n DATA TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25],tx_frame[26]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); /*** Starting Timer for DATA transmission ****************************************/ IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x0002); IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_0_BASE , 0xAAAA); IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_0_BASE , 0x002F); IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x0007); TCP[0].seq_num++; } if (delay > 1000000){ delay=0; } } /******* Condition to check for re transmission *************************************/ /*** Stop Retransmitting and exit if retransmit count reaches 50 (actual ethernet exits after count 16) ********************/ n = IORD_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE); if(n == 3){ retr_count++; if(retr_count>=50){ retr_count = 0; alt_printf("\n retransmission limit exceeded, DISCONNECTED!!!"); break; } /*** Stopping Timer if already running and starting timer for Data transmission ******************************************/ IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x0008); IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x0002); //Transmit Function alt_printf("\n RE TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); /************************ start timer******************************************/ IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_0_BASE , 0xAAAA); IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_0_BASE , 0x02FF); IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x0007); alt_printf("\nRetx timer started for SYN, status:%d count:%d,",IORD_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE)); } } return 0; } /**************************************************************************************** * Subroutine to read incoming Ethernet frames ****************************************************************************************/ void rx_ethernet_isr (void *context) { retr_count = 0; pckt_rxed++; in = IORD_ALTERA_AVALON_PIO_DATA(SWITCH_BASE); //read the input from the switch /***** If key 3 is ON drop receiving packets ***************************************/ if((in & 0x04) == 0x00){ while (alt_avalon_sgdma_check_descriptor_status(&rx_descriptor) != 0); // Create new receive sgdma descriptor alt_avalon_sgdma_construct_stream_to_mem_desc( &rx_descriptor, &rx_descriptor_end, (alt_u32 *)rx_frame, 0, 0 ); // Set up non-blocking transfer of sgdma receive descriptor alt_avalon_sgdma_do_async_transfer( sgdma_rx_dev, &rx_descriptor ); return; } int sucessFrm; int crcErrorFrm; sucessFrm=*(tse+0x1B); crcErrorFrm=*(tse+0x1C); alt_printf("\nRX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", rx_frame[2],rx_frame[3],rx_frame[4],rx_frame[5],rx_frame[6],rx_frame[7],rx_frame[8], rx_frame[9],rx_frame[10],rx_frame[11],rx_frame[12],rx_frame[13],rx_frame[14],rx_frame[15], rx_frame[16],rx_frame[17],rx_frame[18],rx_frame[19],rx_frame[20],rx_frame[21],rx_frame[22], rx_frame[23],rx_frame[24],rx_frame[25],rx_frame[26]); alt_printf("Number of successful frames:%x\n",sucessFrm); alt_printf("The number of receive frames with CRC error:%x\n",crcErrorFrm); alt_dcache_flush_all(); IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x0008); IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x0000); succ_rxed++; // successfully received frame incrementing upon reception /**** check if SYN frame is received *********************************************/ if ( rx_frame [24] == 0x01) { TCP[0].link = 1; /******* Sending SYN-ACK Frame ***************************************/ TCP[0].ack_num++; create_pkt(); memmove(tx_frame+24,"\x05",1);//Setting syn-ack //transmit_packet(); alt_printf("\n SYN/ACK TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); TCP[0].seq_num++; } /******************** Syn-Ack recieved *************************************************/ else if((rx_frame[24]) == 0x05){ TCP[0].link = 1; /**************** Send ACknowledgement ************************************************/ TCP[0].ack_num++; create_pkt(); memmove(tx_frame+24,"\x04",1);//setting ack //transmit_packet(); alt_printf("\n Conn Est Ack TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); data_flag = 1; TCP[0].seq_num++; } /***************** FIN Recieved *************************************************/ else if((rx_frame[24]) == 0x02){ TCP[0].link = 0; data_flag = 0; /***************** Sending FIN-ACK **********************************************/ TCP[0].ack_num++; create_pkt(); memmove(tx_frame+24,"\x06",1); //transmit_packet(); alt_printf("\n FIN/ACK TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); TCP[0].seq_num++; } /***************** Fin-Ack received **************************************************************/ else if(rx_frame[24] == 0x06){ TCP[0].link = 0; //ack_send(); TCP[0].ack_num++; create_pkt(); memmove(tx_frame+24,"\x04",1);//setting ack //transmit_packet(); alt_printf("\n Conn Closed ACK TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); printf("\n Connection closed"); printf("\n********************* Statistics - TCP **********************"); printf("\nRxed Packets : %x",pckt_rxed); printf("\nSuccessfull Packets Rxed : %x",succ_rxed); printf("\nDropped Packets : %x",(pckt_rxed - succ_rxed)); statistics_counter(); TCP[0].seq_num++; } /***************** ACK Received *******************************************************/ else if(rx_frame[24] == 0x04){ //ack(); if(TCP[0].link == 1){ alt_printf("\n Connection establishment ack received"); data_flag = 1; TCP[0].ack_num++; } else { /***************** PRINT TCP STATISTICS ***********************************************/ alt_printf("\n Connection closed"); alt_printf("\n********************* Statistics - TCP **********************"); alt_printf("\nRxed Packets : %x",pckt_rxed); alt_printf("\nSuccessfull Packets Rxed : %x",succ_rxed); alt_printf("\nDropped Packets : %x",(pckt_rxed - succ_rxed)); /********** Calling function for printing Ethernet statistics ***************************/ statistics_counter(); TCP[0].ack_num++; } } /******************Data pkt received and sent to LED's**********/ else if(rx_frame[24] == 0x08){ TCP[0].ack_num++; IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,rx_frame[25]); create_pkt(); memmove(tx_frame+24,"\x0C",1); alt_printf("\n DATA ACK TX_FRAME: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", tx_frame[2],tx_frame[3],tx_frame[4],tx_frame[5],tx_frame[6],tx_frame[7],tx_frame[8], tx_frame[9],tx_frame[10],tx_frame[11],tx_frame[12],tx_frame[13],tx_frame[14],tx_frame[15], tx_frame[16],tx_frame[17],tx_frame[18],tx_frame[19],tx_frame[20],tx_frame[21],tx_frame[22], tx_frame[23],tx_frame[24],tx_frame[25],tx_frame[26]); alt_dcache_flush_all(); alt_avalon_sgdma_construct_mem_to_stream_desc(&tx_descriptor, &tx_descriptor_end, (alt_u32 *)tx_frame, 64, 0, 1, 1, 0); alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor ); while (alt_avalon_sgdma_check_descriptor_status(&tx_descriptor) != 0); TCP[0].seq_num++; } /********************* DATA ACKNOWLEDGEMENT RECEIVED***********************************/ else if(rx_frame[24] == 0x0C){ TCP[0].ack_num++; alt_printf("\n Data ACK received"); data_flag = 1; } // Wait until receive descriptor transfer is complete while (alt_avalon_sgdma_check_descriptor_status(&rx_descriptor) != 0); // Create new receive sgdma descriptor alt_avalon_sgdma_construct_stream_to_mem_desc( &rx_descriptor, &rx_descriptor_end, (alt_u32 *)rx_frame, 0, 0 ); // Set up non-blocking transfer of sgdma receive descriptor alt_avalon_sgdma_do_async_transfer( sgdma_rx_dev, &rx_descriptor ); } /********* Function for Creating Packet before transmission ***********************/ void create_pkt(){ memset(tx_frame+26,0,37); memcpy(tx_frame+20, &TCP[0].seq_num, 2); memcpy(tx_frame+22, &TCP[0].ack_num, 2); memcpy(tx_frame+24, "\x00", 1); memmove(tx_frame, "\x00\x00",2); memmove(tx_frame+2, &TCP[0].dest_mac,6); memmove(tx_frame+8, &TCP[0].source_mac,6); memmove(tx_frame+14, "\x2E\x00", 2); memmove(tx_frame+16, &TCP[0].source_port, 2); memmove(tx_frame+18, &TCP[0].dest_port, 2); } /******* Printing Ethernet Statistics *********************************************/ void statistics_counter(){ volatile int *tse = (int *)TSE_BASE; alt_printf("\n********************* Statistics - Ethernet **********************"); alt_printf("\nnum frames successfully received: %x ", *(tse + 0x1B)); alt_printf("\nnum error frames received: %x ", *(tse + 0x22)); alt_printf("\nnum frames correctly received: %x ", *(tse + 0x1B) - *(tse + 0x22)); alt_printf("\n******************************************************************"); }
В программе происходит создание дескрипторов для передачи пакетов, инициализация MAC уровня, чтение и запись регистров с помощью интерфейса MDIO, настройка таймера и прерываний ну и собствено реализация отправки и приема пакетов.
Ну и по традиции видео работы, и исходники:
Проект: 1gb_nios_ii_tcp