diff --git a/lib_ethernet/api/ethernet.h b/lib_ethernet/api/ethernet.h index 44a5e418..529e08be 100644 --- a/lib_ethernet/api/ethernet.h +++ b/lib_ethernet/api/ethernet.h @@ -239,6 +239,12 @@ typedef interface ethernet_cfg_if { */ void disable_link_status_notification(size_t client_num); + /** When forwarding received packets, put them in the high priority queue, + * which the tx pins prioritises when reading packets over the low priority queue + * + */ + void forward_packets_as_hp(unsigned forward_as_hp_flag); + /** Exit ethernet MAC. Quits all of the associated sub tasks and frees memory. * Allows the resources previously used by the MAC to be re-used by other tasks. * Only supported on RMII real-time MACs. This command is ignored for @@ -270,10 +276,10 @@ typedef interface ethernet_tx_if { /** Internal API call. Do not use. */ void _init_send_packet(size_t n, size_t ifnum); /** Internal API call. Do not use. */ - void _complete_send_packet(char packet[n], unsigned n, + unsigned _complete_send_packet(char packet[n], unsigned n, int request_timestamp, size_t ifnum); /** Internal API call. Do not use. */ - unsigned _get_outgoing_timestamp(); + unsigned _get_outgoing_timestamp(size_t ifnum); #ifdef __XC__ } ethernet_tx_if; @@ -293,7 +299,10 @@ extends client interface ethernet_tx_if : { inline void send_packet(CLIENT_INTERFACE(ethernet_tx_if, i), char packet[n], unsigned n, unsigned ifnum) { i._init_send_packet(n, ifnum); - i._complete_send_packet(packet, n, 0, ifnum); + unsigned ready; + do { + ready = i._complete_send_packet(packet, n, 1, ifnum); + }while(!ready); } /** Function to send an Ethernet packet on the specified interface and return a timestamp @@ -314,8 +323,16 @@ extends client interface ethernet_tx_if : { unsigned n, unsigned ifnum) { i._init_send_packet(n, ifnum); - i._complete_send_packet(packet, n, 1, ifnum); - return i._get_outgoing_timestamp(); + unsigned ready; + do { + ready = i._complete_send_packet(packet, n, 1, ifnum); + }while(!ready); + unsigned timestamp = 0; + while(!timestamp) + { + timestamp = i._get_outgoing_timestamp(ifnum); + } + return timestamp; } /**@}*/ // END: addtogroup ethernet_tx_if #ifdef __XC__ @@ -413,7 +430,17 @@ inline void ethernet_send_hp_packet(streaming_chanend_t c_tx_hp, unsigned n, unsigned ifnum) { + unsigned ready = 0; + c_tx_hp <: n; + c_tx_hp <: ifnum; + c_tx_hp :> ready; + while(!ready) + { + c_tx_hp <: n; + c_tx_hp <: ifnum; + c_tx_hp :> ready; + } sout_char_array(c_tx_hp, packet, n); } @@ -610,7 +637,7 @@ void mii_ethernet_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), static_co -/** ENUM to determine which two bits of a four bit port are to be used as data lines +/** ENUM to determine which two bits of a four bit port are to be used as data lines * in the case that a four bit port is specified for RMII. The other two pins of the four bit * port cannot be used. For Rx the input values are ignored. For Tx, the unused pins are always driven low. */ typedef enum rmii_data_4b_pin_assignment_t{ @@ -693,6 +720,30 @@ void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), stati static_const_unsigned_t tx_bufsize_words, enum ethernet_enable_shaper_t shaper_enabled); + +/** 100 Mbps RT RMII dual mac component. + * It creates two MAC instances, with each MAC connected to a separate, dedicated RMII PHY interface. + * + * Note: This is still WIP and requires additional testing. + */ +void rmii_ethernet_rt_mac_dual(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), static_const_unsigned_t n_cfg, + SERVER_INTERFACE(ethernet_rx_if, i_rx_lp[n_rx_lp]), static_const_unsigned_t n_rx_lp, + SERVER_INTERFACE(ethernet_tx_if, i_tx_lp[n_tx_lp]), static_const_unsigned_t n_tx_lp, + nullable_streaming_chanend_t c_rx_hp, + nullable_streaming_chanend_t c_tx_hp, + in_port_t p_clk, + rmii_data_port_t * unsafe p_rxd_0, in_port_t p_rxdv_0, + out_port_t p_txen_0, rmii_data_port_t * unsafe p_txd_0, + clock rxclk_0, + clock txclk_0, + rmii_data_port_t * unsafe p_rxd_1, in_port_t p_rxdv_1, + out_port_t p_txen_1, rmii_data_port_t * unsafe p_txd_1, + clock rxclk_1, + clock txclk_1, + static_const_unsigned_t rx_bufsize_words, + static_const_unsigned_t tx_bufsize_words, + enum ethernet_enable_shaper_t enable_shaper); + #endif // __XC__ || __DOXYGEN__ #endif // __ethernet__h__ diff --git a/lib_ethernet/src/client_state.h b/lib_ethernet/src/client_state.h index 07bdd5d5..b51bb235 100644 --- a/lib_ethernet/src/client_state.h +++ b/lib_ethernet/src/client_state.h @@ -24,10 +24,10 @@ enum status_update_state_t { typedef struct { unsigned dropped_pkt_cnt; - unsigned rd_index; - unsigned wr_index; - void *fifo[ETHERNET_RX_CLIENT_QUEUE_SIZE]; - int status_update_state; + unsigned rd_index[MAX_ETHERNET_PORTS]; + unsigned wr_index[MAX_ETHERNET_PORTS]; + void *fifo[MAX_ETHERNET_PORTS][ETHERNET_RX_CLIENT_QUEUE_SIZE]; + int status_update_state[MAX_ETHERNET_PORTS]; size_t num_etype_filters; int strip_vlan_tags; uint16_t etype_filters[ETHERNET_MAX_ETHERTYPE_FILTERS]; @@ -37,9 +37,10 @@ typedef struct typedef struct { int requested_send_buffer_size; - mii_packet_t *send_buffer; - int has_outgoing_timestamp_info; - unsigned outgoing_timestamp; + mii_packet_t *send_buffer[MAX_ETHERNET_PORTS]; + int has_outgoing_timestamp_info[MAX_ETHERNET_PORTS]; + unsigned outgoing_timestamp[MAX_ETHERNET_PORTS]; + int dst_port; } tx_client_state_t; #ifdef __XC__ diff --git a/lib_ethernet/src/client_state.xc b/lib_ethernet/src/client_state.xc index abfef6a4..cf6f7baa 100644 --- a/lib_ethernet/src/client_state.xc +++ b/lib_ethernet/src/client_state.xc @@ -6,9 +6,12 @@ void init_rx_client_state(rx_client_state_t client_state[n], unsigned n) { for (unsigned i = 0; i < n; i ++) { client_state[i].dropped_pkt_cnt = 0; - client_state[i].rd_index = 0; - client_state[i].wr_index = 0; - client_state[i].status_update_state = STATUS_UPDATE_WAITING; + for(int p=0; p> 31) ? 1 : 0; } +int ethernet_filter_result_is_forwarding_set(unsigned value) +{ + return ((value >> 30) & 0x1) ? 1 : 0; +} + unsigned ethernet_filter_result_interfaces(unsigned value) { - // Throw away bit 31 - return (value << 1) >> 1; + // Throw away bit 30 and 31 + return (value << 2) >> 2; } unsigned ethernet_filter_result_set_hp(unsigned value, int is_hp) @@ -23,6 +28,13 @@ unsigned ethernet_filter_result_set_hp(unsigned value, int is_hp) return value | (is_hp << 31); } +unsigned ethernet_filter_result_set_forwarding(unsigned value, int is_forwarding_set) +{ + // Ensure it is a single bit in the LSB + is_forwarding_set = is_forwarding_set ? 1 : 0; + return value | (is_forwarding_set << 30); +} + void ethernet_init_filter_table(eth_global_filter_info_t table) { for (size_t i = 0; i < ETHERNET_MACADDR_FILTER_TABLE_SIZE; i++) { diff --git a/lib_ethernet/src/mii_buffering.c b/lib_ethernet/src/mii_buffering.c index df9440b0..2730012d 100644 --- a/lib_ethernet/src/mii_buffering.c +++ b/lib_ethernet/src/mii_buffering.c @@ -173,10 +173,6 @@ void mii_commit(mii_mempool_t mempool, unsigned *end_ptr) { mempool_info_t *info = (mempool_info_t *) mempool; -#if 0 && (NUM_ETHERNET_PORTS > 1) && !defined(DISABLE_ETHERNET_PORT_FORWARDING) - buf->forwarding = 0; -#endif - if (end_ptr > info->last_safe_wrptr) end_ptr = info->start; @@ -188,6 +184,8 @@ void mii_add_packet(mii_packet_queue_t queue, mii_packet_t *buf) packet_queue_info_t *info = (packet_queue_info_t *)queue; unsigned wr_index = info->wr_index; + buf->forwarding = 0; + info->ptrs[wr_index] = (unsigned *)buf; info->wr_index = increment_and_wrap_power_of_2(wr_index, ETHERNET_NUM_PACKET_POINTERS); } diff --git a/lib_ethernet/src/mii_buffering.h b/lib_ethernet/src/mii_buffering.h index e6809273..5895bfb3 100644 --- a/lib_ethernet/src/mii_buffering.h +++ b/lib_ethernet/src/mii_buffering.h @@ -61,7 +61,7 @@ typedef struct mii_packet_t { * The end of the buffer is used to contain a pointer to the start such that when the * end is reached it is a simple load operation from that address to get the start * address. - */ + */ typedef struct mempool_info_t { unsigned *wrptr; unsigned *start; @@ -92,6 +92,7 @@ typedef unsigned * mii_rdptr_t; typedef unsigned * mii_packet_queue_t; void mii_init_packet_queue(mii_packet_queue_t queue); + mii_mempool_t mii_init_mempool(unsigned *buffer, int size); void mii_init_lock(); void mii_deinit_lock(); diff --git a/lib_ethernet/src/mii_ethernet_mac.xc b/lib_ethernet/src/mii_ethernet_mac.xc index 837afe05..a1dc8bb7 100644 --- a/lib_ethernet/src/mii_ethernet_mac.xc +++ b/lib_ethernet/src/mii_ethernet_mac.xc @@ -235,7 +235,7 @@ static void mii_ethernet_aux(client mii_if i_mii, // Do nothing break; - case i_tx[int i]._get_outgoing_timestamp() -> unsigned timestamp: + case i_tx[int i]._get_outgoing_timestamp(unsigned dst_port) -> unsigned timestamp: fail("Outgoing timestamps are not supported in standard MII Ethernet MAC"); break; @@ -257,6 +257,10 @@ static void mii_ethernet_aux(client mii_if i_mii, client_state.status_update_state = STATUS_UPDATE_IGNORING; break; + case i_cfg[int i].forward_packets_as_hp(unsigned forward_packets_in_hp_queue): + // Do nothing - not supported on this Mac + break; + case i_cfg[int i].exit(void): { // Do nothing - exit not supported on this MAC break; @@ -264,7 +268,8 @@ static void mii_ethernet_aux(client mii_if i_mii, case i_tx[int i]._complete_send_packet(char data[n], unsigned n, int request_timestamp, - unsigned dst_port): + unsigned dst_port) -> unsigned ready: + ready = 1; memcpy(txbuf, data, n); i_mii.send_packet(txbuf, n); // wait for the packet to be sent diff --git a/lib_ethernet/src/mii_ethernet_rt_mac.xc b/lib_ethernet/src/mii_ethernet_rt_mac.xc index 6b81be4f..6c139e5f 100644 --- a/lib_ethernet/src/mii_ethernet_rt_mac.xc +++ b/lib_ethernet/src/mii_ethernet_rt_mac.xc @@ -29,29 +29,33 @@ static inline unsigned int get_tile_id_from_chanend(chanend c) { #define MII_RX_THRESHOLD_BYTES 2000 #endif -unsafe static void reserve(tx_client_state_t client_state[n], unsigned n, mii_mempool_t mem, unsigned * unsafe rdptr) +unsafe static void reserve(tx_client_state_t client_state[n], unsigned n, mii_mempool_t mem, unsigned * unsafe rdptr, int tx_port) { for (unsigned i = 0; i < n; i++) { if (client_state[i].requested_send_buffer_size != 0 && - client_state[i].send_buffer == null) { + client_state[i].send_buffer[tx_port] == null + ) + { debug_printf("Trying to reserve send buffer (client %d, size %d)\n", i, client_state[i].requested_send_buffer_size); - client_state[i].send_buffer = + // reserve memory irrespective of whether the packet is destined for this tx_port. We'll not commit the packet if it isn't + client_state[i].send_buffer[tx_port] = mii_reserve_at_least(mem, rdptr, client_state[i].requested_send_buffer_size + sizeof(mii_packet_t)); } } } -unsafe static void handle_incoming_packet(mii_packet_queue_t packets, +unsafe static unsigned handle_incoming_packet(mii_packet_queue_t packets, unsigned &rd_index, rx_client_state_t client_states[n], server ethernet_rx_if i_rx[n], - unsigned n) + unsigned n, + unsigned current_port) { mii_packet_t * unsafe buf = mii_get_my_next_buf(packets, rd_index); if (!buf) - return; + return 0; int tcount = 0; if (buf->filter_result) { @@ -83,24 +87,29 @@ unsafe static void handle_incoming_packet(mii_packet_queue_t packets, if (client_wants_packet) { debug_printf("Trying to queue for client %d\n", i); - int wr_index = client_state.wr_index; + int wr_index = client_state.wr_index[current_port]; int new_wr_index = increment_and_wrap_to_zero(wr_index, ETHERNET_RX_CLIENT_QUEUE_SIZE); - if (new_wr_index != client_state.rd_index) { + if (new_wr_index != client_state.rd_index[current_port]) { debug_printf("Putting in client queue %d\n", i); // Store the index into the packet queue - client_state.fifo[wr_index] = (void *)rd_index; + client_state.fifo[current_port][wr_index] = (void *)rd_index; tcount++; i_rx[i].packet_ready(); - client_state.wr_index = new_wr_index; + client_state.wr_index[current_port] = new_wr_index; } else { client_state.dropped_pkt_cnt += 1; } } } } + if(ethernet_filter_result_is_forwarding_set(buf->filter_result)) + { + tcount++; // TODO this assumes that there is only one client we want to forward this to, which is a valid assumption for a 2 port system but doesn't scale + buf->forwarding = 0xffffffff; + } if (tcount == 0) { mii_free_index(packets, rd_index); @@ -110,18 +119,20 @@ unsafe static void handle_incoming_packet(mii_packet_queue_t packets, } // Only move the rd_index after any clients register using it rd_index = mii_move_my_rd_index(packets, rd_index); + return 1; } unsafe static void drop_lp_packets(mii_packet_queue_t packets, rx_client_state_t client_states[n], - unsigned n) + unsigned n, + unsigned current_port) { for (unsigned i = 0; i < n; i++) { rx_client_state_t &client_state = client_states[i]; - - if (client_state.rd_index != client_state.wr_index) { - unsigned client_rd_index = client_state.rd_index; - unsigned packets_rd_index = (unsigned)client_state.fifo[client_rd_index]; + + if (client_state.rd_index[current_port] != client_state.wr_index[current_port]) { + unsigned client_rd_index = client_state.rd_index[current_port]; + unsigned packets_rd_index = (unsigned)client_state.fifo[current_port][client_rd_index]; packet_queue_info_t * unsafe p_packets = (packet_queue_info_t * unsafe)packets; mii_packet_t * unsafe buf = (mii_packet_t * unsafe)p_packets->ptrs[packets_rd_index]; @@ -129,7 +140,7 @@ unsafe static void drop_lp_packets(mii_packet_queue_t packets, if (mii_get_and_dec_transmit_count(buf) == 0) { mii_free_index(packets, packets_rd_index); } - client_state.rd_index = increment_and_wrap_to_zero(client_state.rd_index, + client_state.rd_index[current_port] = increment_and_wrap_to_zero(client_state.rd_index[current_port], ETHERNET_RX_CLIENT_QUEUE_SIZE); client_state.dropped_pkt_cnt += 1; } @@ -140,7 +151,8 @@ unsafe static void handle_incoming_hp_packets(mii_mempool_t rxmem, mii_packet_queue_t packets, unsigned &rd_index, streaming chanend c_rx_hp, - volatile ethernet_port_state_t * unsafe p_port_state) + volatile ethernet_port_state_t * unsafe p_port_state, + unsigned current_port) { while (1) { mii_packet_t * unsafe buf = mii_get_my_next_buf(packets, rd_index); @@ -149,7 +161,7 @@ unsafe static void handle_incoming_hp_packets(mii_mempool_t rxmem, int client_wants_packet = 0; if (buf->filter_result && ethernet_filter_result_is_hp(buf->filter_result)) { - client_wants_packet = (buf->filter_result & 1); + client_wants_packet = (buf->filter_result & 1); // there's only one hp client } if (client_wants_packet) @@ -174,18 +186,27 @@ unsafe static void handle_incoming_hp_packets(mii_mempool_t rxmem, sout_char_array(c_rx_hp, (char *)*wrap_ptr, len2); } } - - rd_index = mii_free_index(packets, rd_index); + if(ethernet_filter_result_is_forwarding_set(buf->filter_result)) + { + buf->forwarding = 0xffffffff; + buf->tcount = 0; + } + else + { + mii_free_index(packets, rd_index); + } + rd_index = mii_move_my_rd_index(packets, rd_index); } } static inline void update_client_state(rx_client_state_t client_state[n], server ethernet_rx_if i_rx[n], - unsigned n) + unsigned n, + unsigned ifnum) { for (unsigned i = 0; i < n; i += 1) { - if (client_state[i].status_update_state == STATUS_UPDATE_WAITING) { - client_state[i].status_update_state = STATUS_UPDATE_PENDING; + if (client_state[i].status_update_state[ifnum] == STATUS_UPDATE_WAITING) { + client_state[i].status_update_state[ifnum] = STATUS_UPDATE_PENDING; i_rx[i].packet_ready(); } } @@ -193,37 +214,41 @@ static inline void update_client_state(rx_client_state_t client_state[n], unsafe static inline void handle_ts_queue(mii_ts_queue_t ts_queue, tx_client_state_t client_state[n], - unsigned n) + unsigned n, + unsigned current_port) { unsigned index = 0; unsigned timestamp = 0; int found = mii_ts_queue_get_entry(ts_queue, &index, ×tamp); if (found) { size_t client_id = index - 1; - client_state[client_id].has_outgoing_timestamp_info = 1; - client_state[client_id].outgoing_timestamp = timestamp; + client_state[client_id].has_outgoing_timestamp_info[current_port] = 1; + client_state[client_id].outgoing_timestamp[current_port] = timestamp; } } -unsafe void mii_ethernet_server(mii_mempool_t rx_mem, - mii_packet_queue_t rx_packets_lp, - mii_packet_queue_t rx_packets_hp, - unsigned * unsafe rx_rdptr, - mii_mempool_t tx_mem_lp, - mii_mempool_t tx_mem_hp, - mii_packet_queue_t tx_packets_lp, - mii_packet_queue_t tx_packets_hp, - mii_ts_queue_t ts_queue_lp, - server ethernet_cfg_if i_cfg[n_cfg], static const unsigned n_cfg, - server ethernet_rx_if i_rx_lp[n_rx_lp], static const unsigned n_rx_lp, - server ethernet_tx_if i_tx_lp[n_tx_lp], static const unsigned n_tx_lp, - streaming chanend ? c_rx_hp, - streaming chanend ? c_tx_hp, - chanend c_macaddr_filter, - volatile ethernet_port_state_t * unsafe p_port_state, - volatile int * unsafe running_flag_ptr, - chanend c_rx_pins_exit, - phy_100mb_t phy_type) + +unsafe void mii_ethernet_server(mii_mempool_t * unsafe rx_mem, + packet_queue_info_t * unsafe rx_packets_lp, + packet_queue_info_t * unsafe rx_packets_hp, + mii_rdptr_t * unsafe rx_rdptr, + mii_mempool_t * unsafe tx_mem_lp, + mii_mempool_t * unsafe tx_mem_hp, + packet_queue_info_t * unsafe tx_packets_lp, + packet_queue_info_t * unsafe tx_packets_hp, + mii_ts_queue_t ts_queue_lp, + server ethernet_cfg_if i_cfg[n_cfg], static const unsigned n_cfg, + server ethernet_rx_if i_rx_lp[n_rx_lp], static const unsigned n_rx_lp, + server ethernet_tx_if i_tx_lp[n_tx_lp], static const unsigned n_tx_lp, + streaming chanend ? c_rx_hp, + streaming chanend ? c_tx_hp, + chanend c_macaddr_filter, + volatile ethernet_port_state_t * unsafe p_port_state, + volatile int * unsafe running_flag_ptr, + chanend c_rx_pins_exit[], + phy_100mb_t phy_type, + static const unsigned num_mac_ports + ) { uint8_t mac_address[MACADDR_NUM_BYTES] = {0}; rx_client_state_t rx_client_state_lp[n_rx_lp]; @@ -231,8 +256,15 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, tx_client_state_t tx_client_state_lp[n_tx_lp]; tx_client_state_t tx_client_state_hp[1]; - unsigned rd_index_hp = mii_init_my_rd_index(rx_packets_hp); - unsigned rd_index_lp = mii_init_my_rd_index(rx_packets_lp); + + unsigned rd_index_hp[num_mac_ports], rd_index_lp[num_mac_ports]; + // Server's read index in the rx_packets_lp and rx_packets_hp queues + for(int i=0; ilink_state; - data[1] = p_port_state->link_speed; - desc.type = ETH_IF_STATUS; - desc.src_ifnum = 0; - desc.timestamp = 0; - desc.len = 2; - desc.filter_data = 0; - client_state.status_update_state = STATUS_UPDATE_WAITING; - } - else if (client_state.rd_index != client_state.wr_index) { - unsigned client_rd_index = client_state.rd_index; - unsigned packets_rd_index = (unsigned)client_state.fifo[client_rd_index]; - - packet_queue_info_t * unsafe p_packets_lp = (packet_queue_info_t * unsafe)rx_packets_lp; + packet_queue_info_t * unsafe p_packets_lp = (packet_queue_info_t * unsafe)&rx_packets_lp[current_port_lp]; mii_packet_t * unsafe buf = (mii_packet_t * unsafe)p_packets_lp->ptrs[packets_rd_index]; ethernet_packet_info_t info; @@ -283,7 +326,7 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, info.filter_data = buf->filter_data; int len = (n > buf->length ? buf->length : n); - unsigned * unsafe wrap_ptr = mii_get_wrap_ptr(rx_mem); + unsigned * unsafe wrap_ptr = mii_get_wrap_ptr(rx_mem[current_port_lp]); unsigned * unsafe dptr = buf->data; int prewrap = ((char *) wrap_ptr - (char *) dptr); int len1 = prewrap > len ? len : prewrap; @@ -303,12 +346,12 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, memcpy(&desc, &info, sizeof(info)); if (mii_get_and_dec_transmit_count(buf) == 0) { - mii_free_index(rx_packets_lp, packets_rd_index); + mii_free_index((mii_packet_queue_t)&rx_packets_lp[current_port_lp], packets_rd_index); } - client_state.rd_index = increment_and_wrap_to_zero(client_state.rd_index, + client_state.rd_index[current_port_lp] = increment_and_wrap_to_zero(client_state.rd_index[current_port_lp], ETHERNET_RX_CLIENT_QUEUE_SIZE); - if (client_state.rd_index != client_state.wr_index) { + if (client_state.rd_index[current_port_lp] != client_state.wr_index[current_port_lp]) { i_rx_lp[i].packet_ready(); } } @@ -327,13 +370,18 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, break; case i_cfg[int i].set_link_state(int ifnum, ethernet_link_state_t status, ethernet_speed_t speed): - if (p_port_state->link_state != status) { - p_port_state->link_state = status; - p_port_state->link_speed = speed; - update_client_state(rx_client_state_lp, i_rx_lp, n_rx_lp); + if (p_port_state[ifnum].link_state != status) { + p_port_state[ifnum].link_state = status; + p_port_state[ifnum].link_speed = speed; + update_client_state(rx_client_state_lp, i_rx_lp, n_rx_lp, ifnum); } break; + case i_cfg[int i].forward_packets_as_hp(unsigned forward_packets_in_hp_queue): + c_macaddr_filter <: 1; + c_macaddr_filter <: forward_packets_in_hp_queue; + break; + case i_cfg[int i].add_macaddr_filter(size_t client_num, int is_hp, ethernet_macaddr_filter_t entry) -> ethernet_macaddr_filter_result_t result: @@ -400,7 +448,7 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, } case i_cfg[int i].set_egress_qav_idle_slope(size_t ifnum, unsigned slope): { - p_port_state->qav_idle_slope = slope; + p_port_state[ifnum].qav_idle_slope = slope; break; } @@ -408,7 +456,7 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, if (speed < 0 || speed >= NUM_ETHERNET_SPEEDS) { fail("Invalid Ethernet speed, must be a valid ethernet_speed_t enum value"); } - p_port_state->ingress_ts_latency[speed] = value / 10; + p_port_state[ifnum].ingress_ts_latency[speed] = value / 10; break; } @@ -416,7 +464,7 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, if (speed < 0 || speed >= NUM_ETHERNET_SPEEDS) { fail("Invalid Ethernet speed, must be a valid ethernet_speed_t enum value"); } - p_port_state->egress_ts_latency[speed] = value / 10; + p_port_state[ifnum].egress_ts_latency[speed] = value / 10; break; } @@ -432,23 +480,35 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, case i_cfg[int i].enable_link_status_notification(size_t client_num): rx_client_state_t &client_state = rx_client_state_lp[client_num]; - client_state.status_update_state = STATUS_UPDATE_WAITING; + for(int i=0; i - i_tx_lp[i]._get_outgoing_timestamp() -> unsigned timestamp: - timestamp = tx_client_state_lp[i].outgoing_timestamp + p_port_state->egress_ts_latency[p_port_state->link_speed]; - tx_client_state_lp[i].has_outgoing_timestamp_info = 0; + i_tx_lp[i]._get_outgoing_timestamp(unsigned dst_port) -> unsigned timestamp: + if(dst_port == ETHERNET_ALL_INTERFACES) + { + dst_port = 0; // TODO - FIXME + } + if(tx_client_state_lp[i].has_outgoing_timestamp_info[dst_port]) + { + timestamp = tx_client_state_lp[i].outgoing_timestamp[dst_port] + p_port_state[dst_port].egress_ts_latency[p_port_state[dst_port].link_speed]; + tx_client_state_lp[i].has_outgoing_timestamp_info[dst_port] = 0; + } + else + { + timestamp = 0; + } break; - case (!isnull(c_tx_hp) && tx_client_state_hp[0].send_buffer && !prioritize_rx) => c_tx_hp :> unsigned len: - mii_packet_t * unsafe buf = tx_client_state_hp[0].send_buffer; - unsigned * unsafe dptr = &buf->data[0]; - unsigned * unsafe wrap_ptr = mii_get_wrap_ptr(tx_mem_hp); - unsigned prewrap = ((char *) wrap_ptr - (char *) dptr); - unsigned len1 = prewrap > len ? len : prewrap; - unsigned len2 = prewrap > len ? 0 : len - prewrap; - unsigned * unsafe start_ptr = (unsigned *) *wrap_ptr; - // sout_char_array sends bytes in reverse order so the second - // half must be received first - if (len2) { - sin_char_array(c_tx_hp, (char*)start_ptr, len2); + case (!isnull(c_tx_hp) && !prioritize_rx) => c_tx_hp :> unsigned len: + unsigned dst_port; + c_tx_hp :> dst_port; + if(dst_port == ETHERNET_ALL_INTERFACES) + { + dst_port = 0; // TODO FIXME Sending on multiple ports with one send_packet() call when num_mac_ports > 1 is not supported yet. } - sin_char_array(c_tx_hp, (char*)dptr, len1); - if (len2) { - dptr = start_ptr + (len2+3)/4; + + mii_packet_t * unsafe buf = tx_client_state_hp[0].send_buffer[dst_port]; + if(!buf) // check if there's a send_buffer available for this port + { + c_tx_hp <: 0; // not ready } - else { - dptr = dptr + (len+3)/4; + else + { + c_tx_hp <: 1; //ready. Expect data next + + unsigned * unsafe dptr = &buf->data[0]; + unsigned * unsafe wrap_ptr = mii_get_wrap_ptr(tx_mem_hp[dst_port]); + unsigned prewrap = ((char *) wrap_ptr - (char *) dptr); + unsigned len1 = prewrap > len ? len : prewrap; + unsigned len2 = prewrap > len ? 0 : len - prewrap; + unsigned * unsafe start_ptr = (unsigned *) *wrap_ptr; + + // sout_char_array sends bytes in reverse order so the second + // half must be received first + if (len2) { + sin_char_array(c_tx_hp, (char*)start_ptr, len2); + } + sin_char_array(c_tx_hp, (char*)dptr, len1); + if (len2) { + dptr = start_ptr + (len2+3)/4; + } + else { + dptr = dptr + (len+3)/4; + } + buf->length = len; + buf->tcount = 0; + mii_commit(tx_mem_hp[dst_port], dptr); + mii_add_packet((mii_packet_queue_t)&tx_packets_hp[dst_port], buf); + tx_client_state_hp[0].send_buffer[dst_port] = null; + prioritize_rx = 3; } - buf->length = len; - mii_commit(tx_mem_hp, dptr); - mii_add_packet(tx_packets_hp, buf); - buf->tcount = 0; - tx_client_state_hp[0].send_buffer = null; - prioritize_rx = 3; + break; [[independent_guard]] case (unsigned i = 0; i < n_tx_lp; i++) - (tx_client_state_lp[i].send_buffer != null && !prioritize_rx) => - i_tx_lp[i]._complete_send_packet(char data[n], unsigned n, + (!prioritize_rx) => + i_tx_lp[i]._complete_send_packet(char data[n], unsigned n, int request_timestamp, - unsigned dst_port): - mii_packet_t * unsafe buf = tx_client_state_lp[i].send_buffer; - unsigned * unsafe dptr = &buf->data[0]; - unsigned * unsafe wrap_ptr = mii_get_wrap_ptr(tx_mem_lp); - int prewrap = ((char *) wrap_ptr - (char *) dptr); - int len = n; - int len1 = prewrap > len ? len : prewrap; - int len2 = prewrap > len ? 0 : len - prewrap; - memcpy(dptr, data, len1); - if (len2) { - unsigned * unsafe start_ptr = (unsigned *) *wrap_ptr; - memcpy((unsigned *) start_ptr, &data[len1], len2); - dptr = start_ptr + (len2+3)/4; + unsigned dst_port) -> unsigned ready: + ready = 1; + for(int p=0; pdata[0]; + unsigned * unsafe wrap_ptr = mii_get_wrap_ptr(tx_mem_lp[p]); + int prewrap = ((char *) wrap_ptr - (char *) dptr); + int len = n; + int len1 = prewrap > len ? len : prewrap; + int len2 = prewrap > len ? 0 : len - prewrap; + memcpy(dptr, data, len1); + if (len2) { + unsigned * unsafe start_ptr = (unsigned *) *wrap_ptr; + memcpy((unsigned *) start_ptr, &data[len1], len2); + dptr = start_ptr + (len2+3)/4; + } + else { + dptr = dptr + (len+3)/4; + } + buf->length = n; + if (request_timestamp) + buf->timestamp_id = i+1; + else + buf->timestamp_id = 0; + mii_commit(tx_mem_lp[p], dptr); + mii_add_packet((mii_packet_queue_t)&tx_packets_lp[p], buf); + buf->tcount = 0; + } + tx_client_state_lp[i].send_buffer[p] = null; + } + tx_client_state_lp[i].requested_send_buffer_size = 0; + prioritize_rx = 3; } - buf->length = n; - if (request_timestamp) - buf->timestamp_id = i+1; - else - buf->timestamp_id = 0; - mii_commit(tx_mem_lp, dptr); - mii_add_packet(tx_packets_lp, buf); - buf->tcount = 0; - tx_client_state_lp[i].send_buffer = null; - tx_client_state_lp[i].requested_send_buffer_size = 0; - prioritize_rx = 3; break; default: @@ -531,38 +640,61 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, } if (!isnull(c_rx_hp)) { - handle_incoming_hp_packets(rx_mem, rx_packets_hp, rd_index_hp, c_rx_hp, p_port_state); + for(int i=0; i int: + case c_conf :> int i: // Give the routing table to the ethernet server to reconfigure unsafe { - eth_global_filter_info_t * unsafe p = &filter_info; - c_conf <: p; - c_conf :> int; + if(i == 0) // Add mac addr filter table entry + { + eth_global_filter_info_t * unsafe p = &filter_info; + c_conf <: p; + c_conf :> int; + } + else if(i == 1) // communicate if forwarding packets need to go in hp queue + { + c_conf :> forward_packets_as_high_priority; + } } break; @@ -70,12 +80,28 @@ unsafe void mii_ethernet_filter(chanend c_conf, break; } - mii_packet_t * unsafe buf = mii_get_next_buf(incoming_packets); + mii_packet_t * unsafe buf = mii_get_next_buf((mii_packet_queue_t)&incoming_packets[0]); + current_port = 0; if (buf == null) - continue; + { + if(num_mac_ports == 2) + { + buf = mii_get_next_buf((mii_packet_queue_t)&incoming_packets[1]); + if(buf == null) + { + continue; + } + current_port = 1; + } + else + { + continue; + } + } - mii_move_rd_index(incoming_packets); + + mii_move_rd_index((mii_packet_queue_t)&incoming_packets[current_port]); unsigned length = buf->length; // Number of bytes in the frame minus the CRC unsigned crc; @@ -106,7 +132,7 @@ unsafe void mii_ethernet_filter(chanend c_conf, continue; } - buf->src_port = 0; + buf->src_port = current_port; buf->timestamp_id = 0; char * unsafe data = (char * unsafe) buf->data; @@ -117,17 +143,24 @@ unsafe void mii_ethernet_filter(chanend c_conf, debug_printf("Filter result: %x\n", filter_result); buf->filter_result = filter_result; - if (ethernet_filter_result_is_hp(filter_result)) { - if (!mii_packet_queue_full(rx_packets_hp)) { - mii_add_packet(rx_packets_hp, buf); + if(!buf->filter_result) + { + // If none of the clients want the packet, forward it to the other tx port + buf->filter_result = ethernet_filter_result_set_forwarding(buf->filter_result, 1); + } + + if (ethernet_filter_result_is_hp(buf->filter_result) || forward_packets_as_high_priority) + { + if (!mii_packet_queue_full((mii_packet_queue_t)&rx_packets_hp[current_port])) { + mii_add_packet((mii_packet_queue_t)&rx_packets_hp[current_port], buf); } else { // Drop the packet because there is no room in the packet buffer // pointers } } else { - if (!mii_packet_queue_full(rx_packets_lp)) { - mii_add_packet(rx_packets_lp, buf); + if (!mii_packet_queue_full((mii_packet_queue_t)&rx_packets_lp[current_port])) { + mii_add_packet((mii_packet_queue_t)&rx_packets_lp[current_port], buf); } else { // Drop the packet because there is no room in the packet buffer // pointers diff --git a/lib_ethernet/src/rgmii_buffering.xc b/lib_ethernet/src/rgmii_buffering.xc index fc26c2cc..9d68dfca 100644 --- a/lib_ethernet/src/rgmii_buffering.xc +++ b/lib_ethernet/src/rgmii_buffering.xc @@ -296,16 +296,16 @@ unsafe static void handle_incoming_packet(rx_client_state_t client_states[n], } if (client_wants_packet) { - int wrptr = client_state.wr_index; + int wrptr = client_state.wr_index[0]; int new_wrptr = wrptr + 1; if (new_wrptr >= ETHERNET_RX_CLIENT_QUEUE_SIZE) { new_wrptr = 0; } - if (new_wrptr != client_state.rd_index) { - client_state.fifo[wrptr] = (void *)buf; + if (new_wrptr != client_state.rd_index[0]) { + client_state.fifo[0][wrptr] = (void *)buf; tcount++; i_rx[i].packet_ready(); - client_state.wr_index = new_wrptr; + client_state.wr_index[0] = new_wrptr; } else { client_state.dropped_pkt_cnt += 1; @@ -328,14 +328,14 @@ unsafe static void drop_lp_packets(rx_client_state_t client_states[n], unsigned for (unsigned i = 0; i < n; i++) { rx_client_state_t &client_state = client_states[i]; - unsigned rd_index = client_state.rd_index; - if (rd_index != client_state.wr_index) { - mii_packet_t * unsafe buf = (mii_packet_t * unsafe)client_state.fifo[rd_index]; + unsigned rd_index = client_state.rd_index[0]; + if (rd_index != client_state.wr_index[0]) { + mii_packet_t * unsafe buf = (mii_packet_t * unsafe)client_state.fifo[0][rd_index]; if (mii_get_and_dec_transmit_count(buf) == 0) { buffers_free_add(free_buffers, buf, 1); } - client_state.rd_index = increment_and_wrap_power_of_2(rd_index, + client_state.rd_index[0] = increment_and_wrap_power_of_2(rd_index, ETHERNET_RX_CLIENT_QUEUE_SIZE); client_state.dropped_pkt_cnt += 1; } @@ -430,7 +430,7 @@ unsafe void rgmii_ethernet_rx_server(rx_client_state_t client_state_lp[n_rx_lp], case i_rx_lp[int i].get_packet(ethernet_packet_info_t &desc, char data[n], unsigned n): rx_client_state_t &client_state = client_state_lp[i]; - if (client_state.status_update_state == STATUS_UPDATE_PENDING) { + if (client_state.status_update_state[0] == STATUS_UPDATE_PENDING) { data[0] = cur_link_state; data[1] = p_port_state->link_speed; desc.type = ETH_IF_STATUS; @@ -438,12 +438,12 @@ unsafe void rgmii_ethernet_rx_server(rx_client_state_t client_state_lp[n_rx_lp], desc.timestamp = 0; desc.len = 2; desc.filter_data = 0; - client_state.status_update_state = STATUS_UPDATE_WAITING; + client_state.status_update_state[0] = STATUS_UPDATE_WAITING; } - else if (client_state.rd_index != client_state.wr_index) { + else if (client_state.rd_index[0] != client_state.wr_index[0]) { // send received packet - int rd_index = client_state.rd_index; - mii_packet_t * unsafe buf = (mii_packet_t * unsafe)client_state.fifo[rd_index]; + int rd_index = client_state.rd_index[0]; + mii_packet_t * unsafe buf = (mii_packet_t * unsafe)client_state.fifo[0][rd_index]; ethernet_packet_info_t info; info.type = ETH_DATA; info.src_ifnum = 0; // There is only one RGMII port @@ -456,10 +456,10 @@ unsafe void rgmii_ethernet_rx_server(rx_client_state_t client_state_lp[n_rx_lp], buffers_free_add(free_buffers, buf, 1); } - client_state.rd_index = increment_and_wrap_power_of_2(client_state.rd_index, + client_state.rd_index[0] = increment_and_wrap_power_of_2(client_state.rd_index[0], ETHERNET_RX_CLIENT_QUEUE_SIZE); - if (client_state.rd_index != client_state.wr_index) { + if (client_state.rd_index[0] != client_state.wr_index[0]) { i_rx_lp[i].packet_ready(); } } @@ -490,8 +490,8 @@ unsafe void rgmii_ethernet_rx_server(rx_client_state_t client_state_lp[n_rx_lp], if (cur_link_state != p_port_state->link_state) { cur_link_state = p_port_state->link_state; for (unsigned i = 0; i < n_rx_lp; i += 1) { - if (client_state_lp[i].status_update_state == STATUS_UPDATE_WAITING) { - client_state_lp[i].status_update_state = STATUS_UPDATE_PENDING; + if (client_state_lp[i].status_update_state[0] == STATUS_UPDATE_WAITING) { + client_state_lp[i].status_update_state[0] = STATUS_UPDATE_PENDING; i_rx_lp[i].packet_ready(); } } @@ -565,27 +565,27 @@ unsafe void rgmii_ethernet_tx_server(tx_client_state_t client_state_lp[n_tx_lp], select { case i_tx_lp[int i]._init_send_packet(unsigned n, unsigned dst_port): - if (client_state_lp[i].send_buffer == null) { + if (client_state_lp[i].send_buffer[0] == null) { client_state_lp[i].requested_send_buffer_size = 1; } break; [[independent_guard]] case (unsigned i = 0; i < n_tx_lp; i++) - (client_state_lp[i].has_outgoing_timestamp_info) => - i_tx_lp[i]._get_outgoing_timestamp() -> unsigned timestamp: - timestamp = client_state_lp[i].outgoing_timestamp + p_port_state->egress_ts_latency[p_port_state->link_speed]; - client_state_lp[i].has_outgoing_timestamp_info = 0; + (client_state_lp[i].has_outgoing_timestamp_info[0]) => + i_tx_lp[i]._get_outgoing_timestamp(unsigned dst_port) -> unsigned timestamp: + timestamp = client_state_lp[i].outgoing_timestamp[0] + p_port_state->egress_ts_latency[p_port_state->link_speed]; + client_state_lp[i].has_outgoing_timestamp_info[0] = 0; break; [[independent_guard]] case (unsigned i = 0; i < n_tx_lp; i++) - (client_state_lp[i].send_buffer != null && !prioritize_ack) => + (client_state_lp[i].send_buffer[0] != null && !prioritize_ack) => i_tx_lp[i]._complete_send_packet(char data[n], unsigned n, int request_timestamp, - unsigned dst_port): + unsigned dst_port) -> unsigned ready: - mii_packet_t * unsafe buf = client_state_lp[i].send_buffer; + mii_packet_t * unsafe buf = client_state_lp[i].send_buffer[0]; unsigned * unsafe dptr = &buf->data[0]; memcpy(buf->data, data, n); buf->length = n; @@ -602,12 +602,14 @@ unsafe void rgmii_ethernet_tx_server(tx_client_state_t client_state_lp[n_tx_lp], work_pending++; buffers_used_add(used_buffers_tx_lp, buf, RGMII_MAC_BUFFER_COUNT_TX, 0); buf->tcount = 0; - client_state_lp[i].send_buffer = null; + client_state_lp[i].send_buffer[0] = null; client_state_lp[i].requested_send_buffer_size = 0; prioritize_ack += 2; break; case (tx_buf_hp && !prioritize_ack) => c_tx_hp :> unsigned n_bytes: + c_tx_hp :> unsigned dst_port; + c_tx_hp <: 1; // protocol requires 'ready' to be transmitted sin_char_array(c_tx_hp, (char *)tx_buf_hp->data, n_bytes); tx_buf_hp->length = n_bytes; tx_buf_hp->timestamp_id = 0; @@ -632,8 +634,8 @@ unsafe void rgmii_ethernet_tx_server(tx_client_state_t client_state_lp[n_tx_lp], // Low priority packet sent if (buf->timestamp_id) { size_t client_id = buf->timestamp_id - 1; - client_state_lp[client_id].has_outgoing_timestamp_info = 1; - client_state_lp[client_id].outgoing_timestamp = buf->timestamp + p_port_state->egress_ts_latency[p_port_state->link_speed]; + client_state_lp[client_id].has_outgoing_timestamp_info[0] = 1; + client_state_lp[client_id].outgoing_timestamp[0] = buf->timestamp + p_port_state->egress_ts_latency[p_port_state->link_speed]; } buffers_free_add(free_buffers_lp, buf, 0); } @@ -710,8 +712,8 @@ unsafe void rgmii_ethernet_tx_server(tx_client_state_t client_state_lp[n_tx_lp], } for (unsigned i = 0; i < n_tx_lp; i++) { - if (client_state_lp[i].requested_send_buffer_size != 0 && client_state_lp[i].send_buffer == null) { - client_state_lp[i].send_buffer = buffers_free_take(free_buffers_lp, 0); + if (client_state_lp[i].requested_send_buffer_size != 0 && client_state_lp[i].send_buffer[0] == null) { + client_state_lp[i].send_buffer[0] = buffers_free_take(free_buffers_lp, 0); } } } @@ -847,17 +849,21 @@ void rgmii_ethernet_mac_config(server ethernet_cfg_if i_cfg[n], case i_cfg[int i].enable_link_status_notification(size_t client_num): unsafe { rx_client_state_t &client_state = client_state_lp[client_num]; - client_state.status_update_state = STATUS_UPDATE_WAITING; + client_state.status_update_state[0] = STATUS_UPDATE_WAITING; break; } case i_cfg[int i].disable_link_status_notification(size_t client_num): unsafe { rx_client_state_t &client_state = client_state_lp[client_num]; - client_state.status_update_state = STATUS_UPDATE_IGNORING; + client_state.status_update_state[0] = STATUS_UPDATE_IGNORING; break; } + case i_cfg[int i].forward_packets_as_hp(unsigned forward_packets_in_hp_queue): + // Do nothing - Not supported on rgmii + break; + case i_cfg[int i].exit(void): // Do nothing - exit not supported on this MAC break; diff --git a/lib_ethernet/src/rmii_ethernet_rt_mac.xc b/lib_ethernet/src/rmii_ethernet_rt_mac.xc index edc3c2f0..e415508b 100644 --- a/lib_ethernet/src/rmii_ethernet_rt_mac.xc +++ b/lib_ethernet/src/rmii_ethernet_rt_mac.xc @@ -39,6 +39,72 @@ static out buffered port:32 * unsafe enable_buffered_out_port(unsigned *port_poi } + +{unsigned, rmii_data_4b_pin_assignment_t, in buffered port:32 * unsafe,in buffered port:32 * unsafe} + init_rx_ports(in_port_t p_clk, + in_port_t p_rxdv, + clock rxclk, + rmii_data_port_t * unsafe p_rxd){ + unsafe { + in buffered port:32 * unsafe rx_data_0 = NULL; + in buffered port:32 * unsafe rx_data_1 = NULL; + // Extract width and optionally which 4b pins to use + unsigned rx_port_width = ((unsigned)(p_rxd->rmii_data_1b.data_0) >> 16) & 0xff; + rmii_data_4b_pin_assignment_t rx_port_4b_pins = (rmii_data_4b_pin_assignment_t)(p_rxd->rmii_data_1b.data_1); + + // Extract pointers to ports with correct port qualifiers and setup data pins + switch(rx_port_width){ + case 4: + rx_data_0 = enable_buffered_in_port((unsigned*)(&p_rxd->rmii_data_1b.data_0), 32); + rmii_master_init_rx_4b(p_clk, rx_data_0, p_rxdv, rxclk); + break; + case 1: + rx_data_0 = enable_buffered_in_port((unsigned*)&p_rxd->rmii_data_1b.data_0, 32); + rx_data_1 = enable_buffered_in_port((unsigned*)&p_rxd->rmii_data_1b.data_1, 32); + rmii_master_init_rx_1b(p_clk, rx_data_0, rx_data_1, p_rxdv, rxclk); + break; + default: + fail("Invald port width for RMII Rx"); + break; + } + + return {rx_port_width, rx_port_4b_pins, rx_data_0, rx_data_1}; + } +} + + +{unsigned, rmii_data_4b_pin_assignment_t, out buffered port:32 * unsafe, out buffered port:32 * unsafe} + init_tx_ports(in_port_t p_clk, + out_port_t p_txen, + clock txclk, + rmii_data_port_t * unsafe p_txd){ + unsafe { + out buffered port:32 * unsafe tx_data_0; + out buffered port:32 * unsafe tx_data_1; + unsigned tx_port_width = ((unsigned)(p_txd->rmii_data_1b.data_0) >> 16) & 0xff; + rmii_data_4b_pin_assignment_t tx_port_4b_pins = (rmii_data_4b_pin_assignment_t)(p_txd->rmii_data_1b.data_1); + + switch(tx_port_width){ + case 4: + tx_data_0 = enable_buffered_out_port((unsigned*)(&p_txd->rmii_data_1b.data_0), 32); + rmii_master_init_tx_4b(p_clk, tx_data_0, p_txen, txclk); + break; + case 1: + tx_data_0 = enable_buffered_out_port((unsigned*)&p_txd->rmii_data_1b.data_0, 32); + tx_data_1 = enable_buffered_out_port((unsigned*)&p_txd->rmii_data_1b.data_1, 32); + rmii_master_init_tx_1b(p_clk, tx_data_0, tx_data_1, p_txen, txclk); + break; + default: + fail("Invald port width for RMII Tx"); + break; + } + + return {tx_port_width, tx_port_4b_pins, tx_data_0, tx_data_1}; + + } +} + + void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), static_const_unsigned_t n_cfg, SERVER_INTERFACE(ethernet_rx_if, i_rx_lp[n_rx_lp]), static_const_unsigned_t n_rx_lp, SERVER_INTERFACE(ethernet_tx_if, i_tx_lp[n_tx_lp]), static_const_unsigned_t n_tx_lp, @@ -58,7 +124,11 @@ void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), stati // Setup buffering unsigned int rx_data[rx_bufsize_words]; unsigned int tx_data[tx_bufsize_words]; - mii_mempool_t rx_mem = mii_init_mempool(rx_data, rx_bufsize_words*4); + mii_mempool_t rx_mem[1]; + mii_mempool_t * unsafe rx_mem_ptr = (mii_mempool_t *)rx_mem; + + + rx_mem[0] = mii_init_mempool(rx_data, rx_bufsize_words*4); // If the high priority traffic is connected then allocate half the buffer for high priority // and half for low priority. Otherwise, allocate it all to low priority. @@ -66,6 +136,8 @@ void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), stati const size_t hp_buffer_bytes = tx_bufsize_words * 4 - lp_buffer_bytes; mii_mempool_t tx_mem_lp = mii_init_mempool(tx_data, lp_buffer_bytes); mii_mempool_t tx_mem_hp = mii_init_mempool(tx_data + (lp_buffer_bytes/4), hp_buffer_bytes); + mii_mempool_t * unsafe tx_mem_lp_ptr = (mii_mempool_t *)&tx_mem_lp; + mii_mempool_t * unsafe tx_mem_hp_ptr = (mii_mempool_t *)&tx_mem_hp; packet_queue_info_t rx_packets_lp, rx_packets_hp, tx_packets_lp, tx_packets_hp, incoming_packets; mii_init_packet_queue((mii_packet_queue_t)&rx_packets_lp); @@ -73,10 +145,15 @@ void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), stati mii_init_packet_queue((mii_packet_queue_t)&tx_packets_lp); mii_init_packet_queue((mii_packet_queue_t)&tx_packets_hp); mii_init_packet_queue((mii_packet_queue_t)&incoming_packets); + packet_queue_info_t * unsafe incoming_packets_ptr = &incoming_packets; + packet_queue_info_t * unsafe rx_packets_lp_ptr = &rx_packets_lp; + packet_queue_info_t * unsafe rx_packets_hp_ptr = &rx_packets_hp; + packet_queue_info_t * unsafe tx_packets_lp_ptr = &tx_packets_lp; + packet_queue_info_t * unsafe tx_packets_hp_ptr = &tx_packets_hp; // Shared read pointer to help optimize the RX code unsigned rx_rdptr = 0; - unsigned * unsafe p_rx_rdptr = &rx_rdptr; + mii_rdptr_t * unsafe p_rx_rdptr = (mii_rdptr_t*)&rx_rdptr; mii_init_lock(); @@ -92,59 +169,28 @@ void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), stati fail("Using high priority channels without #define ETHERNET_SUPPORT_HP_QUEUES set true"); } - mii_ts_queue_t ts_queue = mii_ts_queue_init(&ts_queue_info, ts_fifo, n_tx_lp + 1); - + mii_ts_queue_init(&ts_queue_info, ts_fifo, n_tx_lp + 1); + mii_ts_queue_info_t * unsafe ts_queue_info_ptr = &ts_queue_info; // Common initialisation set_port_use_on(p_clk); // RMII 50MHz clock input port // Setup RX data ports - // First declare C pointers for port resources + // First declare C pointers for port resources and the initialise in buffered port:32 * unsafe rx_data_0 = NULL; in buffered port:32 * unsafe rx_data_1 = NULL; - - // Extract width and optionally which 4b pins to use - unsigned rx_port_width = ((unsigned)(p_rxd->rmii_data_1b.data_0) >> 16) & 0xff; - rmii_data_4b_pin_assignment_t rx_port_4b_pins = (rmii_data_4b_pin_assignment_t)(p_rxd->rmii_data_1b.data_1); - - // Extract pointers to ports with correct port qualifiers and setup data pins - switch(rx_port_width){ - case 4: - rx_data_0 = enable_buffered_in_port((unsigned*)(&p_rxd->rmii_data_1b.data_0), 32); - rmii_master_init_rx_4b(p_clk, rx_data_0, p_rxdv, rxclk); - break; - case 1: - rx_data_0 = enable_buffered_in_port((unsigned*)&p_rxd->rmii_data_1b.data_0, 32); - rx_data_1 = enable_buffered_in_port((unsigned*)&p_rxd->rmii_data_1b.data_1, 32); - rmii_master_init_rx_1b(p_clk, rx_data_0, rx_data_1, p_rxdv, rxclk); - break; - default: - fail("Invald port width for RMII Rx"); - break; - } + unsigned rx_port_width; + rmii_data_4b_pin_assignment_t rx_port_4b_pins; + {rx_port_width, rx_port_4b_pins, rx_data_0, rx_data_1} = init_rx_ports(p_clk, p_rxdv, rxclk, p_rxd); // Setup TX data ports + // First declare C pointers for port resources and the initialise out buffered port:32 * unsafe tx_data_0 = NULL; out buffered port:32 * unsafe tx_data_1 = NULL; - - unsigned tx_port_width = ((unsigned)(p_txd->rmii_data_1b.data_0) >> 16) & 0xff; - rmii_data_4b_pin_assignment_t tx_port_4b_pins = (rmii_data_4b_pin_assignment_t)(p_txd->rmii_data_1b.data_1); - - switch(tx_port_width){ - case 4: - tx_data_0 = enable_buffered_out_port((unsigned*)(&p_txd->rmii_data_1b.data_0), 32); - rmii_master_init_tx_4b(p_clk, tx_data_0, p_txen, txclk); - break; - case 1: - tx_data_0 = enable_buffered_out_port((unsigned*)&p_txd->rmii_data_1b.data_0, 32); - tx_data_1 = enable_buffered_out_port((unsigned*)&p_txd->rmii_data_1b.data_1, 32); - rmii_master_init_tx_1b(p_clk, tx_data_0, tx_data_1, p_txen, txclk); - break; - default: - fail("Invald port width for RMII Tx"); - break; - } + unsigned tx_port_width; + rmii_data_4b_pin_assignment_t tx_port_4b_pins; + {tx_port_width, tx_port_4b_pins, tx_data_0, tx_data_1} = init_tx_ports(p_clk, p_txen, txclk, p_txd); // Setup server ethernet_port_state_t port_state; @@ -155,62 +201,67 @@ void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), stati // Exit flag and chanend int rmii_ethernet_rt_mac_running = 1; int * unsafe running_flag_ptr = &rmii_ethernet_rt_mac_running; - chan c_rx_pins_exit; + chan c_rx_pins_exit[1]; chan c_conf; par { // Rx task { if(rx_port_width == 4){ - rmii_master_rx_pins_4b(rx_mem, + rmii_master_rx_pins_4b(rx_mem[0], (mii_packet_queue_t)&incoming_packets, - p_rx_rdptr, + (mii_rdptr_t)&rx_rdptr, p_rxdv, rx_data_0, rx_port_4b_pins, running_flag_ptr, - c_rx_pins_exit); + c_rx_pins_exit[0]); } else { - rmii_master_rx_pins_1b(rx_mem, + rmii_master_rx_pins_1b(rx_mem[0], (mii_packet_queue_t)&incoming_packets, - p_rx_rdptr, + (mii_rdptr_t)&rx_rdptr, p_rxdv, rx_data_0, rx_data_1, running_flag_ptr, - c_rx_pins_exit); + c_rx_pins_exit[0]); } } // Tx task - rmii_master_tx_pins(tx_mem_lp, tx_mem_hp, (mii_packet_queue_t)&tx_packets_lp, (mii_packet_queue_t)&tx_packets_hp, - ts_queue, + rx_mem_ptr, + rx_packets_lp_ptr, + rx_packets_hp_ptr, + &ts_queue_info, tx_port_width, tx_data_0, tx_data_1, tx_port_4b_pins, txclk, p_port_state, - running_flag_ptr); + 0, + running_flag_ptr, + 1); mii_ethernet_filter(c_conf, - (mii_packet_queue_t)&incoming_packets, - (mii_packet_queue_t)&rx_packets_lp, - (mii_packet_queue_t)&rx_packets_hp, - running_flag_ptr); - - mii_ethernet_server(rx_mem, - (mii_packet_queue_t)&rx_packets_lp, - (mii_packet_queue_t)&rx_packets_hp, + incoming_packets_ptr, + rx_packets_lp_ptr, + rx_packets_hp_ptr, + running_flag_ptr, + 1); + + mii_ethernet_server(rx_mem_ptr, + rx_packets_lp_ptr, + rx_packets_hp_ptr, p_rx_rdptr, - tx_mem_lp, - tx_mem_hp, - (mii_packet_queue_t)&tx_packets_lp, - (mii_packet_queue_t)&tx_packets_hp, - ts_queue, + tx_mem_lp_ptr, + tx_mem_hp_ptr, + tx_packets_lp_ptr, + tx_packets_hp_ptr, + ts_queue_info_ptr, i_cfg, n_cfg, i_rx_lp, n_rx_lp, i_tx_lp, n_tx_lp, @@ -220,7 +271,8 @@ void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), stati p_port_state, running_flag_ptr, c_rx_pins_exit, - ETH_MAC_IF_RMII); + ETH_MAC_IF_RMII, + 1); } // par // If exit occurred, disable used ports and resources so they are left in a good state @@ -264,3 +316,259 @@ void rmii_ethernet_rt_mac(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), stati } // unsafe block } + + +void rmii_ethernet_rt_mac_dual(SERVER_INTERFACE(ethernet_cfg_if, i_cfg[n_cfg]), static_const_unsigned_t n_cfg, + SERVER_INTERFACE(ethernet_rx_if, i_rx_lp[n_rx_lp]), static_const_unsigned_t n_rx_lp, + SERVER_INTERFACE(ethernet_tx_if, i_tx_lp[n_tx_lp]), static_const_unsigned_t n_tx_lp, + nullable_streaming_chanend_t c_rx_hp, + nullable_streaming_chanend_t c_tx_hp, + in_port_t p_clk, + rmii_data_port_t * unsafe p_rxd_0, in_port_t p_rxdv_0, + out_port_t p_txen_0, rmii_data_port_t * unsafe p_txd_0, + clock rxclk_0, + clock txclk_0, + rmii_data_port_t * unsafe p_rxd_1, in_port_t p_rxdv_1, + out_port_t p_txen_1, rmii_data_port_t * unsafe p_txd_1, + clock rxclk_1, + clock txclk_1, + static_const_unsigned_t rx_bufsize_words, + static_const_unsigned_t tx_bufsize_words, + enum ethernet_enable_shaper_t enable_shaper) +{ + // Establish types of data ports presented + unsafe{ + // Setup buffering + unsigned int rx_data[rx_bufsize_words ][2]; + unsigned int tx_data[tx_bufsize_words][2]; + mii_mempool_t rx_mem[2]; + mii_mempool_t * unsafe rx_mem_ptr = (mii_mempool_t *)rx_mem; + for(int i=0; i<2; i++) + { + rx_mem[i] = mii_init_mempool(&rx_data[0][0] + i*rx_bufsize_words, rx_bufsize_words*4); + } + + // If the high priority traffic is connected then allocate half the buffer for high priority + // and half for low priority. Otherwise, allocate it all to low priority. + const size_t lp_buffer_bytes = !isnull(c_tx_hp) ? tx_bufsize_words * 2 : tx_bufsize_words * 4; + const size_t hp_buffer_bytes = tx_bufsize_words * 4 - lp_buffer_bytes; + + mii_mempool_t tx_mem_lp[2], tx_mem_hp[2]; + for(int i=0; i<2; i++) + { + tx_mem_lp[i] = mii_init_mempool(&tx_data[0][0] + i*((lp_buffer_bytes/4) + (hp_buffer_bytes/4)), lp_buffer_bytes); + tx_mem_hp[i] = mii_init_mempool(&tx_data[0][0] + i*((lp_buffer_bytes/4) + (hp_buffer_bytes/4)) + (lp_buffer_bytes/4), hp_buffer_bytes); + } + mii_mempool_t * unsafe tx_mem_lp_ptr = (mii_mempool_t *)tx_mem_lp; + mii_mempool_t * unsafe tx_mem_hp_ptr = (mii_mempool_t *)tx_mem_hp; + + packet_queue_info_t rx_packets_lp[2], rx_packets_hp[2], incoming_packets[2]; + packet_queue_info_t tx_packets_lp[2], tx_packets_hp[2]; + + packet_queue_info_t * unsafe incoming_packets_ptr = incoming_packets; + packet_queue_info_t * unsafe rx_packets_lp_ptr = rx_packets_lp; + packet_queue_info_t * unsafe rx_packets_hp_ptr = rx_packets_hp; + packet_queue_info_t * unsafe tx_packets_lp_ptr = tx_packets_lp; + packet_queue_info_t * unsafe tx_packets_hp_ptr = tx_packets_hp; + + for(int i=0; i<2; i++) + { + mii_init_packet_queue((mii_packet_queue_t)&incoming_packets[i]); + mii_init_packet_queue((mii_packet_queue_t)&rx_packets_lp[i]); + mii_init_packet_queue((mii_packet_queue_t)&rx_packets_hp[i]); + mii_init_packet_queue((mii_packet_queue_t)&tx_packets_lp[i]); + mii_init_packet_queue((mii_packet_queue_t)&tx_packets_hp[i]); + } + + + // Shared read pointer to help optimize the RX code + unsigned rx_rdptr[2] = {0}; + mii_rdptr_t * unsafe p_rx_rdptr = (mii_rdptr_t *)rx_rdptr; // Array of pointers + + + mii_init_lock(); + mii_ts_queue_entry_t ts_fifo[2][MII_TIMESTAMP_QUEUE_MAX_SIZE + 1]; + mii_ts_queue_info_t ts_queue_info[2]; + + if (n_tx_lp > MII_TIMESTAMP_QUEUE_MAX_SIZE) { + fail("Exceeded maximum number of transmit clients. Increase MII_TIMESTAMP_QUEUE_MAX_SIZE in ethernet_conf.h"); + } + + if (!ETHERNET_SUPPORT_HP_QUEUES && (!isnull(c_rx_hp) || !isnull(c_tx_hp))) { + fail("Using high priority channels without #define ETHERNET_SUPPORT_HP_QUEUES set true"); + } + + for(int i=0; i<2; i++) + { + mii_ts_queue_init(&ts_queue_info[i], ts_fifo[i], n_tx_lp + 1); + } + mii_ts_queue_info_t * unsafe ts_queue_info_ptr = ts_queue_info; + + + + + // Common initialisation + set_port_use_on(p_clk); // RMII 50MHz clock input port + + // Setup RX data ports + // First declare C pointers for port resources and the initialise + // MAC port 0 + in buffered port:32 * unsafe rx_data_0_0 = NULL; + in buffered port:32 * unsafe rx_data_0_1 = NULL; + unsigned rx_port_width_0; + rmii_data_4b_pin_assignment_t rx_port_4b_pins_0; + {rx_port_width_0, rx_port_4b_pins_0, rx_data_0_0, rx_data_0_1} = init_rx_ports(p_clk, p_rxdv_0, rxclk_0, p_rxd_0); + // MAC port 1 + in buffered port:32 * unsafe rx_data_1_0 = NULL; + in buffered port:32 * unsafe rx_data_1_1 = NULL; + unsigned rx_port_width_1 = 0; + rmii_data_4b_pin_assignment_t rx_port_4b_pins_1; + {rx_port_width_1, rx_port_4b_pins_1, rx_data_1_0, rx_data_1_1} = init_rx_ports(p_clk, p_rxdv_1, rxclk_1, p_rxd_1); + + + + // Setup TX data ports + // First declare C pointers for port resources and the initialise + // MAC port 0 + out buffered port:32 * unsafe tx_data_0_0 = NULL; + out buffered port:32 * unsafe tx_data_0_1 = NULL; + unsigned tx_port_width_0; + rmii_data_4b_pin_assignment_t tx_port_4b_pins_0; + {tx_port_width_0, tx_port_4b_pins_0, tx_data_0_0, tx_data_0_1} = init_tx_ports(p_clk, p_txen_0, txclk_0, p_txd_0); + // MAC port 1 + out buffered port:32 * unsafe tx_data_1_0 = NULL; + out buffered port:32 * unsafe tx_data_1_1 = NULL; + unsigned tx_port_width_1; + rmii_data_4b_pin_assignment_t tx_port_4b_pins_1; + {tx_port_width_1, tx_port_4b_pins_1, tx_data_1_0, tx_data_1_1} = init_tx_ports(p_clk, p_txen_1, txclk_1, p_txd_1); + + // Setup server + ethernet_port_state_t port_state[2]; + + for(int i=0; i<2; i++) + { + init_server_port_state(port_state[i], enable_shaper == ETHERNET_ENABLE_SHAPER); + } + + ethernet_port_state_t * unsafe p_port_state = (ethernet_port_state_t * unsafe)port_state; + + // Exit flag and chanend + int rmii_ethernet_rt_mac_running = 1; + int * unsafe running_flag_ptr = &rmii_ethernet_rt_mac_running; + chan c_rx_pins_exit[2]; + + chan c_conf; + par + { + { + if(rx_port_width_0 == 4) + { + rmii_master_rx_pins_4b(rx_mem[0], + (mii_packet_queue_t)(&incoming_packets[0]), + (mii_rdptr_t)&rx_rdptr[0], + p_rxdv_0, + rx_data_0_0, + rx_port_4b_pins_0, + running_flag_ptr, + c_rx_pins_exit[0]); + } else { + rmii_master_rx_pins_1b(rx_mem[0], + (mii_packet_queue_t)(&incoming_packets[0]), + (mii_rdptr_t)&rx_rdptr[0], + p_rxdv_0, + rx_data_0_0, + rx_data_0_1, + running_flag_ptr, + c_rx_pins_exit[0]); + } + } + { + if(rx_port_width_1 == 4) + { + rmii_master_rx_pins_4b(rx_mem[1], + (mii_packet_queue_t)(&incoming_packets[1]), + (mii_rdptr_t)&rx_rdptr[1], + p_rxdv_1, + rx_data_1_0, + rx_port_4b_pins_1, + running_flag_ptr, + c_rx_pins_exit[1]); + } else { + rmii_master_rx_pins_1b(rx_mem[1], + (mii_packet_queue_t)(&incoming_packets[1]), + (mii_rdptr_t)&rx_rdptr[1], + p_rxdv_1, + rx_data_1_0, + rx_data_1_1, + running_flag_ptr, + c_rx_pins_exit[1]); + } + } + rmii_master_tx_pins(tx_mem_lp[0], + tx_mem_hp[0], + (mii_packet_queue_t)(&tx_packets_lp[0]), + (mii_packet_queue_t)(&tx_packets_hp[0]), + rx_mem_ptr, // memory pool for the forwarding packets + rx_packets_lp_ptr, // lp forwarding packets queue + rx_packets_hp_ptr, // hp forwarding packets queue + (mii_ts_queue_t)&ts_queue_info[0], + tx_port_width_0, + tx_data_0_0, + tx_data_0_1, + tx_port_4b_pins_0, + txclk_0, + &p_port_state[0], + 0, + running_flag_ptr, + 2); + + rmii_master_tx_pins(tx_mem_lp[1], + tx_mem_hp[1], + (mii_packet_queue_t)(&tx_packets_lp[1]), + (mii_packet_queue_t)(&tx_packets_hp[1]), + rx_mem_ptr, // memory pool for the forwarding packets + rx_packets_lp_ptr, // lp forwarding packets queue + rx_packets_hp_ptr, // hp forwarding packets queue + (mii_ts_queue_t)&ts_queue_info[1], + tx_port_width_1, + tx_data_1_0, + tx_data_1_1, + tx_port_4b_pins_1, + txclk_1, + &p_port_state[1], + 1, + running_flag_ptr, + 2); + + + mii_ethernet_filter(c_conf, + incoming_packets_ptr, + rx_packets_lp_ptr, + rx_packets_hp_ptr, + running_flag_ptr, + 2); + + mii_ethernet_server(rx_mem_ptr, + rx_packets_lp_ptr, + rx_packets_hp_ptr, + p_rx_rdptr, + tx_mem_lp_ptr, + tx_mem_hp_ptr, + tx_packets_lp_ptr, + tx_packets_hp_ptr, + ts_queue_info_ptr, + i_cfg, n_cfg, + i_rx_lp, n_rx_lp, + i_tx_lp, n_tx_lp, + c_rx_hp, + c_tx_hp, + c_conf, + p_port_state, + running_flag_ptr, + c_rx_pins_exit, + ETH_MAC_IF_RMII, + 2); + } // par + } // unsafe block +} + diff --git a/lib_ethernet/src/rmii_master.h b/lib_ethernet/src/rmii_master.h index 35f6933a..c8b7ce2a 100644 --- a/lib_ethernet/src/rmii_master.h +++ b/lib_ethernet/src/rmii_master.h @@ -52,6 +52,9 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, mii_mempool_t tx_mem_hp, mii_packet_queue_t hp_packets, mii_packet_queue_t lp_packets, + mii_mempool_t * unsafe forwarding_mem, + packet_queue_info_t * unsafe forwarding_packets_lp, + packet_queue_info_t * unsafe forwarding_packets_hp, mii_ts_queue_t ts_queue_lp, unsigned tx_port_width, out buffered port:32 * unsafe p_mii_txd_0, @@ -59,18 +62,20 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, rmii_data_4b_pin_assignment_t tx_port_4b_pins, clock txclk, volatile ethernet_port_state_t * unsafe p_port_state, - volatile int * unsafe running_flag_ptr); + int ifnum, + volatile int * unsafe running_flag_ptr, + static const unsigned num_mac_ports); // This is re-used by RMII as it is abstracted from the MAC pins -unsafe void mii_ethernet_server(mii_mempool_t rx_mem, - mii_packet_queue_t rx_packets_lp, - mii_packet_queue_t rx_packets_hp, - unsigned * unsafe rx_rdptr, - mii_mempool_t tx_mem_lp, - mii_mempool_t tx_mem_hp, - mii_packet_queue_t tx_packets_lp, - mii_packet_queue_t tx_packets_hp, +unsafe void mii_ethernet_server(mii_mempool_t * unsafe rx_mem, + packet_queue_info_t * unsafe rx_packets_lp, + packet_queue_info_t * unsafe rx_packets_hp, + mii_rdptr_t * unsafe rx_rdptr, + mii_mempool_t * unsafe tx_mem_lp, + mii_mempool_t * unsafe tx_mem_hp, + packet_queue_info_t * unsafe tx_packets_lp, + packet_queue_info_t * unsafe tx_packets_hp, mii_ts_queue_t ts_queue_lp, server ethernet_cfg_if i_cfg[n_cfg], static const unsigned n_cfg, server ethernet_rx_if i_rx_lp[n_rx_lp], static const unsigned n_rx_lp, @@ -80,8 +85,9 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem, chanend c_macaddr_filter, volatile ethernet_port_state_t * unsafe p_port_state, volatile int * unsafe running_flag_ptr, - chanend c_rx_pins_exit, - phy_100mb_t phy_type); + chanend c_rx_pins_exit[], + phy_100mb_t phy_type, + static const unsigned num_mac_ports); #endif diff --git a/lib_ethernet/src/rmii_master.xc b/lib_ethernet/src/rmii_master.xc index 87ddd8af..81e7e61f 100644 --- a/lib_ethernet/src/rmii_master.xc +++ b/lib_ethernet/src/rmii_master.xc @@ -505,7 +505,7 @@ unsafe void rmii_master_rx_pins_4b( mii_mempool_t rx_mem, /* pointers never fill up */ mii_add_packet(incoming_packets, buf); } - + // Exit cleanly so we don't leave channels full/in use rx_end_disable_interrupt(); rx_end_drain_and_clear(c_rx_pins_exit); @@ -682,7 +682,7 @@ unsafe void rmii_master_rx_pins_1b( mii_mempool_t rx_mem, in buffered port:32 * unsafe p_mii_rxd_1, volatile int * unsafe running_flag_ptr, chanend c_rx_pins_exit){ - + // Setup ISR to for exiting this task int isrstack[RXE_ISR_CONTEXT_WORDS] = {0}; rx_end_isr_ctx_t isr_ctx = { @@ -980,6 +980,9 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, mii_mempool_t tx_mem_hp, mii_packet_queue_t packets_lp, mii_packet_queue_t packets_hp, + mii_mempool_t * unsafe forwarding_packets_mem, + packet_queue_info_t * unsafe forwarding_packets_lp, + packet_queue_info_t * unsafe forwarding_packets_hp, mii_ts_queue_t ts_queue_lp, unsigned tx_port_width, out buffered port:32 * unsafe p_mii_txd_0, @@ -987,8 +990,10 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, rmii_data_4b_pin_assignment_t tx_port_4b_pins, clock txclk, volatile ethernet_port_state_t * unsafe p_port_state, - volatile int * unsafe running_flag_ptr){ - + int ifnum, + volatile int * unsafe running_flag_ptr, + static const unsigned num_mac_ports) +{ // Flag for readability and faster comparison const unsigned use_4b = (tx_port_width == 4); @@ -1002,6 +1007,7 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, unsigned eof_time = 0; unsigned enable_shaper = p_port_state->qav_shaper_enabled; + if (!ETHERNET_SUPPORT_TRAFFIC_SHAPER) { enable_shaper = 0; } @@ -1015,9 +1021,32 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, mii_packet_t * unsafe buf = null; mii_ts_queue_t *p_ts_queue = null; mii_mempool_t tx_mem = tx_mem_hp; + mii_packet_queue_t pkt_queue = packets_hp; if (ETHERNET_SUPPORT_HP_QUEUES){ buf = mii_get_next_buf(packets_hp); + if(!buf) + { + for (unsigned int i=0; iforwarding) + { + tx_mem = forwarding_packets_mem[i]; + pkt_queue = (mii_packet_queue_t)&forwarding_packets_hp[i]; + break; + } + buf = 0; + } + } } if (enable_shaper) { @@ -1039,9 +1068,32 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, } if (!buf) { + tx_mem = tx_mem_lp; + pkt_queue = packets_lp; buf = mii_get_next_buf(packets_lp); + if(!buf) + { + for (unsigned int i=0; iforwarding) + { + tx_mem = forwarding_packets_mem[i]; + pkt_queue = (mii_packet_queue_t)&forwarding_packets_lp[i]; + break; + } + buf = 0; + } + } p_ts_queue = &ts_queue_lp; - tx_mem = tx_mem_lp; } if (!buf) { @@ -1067,8 +1119,6 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, } } - - const int packet_is_high_priority = (p_ts_queue == null); if (enable_shaper && packet_is_high_priority) { const int preamble_bytes = 8; @@ -1085,9 +1135,9 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp, mii_ts_queue_add_entry(*p_ts_queue, buf->timestamp_id, time); } - mii_free_current(packets_lp); + mii_free_current(pkt_queue); } else { - mii_free_current(packets_hp); + mii_free_current(pkt_queue); } } } diff --git a/requirements.txt b/requirements.txt index 9ef24564..d39791de 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,6 +23,7 @@ pytest==8.2.2 pytest-xdist==3.6.1 filelock==3.16.1 bitstring==4.3.0 +numpy==2.2.2 # Development dependencies # diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d51f1f4c..fd27beb0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,5 +20,6 @@ add_subdirectory(test_rx_queues) add_subdirectory(test_check_ifg_wait) add_subdirectory(test_rmii_timing) add_subdirectory(test_rmii_restart) +add_subdirectory(test_rmii_dual_basic) add_subdirectory(test_smi) diff --git a/tests/helpers.py b/tests/helpers.py index 41c2c75a..d39044b0 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -9,6 +9,8 @@ import pytest import json import copy +import numpy as np +import multiprocessing from mii_clock import Clock from mii_phy import MiiTransmitter, MiiReceiver @@ -184,11 +186,27 @@ def do_rx_test(capfd, mac, arch, rx_clk, rx_phy, tx_clk, tx_phy, packets, test_f def create_expect(packets, filename): """ Create the expect file for what packets should be reported by the DUT """ + # Check if the packet array is one or 2 dimensional. + # ndim=1 means its an array of packets, all meant for a single ethernet port + # ndim=2 means, its a 2D array of form [num ehthernet ports][packets for a given port] + # Anything other than 1 or 2 is unexpected and should be flagged. + ndim = np.array(packets).ndim with open(filename, 'w') as f: - for i,packet in enumerate(packets): - if not packet.dropped: - f.write("Received packet {} ok\n".format(i)) - f.write("Test done\n") + if ndim == 1: + for i,packet in enumerate(packets): + if not packet.dropped: + f.write(f"Received packet {i} ok\n") + f.write("Test done\n") + elif ndim == 2: + for id in range(2): + for i,packet in enumerate(packets[id]): + if not packet.dropped: + f.write(f"Phy {id} Received packet {i} ok\n") + f.write("Test done\n") + else: + assert False, f"Incorrect dimensions of the packets array.\n{packets}" + + def get_sim_args(testname, mac, clk, phy, arch='xs2'): sim_args = [] @@ -260,7 +278,10 @@ def check_received_packet(packet, phy): print("Expected:") sys.stdout.write(expected.dump()) - print(f"Received packet {phy.expect_packet_index} ok") + st = f"Received packet {phy.expect_packet_index} ok" + if phy.get_id() != None: + st = f"Phy {phy.get_id()} " + st + print(st) # Skip this packet phy.expect_packet_index += 1 @@ -274,6 +295,15 @@ def check_received_packet(packet, phy): if phy.expect_packet_index >= phy.num_expected_packets: print("Test done") + if phy._sync_pipe != None: + phy._sync_pipe.send(f"done") # Send done to the other phy + while True: # wait for a done from the other end + poll_duration_us = 1 + poll_duration_ticks = (poll_duration_us* px.Xsi.get_xsi_tick_freq_hz())/1e6 + phy.wait_until(phy.xsi.get_time() + poll_duration_ticks) # Thread needs to yield for other threads to run + if phy._sync_pipe.poll(0): # Check if there's something to receive from the other phy + assert phy._sync_pipe.recv() == "done", "Unexpected recv over the pipe from the other phy" + break phy.xsi.terminate() def generate_tests(test_params_json): @@ -328,6 +358,20 @@ def get_rmii_tx_phy(rx_width, clk, **kwargs): assert False, f"get_rmii_tx_phy(): Invalid rx_width {rx_width}" return tx_rmii_phy +def get_rmii_tx_phy_dual(rx_widths, clk, **kwargs): + tx_rmii_phy = get_rmii_tx_phy(rx_widths[0], + clk, + **kwargs + ) + + tx_rmii_phy_2 = get_rmii_tx_phy(rx_widths[1], + clk, + **kwargs, + second_phy=True + ) + return tx_rmii_phy, tx_rmii_phy_2 + + def get_rmii_rx_phy(tx_width, clk, **kwargs): if tx_width == "4b_lower": rx_rmii_phy = get_rmii_4b_port_rx_phy(clk, @@ -347,12 +391,35 @@ def get_rmii_rx_phy(tx_width, clk, **kwargs): assert False, f"get_rmii_rx_phy(): Invalid tx_width {tx_width}" return rx_rmii_phy +def get_rmii_rx_phy_dual(tx_widths, clk, **kwargs): + end1, end2 = multiprocessing.Pipe() + + rx_rmii_phy = get_rmii_rx_phy(tx_widths[0], + clk, + **kwargs, + id="0", + sync_pipe=end1 + ) + + rx_rmii_phy_2 = get_rmii_rx_phy(tx_widths[1], + clk, + **kwargs, + second_phy=True, + id="1", + sync_pipe=end2 + ) + return rx_rmii_phy, rx_rmii_phy_2 def get_rmii_4b_port_tx_phy(clk, rxd_4b_port_pin_assignment, **kwargs): - phy = RMiiTransmitter('tile[0]:XS1_PORT_4A', # 4b rxd port - 'tile[0]:XS1_PORT_1K', # 1b rxdv - 'tile[0]:XS1_PORT_1I', # 1b rxerr + rxd = 'tile[0]:XS1_PORT_4C' if "second_phy" in kwargs else 'tile[0]:XS1_PORT_4A' + rxdv = 'tile[0]:XS1_PORT_1O' if "second_phy" in kwargs else 'tile[0]:XS1_PORT_1K' + rxderr = 'tile[0]:XS1_PORT_1I' # Currently unused so assign the same + if "second_phy" in kwargs: kwargs.pop("second_phy") + + phy = RMiiTransmitter(rxd, # 4b rxd port + rxdv, # 1b rxdv + rxderr, # 1b rxerr clk, rxd_4b_port_pin_assignment=rxd_4b_port_pin_assignment, **kwargs @@ -360,28 +427,88 @@ def get_rmii_4b_port_tx_phy(clk, rxd_4b_port_pin_assignment, **kwargs): return phy def get_rmii_1b_port_tx_phy(clk, **kwargs): - phy = RMiiTransmitter(['tile[0]:XS1_PORT_1A', 'tile[0]:XS1_PORT_1B'], # 2, 1b rxd ports - 'tile[0]:XS1_PORT_1K', # 1b rxdv - 'tile[0]:XS1_PORT_1I', # 1b rxerr + rxd = ['tile[0]:XS1_PORT_1E', 'tile[0]:XS1_PORT_1F'] if "second_phy" in kwargs else ['tile[0]:XS1_PORT_1A', 'tile[0]:XS1_PORT_1B'] + rxdv = 'tile[0]:XS1_PORT_1O' if "second_phy" in kwargs else 'tile[0]:XS1_PORT_1K' + rxderr = 'tile[0]:XS1_PORT_1I' # Currently unused so assign the same + if "second_phy" in kwargs: kwargs.pop("second_phy") + + phy = RMiiTransmitter(rxd, # 2, 1b rxd ports + rxdv, # 1b rxdv + rxderr, # 1b rxerr clk, **kwargs ) return phy def get_rmii_4b_port_rx_phy(clk, txd_4b_port_pin_assignment, **kwargs): - phy = RMiiReceiver('tile[0]:XS1_PORT_4B', - 'tile[0]:XS1_PORT_1L', - clk, - txd_4b_port_pin_assignment=txd_4b_port_pin_assignment, - **kwargs - ) + txd = 'tile[0]:XS1_PORT_4D' if "second_phy" in kwargs else 'tile[0]:XS1_PORT_4B' + txen = 'tile[0]:XS1_PORT_1P' if "second_phy" in kwargs else 'tile[0]:XS1_PORT_1L' + if "second_phy" in kwargs: kwargs.pop("second_phy") + + phy = RMiiReceiver(txd, + txen, + clk, + txd_4b_port_pin_assignment=txd_4b_port_pin_assignment, + **kwargs + ) return phy def get_rmii_1b_port_rx_phy(clk, **kwargs): - phy = RMiiReceiver(['tile[0]:XS1_PORT_1C', 'tile[0]:XS1_PORT_1D'], - 'tile[0]:XS1_PORT_1L', - clk, - **kwargs - ) + txd = ['tile[0]:XS1_PORT_1H', 'tile[0]:XS1_PORT_1I'] if "second_phy" in kwargs else ['tile[0]:XS1_PORT_1C', 'tile[0]:XS1_PORT_1D'] + txen = 'tile[0]:XS1_PORT_1P' if "second_phy" in kwargs else 'tile[0]:XS1_PORT_1L' + if "second_phy" in kwargs: kwargs.pop("second_phy") + + phy = RMiiReceiver(txd, + txen, + clk, + **kwargs + ) return phy +def do_rx_test_dual(capfd, mac, arch, rx_clk, rx_phy, tx_clk, tx_phy, packets, test_file, seed, + extra_tasks=[], override_dut_dir=False, rx_width=None, tx_width=None): + + """ Shared test code for all RX tests using the test_rx application. + """ + testname,extension = os.path.splitext(os.path.basename(test_file)) + + with capfd.disabled(): + print(f"Running {testname}: {mac} {[phy.get_name() for phy in tx_phy]} phy, {arch}, rx_width {rx_width} arch at {tx_clk.get_name()} (seed = {seed})") + capfd.readouterr() # clear capfd buffer + + profile = f'{mac}_{tx_phy[0].get_name()}' + if rx_width: + profile = profile + f"_rx{rx_width}" + if tx_width: + profile = profile + f"_tx{tx_width}" + profile = profile + f"_{arch}" + + dut_dir = override_dut_dir if override_dut_dir else testname + binary = f'{dut_dir}/bin/{profile}/{dut_dir}_{profile}.xe' + assert os.path.isfile(binary), f"Missing .xe {binary}" + + + expect_folder = create_if_needed("expect_temp") + if rx_width: + expect_filename = f'{expect_folder}/{testname}_{mac}_{tx_phy[0].get_name()}_{rx_width}_{tx_width}_{tx_clk.get_name()}_{arch}.expect' + else: + expect_filename = f'{expect_folder}/{testname}_{mac}_{tx_phy[0].get_name()}_{tx_clk.get_name()}_{arch}.expect' + + create_expect(packets, expect_filename) + + tester = px.testers.ComparisonTester(open(expect_filename), ordered=False) + + simargs = get_sim_args(testname, mac, tx_clk, tx_phy[0], arch) + + st = [tx_clk, rx_phy[0], rx_phy[1], tx_phy[0], tx_phy[1]] + + + result = px.run_on_simulator_( binary, + simthreads=st + extra_tasks, + tester=tester, + simargs=simargs, + do_xe_prebuild=False, + capfd=capfd + ) + + assert result is True, f"{result}" diff --git a/tests/include/ports.h b/tests/include/ports.h index 29ba4d5c..f94381d4 100644 --- a/tests/include/ports.h +++ b/tests/include/ports.h @@ -24,10 +24,4 @@ clock eth_txclk = on tile[0]: XS1_CLKBLK_2; #endif // RGMII -port p_smi_mdio = on tile[0]: XS1_PORT_1M; -port p_smi_mdc = on tile[0]: XS1_PORT_1N; -port p_smi_mdc_mdio = on tile[0]: XS1_PORT_4B; -port p_phy_rst_n = on tile[0]: XS1_PORT_4A; - - #endif // __ports_h__ diff --git a/tests/include/ports_rmii.h b/tests/include/ports_rmii.h index 2a816645..b1b7f3e9 100644 --- a/tests/include/ports_rmii.h +++ b/tests/include/ports_rmii.h @@ -28,12 +28,15 @@ #if RX_USE_LOWER_2B rmii_data_port_t p_eth_rxd = {{on tile[0]:XS1_PORT_4A, USE_LOWER_2B}}; +rmii_data_port_t p_eth_rxd_2 = {{on tile[0]:XS1_PORT_4C, USE_LOWER_2B}}; #elif RX_USE_UPPER_2B rmii_data_port_t p_eth_rxd = {{on tile[0]:XS1_PORT_4A, USE_UPPER_2B}}; +rmii_data_port_t p_eth_rxd_2 = {{on tile[0]:XS1_PORT_4C, USE_UPPER_2B}}; #endif #elif RX_WIDTH == 1 rmii_data_port_t p_eth_rxd = {{on tile[0]:XS1_PORT_1A, XS1_PORT_1B}}; +rmii_data_port_t p_eth_rxd_2 = {{on tile[0]:XS1_PORT_1E, XS1_PORT_1F}}; #else #error invalid RX_WIDTH #endif @@ -50,22 +53,28 @@ rmii_data_port_t p_eth_rxd = {{on tile[0]:XS1_PORT_1A, XS1_PORT_1B}}; #if TX_USE_LOWER_2B rmii_data_port_t p_eth_txd = {{on tile[0]:XS1_PORT_4B, USE_LOWER_2B}}; + rmii_data_port_t p_eth_txd_2 = {{on tile[0]:XS1_PORT_4D, USE_LOWER_2B}}; #elif TX_USE_UPPER_2B rmii_data_port_t p_eth_txd = {{on tile[0]:XS1_PORT_4B, USE_UPPER_2B}}; + rmii_data_port_t p_eth_txd_2 = {{on tile[0]:XS1_PORT_4D, USE_UPPER_2B}}; #endif #elif TX_WIDTH == 1 rmii_data_port_t p_eth_txd = {{on tile[0]:XS1_PORT_1C, XS1_PORT_1D}}; +rmii_data_port_t p_eth_txd_2 = {{on tile[0]:XS1_PORT_1H, XS1_PORT_1I}}; #else #error invalid TX_WIDTH #endif port p_eth_clk = on tile[0]: XS1_PORT_1J; port p_eth_rxdv = on tile[0]: XS1_PORT_1K; +port p_eth_rxdv_2 = on tile[0]: XS1_PORT_1O; port p_eth_txen = on tile[0]: XS1_PORT_1L; +port p_eth_txen_2 = on tile[0]: XS1_PORT_1P; port p_test_ctrl = on tile[0]: XS1_PORT_1M; clock eth_rxclk = on tile[0]: XS1_CLKBLK_1; clock eth_txclk = on tile[0]: XS1_CLKBLK_2; - +clock eth_rxclk_2 = on tile[0]: XS1_CLKBLK_3; +clock eth_txclk_2 = on tile[0]: XS1_CLKBLK_4; #endif diff --git a/tests/mii_phy.py b/tests/mii_phy.py index 5c073314..a968b64e 100644 --- a/tests/mii_phy.py +++ b/tests/mii_phy.py @@ -139,7 +139,7 @@ def run(self): class RxPhy(px.SimThread): - def __init__(self, name, txd, txen, clock, print_packets, packet_fn, verbose, test_ctrl): + def __init__(self, name, txd, txen, clock, print_packets, packet_fn, verbose, test_ctrl, id): self._name = name self._txd = txd self._txen = txen @@ -148,6 +148,7 @@ def __init__(self, name, txd, txen, clock, print_packets, packet_fn, verbose, te self._verbose = verbose self._test_ctrl = test_ctrl self._packet_fn = packet_fn + self._id = id self.expected_packets = None self.expect_packet_index = 0 @@ -163,6 +164,9 @@ def get_name(self): def get_clock(self): return self._clock + def get_id(self): + return self._id + def set_expected_packets(self, packets): self.expect_packet_index = 0; self.expected_packets = packets @@ -174,9 +178,9 @@ def set_expected_packets(self, packets): class MiiReceiver(RxPhy): def __init__(self, txd, txen, clock, print_packets=False, - packet_fn=None, verbose=False, test_ctrl=None): + packet_fn=None, verbose=False, test_ctrl=None, id=None): super(MiiReceiver, self).__init__('mii', txd, txen, clock, print_packets, - packet_fn, verbose, test_ctrl) + packet_fn, verbose, test_ctrl, id) def run(self): xsi = self.xsi diff --git a/tests/rgmii_phy.py b/tests/rgmii_phy.py index fc810611..27b69f27 100644 --- a/tests/rgmii_phy.py +++ b/tests/rgmii_phy.py @@ -112,9 +112,9 @@ def run(self): class RgmiiReceiver(RxPhy): def __init__(self, txd, txen, clock, print_packets=False, - packet_fn=None, verbose=None, test_ctrl=None): + packet_fn=None, verbose=None, test_ctrl=None, id=None): super(RgmiiReceiver, self).__init__('rgmii', txd, txen, clock, print_packets, - packet_fn, verbose, test_ctrl) + packet_fn, verbose, test_ctrl, id) def run(self): xsi = self.xsi diff --git a/tests/rmii_phy.py b/tests/rmii_phy.py index 3339397c..8d128acc 100644 --- a/tests/rmii_phy.py +++ b/tests/rmii_phy.py @@ -20,7 +20,7 @@ def get_port_width_from_name(port_name): class RMiiTxPhy(px.SimThread): # Time in fs from the last packet being sent until the end of test is signalled to the DUT - END_OF_TEST_TIME = (10 * px.Xsi.get_xsi_tick_freq_hz())/1e6 # 10us + END_OF_TEST_TIME = (1000 * px.Xsi.get_xsi_tick_freq_hz())/1e6 # 1000us def __init__(self, name, rxd, rxdv, rxer, clock, rxd_4b_port_pin_assignment, @@ -90,7 +90,6 @@ def end_test(self): total_data_bits = total_packet_bytes * 8 - # Allow 2 cycles per bit timeout_time += 2 * total_data_bits * 1e6 # scale to femtoseconds vs nanoseconds in old xsim # The clock ticks are 2ns long @@ -99,6 +98,7 @@ def end_test(self): # The packets are copied to and from the user application timeout_time *= 2 + self.wait_until(self.xsi.get_time() + timeout_time) if self._test_ctrl: @@ -253,7 +253,7 @@ def run(self): class RMiiRxPhy(px.SimThread): - def __init__(self, name, txd, txen, clock, txd_4b_port_pin_assignment, print_packets, packet_fn, verbose, test_ctrl): + def __init__(self, name, txd, txen, clock, txd_4b_port_pin_assignment, print_packets, packet_fn, verbose, test_ctrl, id): self._name = name # Check if txd is a string or an array of strings if not isinstance(txd, (list, tuple)): @@ -267,6 +267,7 @@ def __init__(self, name, txd, txen, clock, txd_4b_port_pin_assignment, print_pac self._verbose = verbose self._test_ctrl = test_ctrl self._packet_fn = packet_fn + self._id = id self._txd_port_width = get_port_width_from_name(self._txd[0]) if len(self._txd) == 2: @@ -295,6 +296,9 @@ def get_name(self): def get_clock(self): return self._clock + def get_id(self): + return self._id + def set_expected_packets(self, packets): self.expect_packet_index = 0; self.expected_packets = packets @@ -309,11 +313,12 @@ class RMiiReceiver(RMiiRxPhy): def __init__(self, txd, txen, clock, txd_4b_port_pin_assignment="lower_2b", print_packets=False, - packet_fn=None, verbose=False, test_ctrl=None): + packet_fn=None, verbose=False, test_ctrl=None, id=None, sync_pipe=None): super(RMiiReceiver, self).__init__('rmii', txd, txen, clock, txd_4b_port_pin_assignment, print_packets, - packet_fn, verbose, test_ctrl) + packet_fn, verbose, test_ctrl, id) self._txen_val = None + self._sync_pipe = sync_pipe def run(self): rand = random.Random() diff --git a/tests/test_4_2_6.py b/tests/test_4_2_6.py index 46081b66..633132f4 100644 --- a/tests/test_4_2_6.py +++ b/tests/test_4_2_6.py @@ -38,7 +38,7 @@ def do_test(capfd, mac, arch, rx_clk, rx_phy, tx_clk, tx_phy, seed, rx_width=Non # Test shrinking the IFG by different amounts. Use the shrink as the step for debug purposes if tx_phy.get_name() == "rmii": - gap_shrink_list = [5] + gap_shrink_list = [3] else: gap_shrink_list = [5, 10] diff --git a/tests/test_avb_traffic.py b/tests/test_avb_traffic.py index 3008f5a7..b1f0db47 100644 --- a/tests/test_avb_traffic.py +++ b/tests/test_avb_traffic.py @@ -178,7 +178,7 @@ def do_test(capfd, mac, arch, tx_clk, tx_phy, seed, rand.seed(seed) bit_time = tx_phy.get_clock().get_bit_time() - rxLpControl = RxLpControl('tile[0]:XS1_PORT_1E', bit_time, 0, True, rand.randint(0, int(sys.maxsize))) + rxLpControl = RxLpControl('tile[0]:XS1_PORT_1G', bit_time, 0, True, rand.randint(0, int(sys.maxsize))) testname = 'test_avb_traffic' expect_folder = create_if_needed("expect_temp") diff --git a/tests/test_avb_traffic/src/main.xc b/tests/test_avb_traffic/src/main.xc index 9cfcd974..6f4f8362 100644 --- a/tests/test_avb_traffic/src/main.xc +++ b/tests/test_avb_traffic/src/main.xc @@ -17,7 +17,7 @@ port p_test_ctrl = on tile[0]: XS1_PORT_1C; #include "control.xc" -port p_rx_lp_control = on tile[0]: XS1_PORT_1E; +port p_rx_lp_control = on tile[0]: XS1_PORT_1G; #include "helpers.xc" diff --git a/tests/test_link_status/src/main.xc b/tests/test_link_status/src/main.xc index 154d1a26..0263d85e 100644 --- a/tests/test_link_status/src/main.xc +++ b/tests/test_link_status/src/main.xc @@ -50,11 +50,13 @@ void test_link_status(client ethernet_cfg_if cfg, size_t index = rx.get_index(); - cfg.enable_link_status_notification(index); + unsigned mac_index = 0; // This is the mac port index and not the client index + + cfg.enable_link_status_notification(mac_index); int events_expected = 4; while (events_expected) { - c <: index; + c <: mac_index; select { case rx.packet_ready(): diff --git a/tests/test_rmii_dual_basic.py b/tests/test_rmii_dual_basic.py new file mode 100644 index 00000000..2086dcd6 --- /dev/null +++ b/tests/test_rmii_dual_basic.py @@ -0,0 +1,90 @@ +# Copyright 2024-2025 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. + +import random +import Pyxsim as px +from pathlib import Path +import pytest +import sys, os + +from mii_packet import MiiPacket +from mii_clock import Clock +from helpers import packet_processing_time, get_dut_mac_address +from helpers import choose_small_frame_size, run_parametrised_test_rx, check_received_packet +from helpers import generate_tests +from helpers import get_rmii_clk, get_rmii_tx_phy_dual, get_rmii_rx_phy_dual +from rmii_phy import RMiiTransmitter, RMiiReceiver +from helpers import do_rx_test_dual + + +test_params_file = Path(__file__).parent / "test_rmii_dual_basic/test_params.json" +@pytest.mark.parametrize("params", generate_tests(test_params_file)[0], ids=generate_tests(test_params_file)[1]) +def test_rmii_dual_basic(capfd, seed, params): + with capfd.disabled(): + print(params) + + if seed == None: + seed = random.randint(0, sys.maxsize) + + rand = random.Random() + rand.seed(seed) + verbose = False + + # Instantiate clk and phys + clk = get_rmii_clk(Clock.CLK_50MHz) + tx_rmii_phy, tx_rmii_phy_2 = get_rmii_tx_phy_dual( + [params['rx_width'], params['rx_width']], + clk, + verbose=verbose, + expect_loopback=True + ) + + rx_rmii_phy, rx_rmii_phy_2 = get_rmii_rx_phy_dual( + [params['tx_width'], params['tx_width']], + clk, + packet_fn=check_received_packet, + verbose=verbose + ) + + mac, arch, rx_clk, rx_phy, tx_clk, tx_phy, rx_width, tx_width = params["mac"], params["arch"], None, [rx_rmii_phy, rx_rmii_phy_2], clk, [tx_rmii_phy, tx_rmii_phy_2], params['rx_width'],params['tx_width'] + + dut_mac_address = get_dut_mac_address() + not_dut_mac_address = [] + for i in range(6): + not_dut_mac_address.append(dut_mac_address[i]+1) + + num_test_packets = 30 + packets = [] + loopback_packets = [] + forwarded_packets = [] + + # Send frames which excercise all of the tail length vals (0, 1, 2, 3 bytes) + packet_start_len = 100 + # Packets that get looped back on the same port + for i in range(num_test_packets): + loopback_packets.append(MiiPacket(rand, + dst_mac_addr=dut_mac_address, + create_data_args=['step', (i, packet_start_len + i)], + inter_frame_gap=210*clk.get_bit_time() + )) + # packets that get forwarded to the other port + for i in range(num_test_packets): + forwarded_packets.append(MiiPacket(rand, + dst_mac_addr=not_dut_mac_address, + create_data_args=['step', (i, packet_start_len + i)], + inter_frame_gap=210*clk.get_bit_time() + )) + + # interleave loopback and forwarded packets + for i in range(num_test_packets): + packets.append(loopback_packets[i]) + packets.append(forwarded_packets[i]) + + tx_phy[1].set_packets(packets) # Send all packets to mac port 1 + rx_phy[1].set_expected_packets(loopback_packets) # Looped back packets show up on port 1 of the sim phy + rx_phy[0].set_expected_packets(forwarded_packets) # Forwarded packets show up on port 0 of the sim phy + + + do_rx_test_dual(capfd, mac, arch, rx_clk, rx_phy, tx_clk, tx_phy, [forwarded_packets, loopback_packets], __file__, seed, rx_width=rx_width, tx_width=tx_width) + + diff --git a/tests/test_rmii_dual_basic/CMakeLists.txt b/tests/test_rmii_dual_basic/CMakeLists.txt new file mode 100644 index 00000000..95eb915d --- /dev/null +++ b/tests/test_rmii_dual_basic/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.21) +include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake) +project(test_rmii_dual_basic) + +include(../helpers.cmake) +include(../test_deps.cmake) + +set(APP_PCA_ENABLE ON) + +file(GLOB_RECURSE SOURCES_XC RELATIVE ${CMAKE_CURRENT_LIST_DIR} "src/*.xc") +set(APP_XC_SRCS ${SOURCES_XC}) +set(APP_INCLUDES ../include src) + +set(COMPILER_FLAGS_COMMON -g + -report + -DDEBUG_PRINT_ENABLE=1 + -Os + -DNUM_ETHERNET_PORTS=2) + +set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) + + +file(READ ${CMAKE_CURRENT_LIST_DIR}/test_params.json JSON_CONTENT) +get_json_list(${JSON_CONTENT} PROFILES profile_list) + +set(done_configs "") +foreach(PROFILE ${profile_list}) + get_json_list(${PROFILE} arch arch_list) # Get archs to build for, for this particular profile + foreach(arch ${arch_list}) + string(JSON phy GET ${PROFILE} phy) + string(JSON mac GET ${PROFILE} mac) + + set(config "${mac}_${phy}") + string(FIND ${PROFILE} "rx_width" rx_width_found) + if(rx_width_found GREATER -1) + string(JSON rx_width GET ${PROFILE} rx_width) + set(config "${config}_rx${rx_width}") + endif() + string(FIND ${PROFILE} "tx_width" tx_width_found) + if(rx_width_found GREATER -1) + string(JSON tx_width GET ${PROFILE} tx_width) + set(config "${config}_tx${tx_width}") + endif() + set(config "${config}_${arch}") + + list (FIND done_configs ${config} _index) + if(${_index} EQUAL -1) # Only build if it is a new config + list(APPEND done_configs ${config}) + message(STATUS "Building cfg_name: ${config}") + + set(APP_HW_TARGET XCORE-AI-EXPLORER) + + set(APP_COMPILER_FLAGS_${config} ${COMPILER_FLAGS_COMMON}) + + set_app_rx_width(rx_width) + + set_app_tx_width(tx_width) + + string(FIND "${PROFILE}" "rt" position) + if(position GREATER -1) + list(APPEND APP_COMPILER_FLAGS_${config} -DRT=1) + else() + list(APPEND APP_COMPILER_FLAGS_${config} -DRT=0) + endif() + + string(FIND "${PROFILE}" "hp" position) + if(position GREATER -1) + list(APPEND APP_COMPILER_FLAGS_${config} -DETHERNET_SUPPORT_HP_QUEUES=1) + else() + list(APPEND APP_COMPILER_FLAGS_${config} -DETHERNET_SUPPORT_HP_QUEUES=0) + endif() + + if(${phy} MATCHES "rgmii") + list(APPEND APP_COMPILER_FLAGS_${config} -DRGMII=1) + elseif(${phy} MATCHES "rmii")# + list(APPEND APP_COMPILER_FLAGS_${config} -DRMII=1) + elseif(${phy} MATCHES "mii") + list(APPEND APP_COMPILER_FLAGS_${config} -DMII=1) + endif() + + XMOS_REGISTER_APP() + unset(APP_COMPILER_FLAGS_${config}) + endif() # if(${_index} equal -1) # New config + endforeach() # foreach(arch ${arch_list}) + unset(arch_list) +endforeach() # foreach(PROFILE ${profile_list}) diff --git a/tests/test_rmii_dual_basic/src/config.xscope b/tests/test_rmii_dual_basic/src/config.xscope new file mode 100644 index 00000000..5c4b0f67 --- /dev/null +++ b/tests/test_rmii_dual_basic/src/config.xscope @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/tests/test_rmii_dual_basic/src/main.xc b/tests/test_rmii_dual_basic/src/main.xc new file mode 100644 index 00000000..28943f57 --- /dev/null +++ b/tests/test_rmii_dual_basic/src/main.xc @@ -0,0 +1,179 @@ +// Copyright 2024-2025 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include +#include +#include +#include "ethernet.h" +#include "print.h" +#include "debug_print.h" +#include "syscall.h" + +#include "ports_rmii.h" +#include "helpers.xc" + +#if ETHERNET_SUPPORT_HP_QUEUES +typedef interface loopback_if { + [[notification]] slave void packet_ready(); + [[clears_notification]] void get_packet(unsigned &len, uintptr_t &buf); +} loopback_if; + +void test_loopback(streaming chanend c_tx_hp, + client loopback_if i_loopback) +{ + set_core_fast_mode_on(); + + unsafe { + while (1) { + unsigned len; + uintptr_t buf; + + select { + case i_loopback.packet_ready(): + i_loopback.get_packet(len, buf); + break; + } + ethernet_send_hp_packet(c_tx_hp, (char *)buf, len, 1); + } + } +} + +#define NUM_BUF 8 + +void test_rx(client ethernet_cfg_if cfg, + streaming chanend c_rx_hp, + server loopback_if i_loopback) +{ + set_core_fast_mode_on(); + + ethernet_macaddr_filter_t macaddr_filter; + + macaddr_filter.appdata = 0; + for (int i = 0; i < 6; i++) + macaddr_filter.addr[i] = i; + cfg.add_macaddr_filter(0, 1, macaddr_filter); + + // Add the broadcast MAC address + memset(macaddr_filter.addr, 0xff, 6); + cfg.add_macaddr_filter(0, 1, macaddr_filter); + + cfg.forward_packets_as_hp(1); // put the forwarding packets in hp queue. For testing only. In reality, client doesn't get to tell this to the Mac. + + unsigned char rxbuf[NUM_BUF][ETHERNET_MAX_PACKET_SIZE]; + unsigned rxlen[NUM_BUF]; + unsigned wr_index = 0; + unsigned rd_index = 0; + + int done = 0; + while (!done) { + ethernet_packet_info_t packet_info; + + #pragma ordered + select { + case ethernet_receive_hp_packet(c_rx_hp, rxbuf[wr_index], packet_info): + rxlen[wr_index] = packet_info.len; + wr_index = (wr_index + 1) % NUM_BUF; + if (wr_index == rd_index) { + debug_printf("test_rx ran out of buffers\n"); + _exit(1); + } + i_loopback.packet_ready(); + break; + + case i_loopback.get_packet(unsigned &len, uintptr_t &buf): { + len = rxlen[rd_index]; + buf = (uintptr_t)&rxbuf[rd_index]; + rd_index = (rd_index + 1) % NUM_BUF; + + if (rd_index != wr_index) + i_loopback.packet_ready(); + break; + } + } + } +} + +#else +void test_rx_loopback(client ethernet_cfg_if cfg, + client ethernet_rx_if rx, + client ethernet_tx_if tx) +{ + set_core_fast_mode_on(); + + ethernet_macaddr_filter_t macaddr_filter; + + size_t index = rx.get_index(); + + macaddr_filter.appdata = 0; + for (int i = 0; i < 6; i++){ + macaddr_filter.addr[i] = i; + } + cfg.add_macaddr_filter(index, 0, macaddr_filter); + + // Add the broadcast MAC address + memset(macaddr_filter.addr, 0xff, 6); + cfg.add_macaddr_filter(index, 0, macaddr_filter); + + int done = 0; + while (!done) { + select { + case rx.packet_ready(): + unsigned char rxbuf[ETHERNET_MAX_PACKET_SIZE]; + ethernet_packet_info_t packet_info; + rx.get_packet(packet_info, rxbuf, ETHERNET_MAX_PACKET_SIZE); + tx.send_packet(rxbuf, packet_info.len, 1); + break; + } + } +} +#endif + + +#define NUM_CFG_IF 1 +#define NUM_RX_LP_IF 1 +#define NUM_TX_LP_IF 1 + +int main() +{ + ethernet_cfg_if i_cfg[NUM_CFG_IF]; + ethernet_rx_if i_rx_lp[NUM_RX_LP_IF]; + ethernet_tx_if i_tx_lp[NUM_TX_LP_IF]; + +#if ETHERNET_SUPPORT_HP_QUEUES + loopback_if i_loopback; + streaming chan c_rx_hp; + streaming chan c_tx_hp; +#else + #define c_rx_hp null + #define c_tx_hp null +#endif + + + + par { + + unsafe{rmii_ethernet_rt_mac_dual(i_cfg, NUM_CFG_IF, + i_rx_lp, NUM_RX_LP_IF, + i_tx_lp, NUM_TX_LP_IF, + c_rx_hp, c_tx_hp, + p_eth_clk, + &p_eth_rxd, p_eth_rxdv, + p_eth_txen, &p_eth_txd, + eth_rxclk, eth_txclk, + &p_eth_rxd_2, p_eth_rxdv_2, + p_eth_txen_2, &p_eth_txd_2, + eth_rxclk_2, eth_txclk_2, + 4000, 4000, ETHERNET_ENABLE_SHAPER);} + +#if ETHERNET_SUPPORT_HP_QUEUES + test_rx(i_cfg[0], c_rx_hp, i_loopback); + test_loopback(c_tx_hp, i_loopback); +#else + filler(0x2222); + test_rx_loopback(i_cfg[0], i_rx_lp[0], i_tx_lp[0]); +#endif + + } + return 0; +} + diff --git a/tests/test_rmii_dual_basic/test_params.json b/tests/test_rmii_dual_basic/test_params.json new file mode 100644 index 00000000..5afd4534 --- /dev/null +++ b/tests/test_rmii_dual_basic/test_params.json @@ -0,0 +1,6 @@ +{ + "PROFILES": [ + {"phy":"rmii", "mac":"rt", "arch":["xs3"], "rx_width":"4b_lower", "tx_width":"4b_lower"}, + {"phy":"rmii", "mac":"rt_hp", "arch":["xs3"], "rx_width":"4b_lower", "tx_width":"4b_lower"} + ] +} diff --git a/tests/test_rmii_dual_fwd_only.py b/tests/test_rmii_dual_fwd_only.py new file mode 100644 index 00000000..4c516542 --- /dev/null +++ b/tests/test_rmii_dual_fwd_only.py @@ -0,0 +1,103 @@ +# Copyright 2024-2025 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. + +""" +DUT receives packets on both ports. +None of the packets received by the DUT are meant for the client running on the DUT, so +they get forwarded on the other port. +So, the sim phy port 0, receives packets that were sent to dut mac port 1 and vice versa +""" + +import random +import Pyxsim as px +from pathlib import Path +import pytest +import sys, os +import numpy as np + +from mii_packet import MiiPacket +from mii_clock import Clock +from helpers import packet_processing_time, get_dut_mac_address +from helpers import choose_small_frame_size, run_parametrised_test_rx, check_received_packet +from helpers import generate_tests, create_if_needed, create_expect, get_sim_args +from helpers import get_rmii_clk, get_rmii_tx_phy_dual, get_rmii_rx_phy_dual +from rmii_phy import RMiiTransmitter, RMiiReceiver +from helpers import do_rx_test_dual + + +def rmii_dual_fwd_test(capfd, params, seed): + rand = random.Random() + rand.seed(seed) + verbose = False + + # Instantiate clk and phys + clk = get_rmii_clk(Clock.CLK_50MHz) + tx_rmii_phy, tx_rmii_phy_2 = get_rmii_tx_phy_dual( + [params['rx_width'], params['rx_width']], + clk, + verbose=verbose + ) + + rx_rmii_phy, rx_rmii_phy_2 = get_rmii_rx_phy_dual( + [params['tx_width'], params['tx_width']], + clk, + packet_fn=check_received_packet, + verbose=verbose + ) + + + mac, arch, rx_clk, rx_phy, tx_clk, tx_phy, rx_width, tx_width = params["mac"], params["arch"], None, [rx_rmii_phy, rx_rmii_phy_2], clk, [tx_rmii_phy, tx_rmii_phy_2], params['rx_width'],params['tx_width'] + + + + dut_mac_address = get_dut_mac_address() # Mac address for which the client running on the DUT will register to receive packets + + # non dut mac address, packets destined for which get forwarded on the other port + not_dut_mac_address_0 = [] # Mac address which is different from the one for which the client running on the DUT has registered to receive packets + not_dut_mac_address_1 = [] # Mac address which is different from the one for which the client running on the DUT has registered to receive packets + for i in range(6): + not_dut_mac_address_0.append(dut_mac_address[i]+1) + not_dut_mac_address_1.append(dut_mac_address[i]+2) + + num_test_packets = 50 + + packets_mac_0 = [] # Packets arriving on mac rx port 0. These get forwarded to tx port 1 + packets_mac_1 = [] # Packets arriving on mac rx port 1. These get forwarded to tx port 0 + + + # Send frames which excercise all of the tail length vals (0, 1, 2, 3 bytes) + packet_start_len = 100 + ifg = tx_clk.get_min_ifg() + + for i in range(num_test_packets): + packets_mac_0.append(MiiPacket(rand, + dst_mac_addr=not_dut_mac_address_0, + create_data_args=['step', (i, packet_start_len + i)], + inter_frame_gap=ifg + )) + packets_mac_1.append(MiiPacket(rand, + dst_mac_addr=not_dut_mac_address_1, + create_data_args=['step', (2*i, packet_start_len + 2*i)], + inter_frame_gap=ifg + )) + + tx_phy[0].set_packets(packets_mac_0) + tx_phy[1].set_packets(packets_mac_1) + + rx_phy[0].set_expected_packets(packets_mac_1) + rx_phy[1].set_expected_packets(packets_mac_0) + + do_rx_test_dual(capfd, mac, arch, rx_clk, rx_phy, tx_clk, tx_phy, [packets_mac_0, packets_mac_1], __file__, seed, rx_width=rx_width, tx_width=tx_width, override_dut_dir="test_rmii_dual_basic") + + + +test_params_file = Path(__file__).parent / "test_rmii_dual_basic/test_params.json" +@pytest.mark.parametrize("params", generate_tests(test_params_file)[0], ids=generate_tests(test_params_file)[1]) +def test_rmii_dual_fwd_only(capfd, seed, params): + with capfd.disabled(): + print(params) + + if seed == None: + seed = random.randint(0, sys.maxsize) + + rmii_dual_fwd_test(capfd, params, seed) diff --git a/tests/test_rmii_restart.py b/tests/test_rmii_restart.py index 6664e53d..09a4128e 100644 --- a/tests/test_rmii_restart.py +++ b/tests/test_rmii_restart.py @@ -50,7 +50,7 @@ def do_test(capfd, mac, arch, rx_clk, rx_phy, tx_clk, tx_phy, seed, rx_width=Non if cycle == 0: ifg = 2000 * tx_clk.get_bit_time() # Wait for MAC to restart a few times else: - ifg = 7000 * tx_clk.get_bit_time() # Wait for forwarding completion and a restart + ifg = 9000 * tx_clk.get_bit_time() # Wait for forwarding completion and a restart else: ifg = 96 * tx_clk.get_bit_time() # Min eth spec IFG between packets packets.append(MiiPacket(rand, diff --git a/tests/test_rx_queues.py b/tests/test_rx_queues.py index 64051e4e..2f61e978 100644 --- a/tests/test_rx_queues.py +++ b/tests/test_rx_queues.py @@ -122,8 +122,8 @@ def do_test(capfd, mac, arch, tx_clk, tx_phy, seed, test_id, rand.seed(seed) bit_time = tx_phy.get_clock().get_bit_time() - rxLpControl1 = RxLpControl('tile[0]:XS1_PORT_1E', bit_time, 0, True, rand.randint(0, sys.maxsize)) - rxLpControl2 = RxLpControl('tile[0]:XS1_PORT_1F', bit_time, 0, True, rand.randint(0, sys.maxsize)) + rxLpControl1 = RxLpControl('tile[0]:XS1_PORT_1G', bit_time, 0, True, rand.randint(0, sys.maxsize)) + rxLpControl2 = RxLpControl('tile[0]:XS1_PORT_1N', bit_time, 0, True, rand.randint(0, sys.maxsize)) testname = 'test_rx_queues' expect_folder = create_if_needed("expect_temp") diff --git a/tests/test_rx_queues/src/main.xc b/tests/test_rx_queues/src/main.xc index 035162f4..b8dacfd0 100644 --- a/tests/test_rx_queues/src/main.xc +++ b/tests/test_rx_queues/src/main.xc @@ -22,7 +22,7 @@ port p_test_ctrl = on tile[0]: XS1_PORT_1C; #define NUM_TX_LP_IF 1 #define NUM_LP_CLIENTS 2 -port p_rx_lp_control[NUM_LP_CLIENTS] = on tile[0]: { XS1_PORT_1E, XS1_PORT_1F }; +port p_rx_lp_control[NUM_LP_CLIENTS] = on tile[0]: { XS1_PORT_1G, XS1_PORT_1N }; #include "helpers.xc" diff --git a/tests/test_smi/src/main.xc b/tests/test_smi/src/main.xc index 0da81b46..fdb94abf 100644 --- a/tests/test_smi/src/main.xc +++ b/tests/test_smi/src/main.xc @@ -11,6 +11,13 @@ #include "ports.h" +// Adding these here instead of ports.h since they conflict with +// test ports (XS1_PORT_1N is the same as p_rx_lp_control[1] used in test_rx_queues and test_avb). +// These are smi testing specific so okay to not include in the common includes file +port p_smi_mdio = on tile[0]: XS1_PORT_1M; +port p_smi_mdc = on tile[0]: XS1_PORT_1N; +port p_smi_mdc_mdio = on tile[0]: XS1_PORT_4B; +port p_phy_rst_n = on tile[0]: XS1_PORT_4A; #define SMI_SINGLE_PORT_MDC_BIT 0 #define SMI_SINGLE_PORT_MDIO_BIT 1