;******************************************************************************
;+--------------------------------------------------------------------------+**
;|                            ****                                          |**
;|                            ****                                          |**
;|                            ******o***                                    |**
;|                      ********_;/_****                                   |**
;|                      ***** /_;_/ ****                                   |**
;|                       ** ** (__/ ****                                    |**
;|                           *********                                      |**
;|                            ****                                          |**
;|                            ***                                           |**
;|                                                                          |**
;|         Copyright (c) 1998-2012 Texas Instruments Incorporated           |**
;|                        ALL RIGHTS RESERVED                               |**
;|                                                                          |**
;| Permission is hereby granted to licensees of Texas Instruments           |**
;| Incorporated (TI) products to use this computer program for the sole     |**
;| purpose of implementing a licensee product based on TI products.         |**
;| No other rights to reproduce, use, or disseminate this computer          |**
;| program, whether in part or in whole, are granted.                       |**
;|                                                                          |**
;| TI makes no representation or warranties with respect to the             |**
;| performance of this computer program, and specifically disclaims         |**
;| any responsibility for any damages, special or consequential,            |**
;| connected with the use of this program.                                  |**
;|                                                                          |**
;+--------------------------------------------------------------------------+**
;*****************************************************************************/
; file:   emac_MII_Rcv.p
;
; brief:  Receive Task
;
;
;  (C) Copyright 2012, Texas Instruments, Inc
;
;	Version		Description						Author
;
; 	0.1     	Created							Thomas Mauer
;	0.2		Updated for Common Baseline				Anjandeep Sahni
	
	.if !$isdefed("__mii_rcv_p")	
__mii_rcv_p	.set	1	
	
;;///////////////////////////////////////////////////////
; Includes Section
;;///////////////////////////////////////////////////////
	.include "emac_MII_Rcv.h"
	.include "icss_macros.h"
;	.include "icss_regs.h"
	.include "micro_scheduler.h"
	.include "emac_MII_Xmt.h"
	.include "icss_miirt_regs.h"


        .global  FN_RCV_FB
        .global  FN_RCV_NB
        .global  FN_RCV_LB
        .global  XMT_QUEUE
        .global  TASK_EXECUTION_FINISHED


	
;****************************************************************************
;
;     NAME		: FN_RCV_FB
;     DESCRIPTION	: receives the first block of data from new frame (out of RX L2)
;     RETURNS		: 
;     ARGS		: 
;     USES 		: 
;     INVOKES 		: 
;
;****************************************************************************
FN_RCV_FB:
	; Data is already present in the registers. So, no need to read it again.
	
	ZERO	&MII_RCV, $sizeof(MII_RCV)	; init MII_RCV parameter
	; OPT: Possible to make them both context next to each other
	; Check if RX port is enabled (information provided by host)
	LDI	R10.w0 , PORT_CONTROL_ADDR
	LBCO	&R10, PRU_DMEM_ADDR, R10.w0, 10	; 4 + 6 bytes of Interface MAC Addr
	
	; OPT: Port can be disabled directly in the MII Hardware
	; Is port enabled?
	QBBC	EXIT_FB, R10, 0	 ;replaced: QBBC	EXIT_FB, R10.t0 
	
	
CONTINUE_PROCESSING:
	; set global flag to indicate an ongoing reception
	SET	R23 , R23 , 1 
	
;*********************************Check for Errors*****************************************
;******************************************************************************************	
;check for SFD Errors    
	.if $isdefed("HALF_DUPLEX_ENABLED")	
; below code not needed for Full Duple
	.if $isdefed("PRU0")	
	LBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1	
	QBBC	CHECK_FOR_SHORT_SFD, RCV_TEMP_REG_3, 1	 ;replaced: QBBC    CHECK_FOR_SHORT_SFD, RCV_TEMP_REG_3.t1 
	;clear error and writeback
	SET	RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1 
	SBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1	
	QBA     COUNT_SFD_ERROR
CHECK_FOR_SHORT_SFD:            
	QBBC	CONTINUE_PROCESSING_PKT, RCV_TEMP_REG_3, 0	 ;replaced: QBBC    CONTINUE_PROCESSING_PKT, RCV_TEMP_REG_3.t0 
	;clear error and writeback
	SET	RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0 
	SBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1	
	QBA     COUNT_SFD_ERROR
	.else
	LBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1	
	QBBC	CHECK_FOR_SHORT_SFD, RCV_TEMP_REG_3, 1	 ;replaced: QBBC    CHECK_FOR_SHORT_SFD, RCV_TEMP_REG_3.t1 
	;clear error and writeback
	SET	RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1 
	SBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1	
	QBA     COUNT_SFD_ERROR
CHECK_FOR_SHORT_SFD:            
	QBBC	CONTINUE_PROCESSING_PKT, RCV_TEMP_REG_3, 0	 ;replaced: QBBC    CONTINUE_PROCESSING_PKT, RCV_TEMP_REG_3.t0 
	;clear error and writeback
	SET	RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0 
	SBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1	
	QBA     COUNT_SFD_ERROR
	.endif
	
	;check R31 error
	QBBC	CONTINUE_PROCESSING_PKT, R31, 19	 ;replaced: QBBC	CONTINUE_PROCESSING_PKT, R31.D_RX_ERROR_FLAG_BITNUM 
	;clear the error
	M_CMD16 D_RX_ERROR_CLEAR
	
	;set error flag
	LDI	RCV_TEMP_REG_3 , RX_ERROR_OFFSET
	QBA     COUNT_RX_STATS
	; Check if SA matches with Slave's Interface MAC addr
	.endif  ;HALF_DUPLEX_ENABLED
CONTINUE_PROCESSING_PKT:
	
	QBNE	FB_SA_NO_MATCH_INTERFACE_MAC, Ethernet.SrcAddr_01, R11.w0	;Check if Source Address matches with own address
	QBNE	FB_SA_NO_MATCH_INTERFACE_MAC, Ethernet.SrcAddr_23, R11.w2	
	QBNE	FB_SA_NO_MATCH_INTERFACE_MAC, Ethernet.SrcAddr_45, R12.w0	
	LDI	RCV_TEMP_REG_3 , RX_DROPPED_FRAMES_OFFSET
	QBA     COUNT_RX_STATS
	;QBA     EXIT_FB
	.if $isdefed("HALF_DUPLEX_ENABLED")	
COUNT_SFD_ERROR:
	LDI	RCV_TEMP_REG_3 , SFD_ERROR_OFFSET
	.endif	;HALF_DUPLEX_ENABLED
	
COUNT_RX_STATS:
;count statistics
	LBCO	&RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	ADD	RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1	
	SBCO	&RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
EXIT_FB:
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 4 
	QBA	FB_DONE
	
FB_SA_NO_MATCH_INTERFACE_MAC:
	; check for multi-cast
	QBBS	FB_MULTI_OR_BROADCAST, EthByte.DstByte_0, 0	 ;replaced: QBBS	FB_MULTI_OR_BROADCAST, EthByte.DstByte_0.multicast 
	
;*********************************
; uni-cast handling
;*********************************
FB_UNICAST:
	
FB_UNICAST_SA_NO_MATCH:
	
	; check if DA matches with our Interface MAC address
	QBNE	FB_UNICAST_DA_NO_MATCH, Ethernet.DstAddr_0123, R11	;Check if Destination Address matches with own address
	QBNE	FB_UNICAST_DA_NO_MATCH, Ethernet.DstAddr_45, R12.w0	
	
	; the frame DST address matches with our own address
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 0 ; set flag that host queue will receive data
	QBA     FB_LT_VT_2
	
FB_UNICAST_DA_NO_MATCH:
	LDI	RCV_TEMP_REG_3 , RX_DROPPED_FRAMES_OFFSET
	QBA     COUNT_RX_STATS
;*********************************
; multicast/broadcast handling
;*********************************
FB_MULTI_OR_BROADCAST:		; detected a multi-cast or broadcast frame
	
;Do storm prevention here
	LDI	RCV_TEMP_REG_3 , STORM_PREVENTION_OFFSET
	LBCO	&RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	QBBC	FB_CONTINUE, RCV_TEMP_REG_2, 0	 ;replaced: QBBC    FB_CONTINUE, RCV_TEMP_REG_2.t0 
	LSR	RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8	
	QBGT	FB_DISCARD, RCV_TEMP_REG_2.w0, 1	
	SUB	RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1	
	LSL	RCV_TEMP_REG_2, RCV_TEMP_REG_2, 8	
	SET	RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 0 
	SBCO	&RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	JMP     FB_CONTINUE
	
FB_DISCARD:
;discard packet transmission if the credits for broadcast expire and update the statistic for the same
	
	LDI	RCV_TEMP_REG_3 , STORM_PREVENTION_COUNTER
	QBA	COUNT_RX_STATS
	
FB_CONTINUE:
	FILL	&RCV_TEMP_REG_1, 4   ; Fill with 0xffffffff
	QBNE	FB_MULTICAST, Ethernet.DstAddr_0123, RCV_TEMP_REG_1	; compare if Dest_addr_0123 match with boardcast
	QBNE	FB_MULTICAST, Ethernet.DstAddr_45, RCV_TEMP_REG_1.w0	
	
FB_BROADCAST:
	SET	R22 , R22 , 28 
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 0 
	QBA	FB_BROADCAST_CHECK_CT
	
FB_MULTICAST:
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 0 
	SET	R22 , R22 , 27 
	
FB_MULTICAST_CONTINUE:
FB_UNICAST_CHECK_CT:
FB_BROADCAST_CHECK_CT:
	
FB_LT_VT_2: ; Quality of service --> select RX queue priority based on Ethernet frame tags
	
	XIN	RX_L2_BANK0_ID, &R18, RANGE_R18_b0	
	XIN	RX_L2_BANK0_ID, &R2, RANGE_R2_R13	; XIN RX L2 bank 0    
	
	.if $isdefed("PRU0")	
; The naming of the QoS queue goes from 1..4, but we need to count from 0..3
	LDI	MII_RCV.qos_queue, 2-1	; default (lowest priority) queue is 2 for PRU0	
	.else
	LDI	MII_RCV.qos_queue, 4-1	; default (lowest priority) queue is 4	for PRU1
	.endif
	
FB_QOS_APPLY_RULES:
	LDI	RCV_TEMP_REG_1.w0, 0x0081	; 0x8100 --> indicates QOS tagged frame
	QBNE	FB_QOS_DONE, Ethernet.TPID, RCV_TEMP_REG_1.w0
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	LSR	RCV_TEMP_REG_1.b0, Ethernet.TCI, 5	; extract PCP info
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.if $isdefed("PRU0")	
	QBGT	FB_QOS_DONE, RCV_TEMP_REG_1.b0, 4	; PCP == 7/6
	LDI	MII_RCV.qos_queue, 1-1	; highest priority is 1, select queue 1
	.else
	QBGT	FB_QOS_DONE, RCV_TEMP_REG_1.b0, 4	; PCP == 7/6
	LDI	MII_RCV.qos_queue, 3-1	; highest priority is 3, select queue 3
	.endif
	QBA		FB_QOS_DONE
	
; if PCP == 1/0, this priority 4, default queue already selected
FB_QOS_DONE:
FB_DONE:
	
; Fill the rcv context with host/port queue base pointer, rd_ptr and wrk_pointer
	QBNE	FB_CHECK_QUEUE_2, MII_RCV.qos_queue,  0
	LDI	RX_CONTEXT_OFFSET , HOST_Q1_RX_CONTEXT_OFFSET
	QBA	Initialize_rcv_context
	
	;end_buffer_desc_offset
FB_CHECK_QUEUE_2:
	QBNE	FB_CHECK_QUEUE_3, MII_RCV.qos_queue,  1
	LDI	RX_CONTEXT_OFFSET , HOST_Q2_RX_CONTEXT_OFFSET
	QBA	Initialize_rcv_context
	
FB_CHECK_QUEUE_3:
	QBNE	FB_CHECK_QUEUE_4, MII_RCV.qos_queue,  2
	LDI	RX_CONTEXT_OFFSET , HOST_Q3_RX_CONTEXT_OFFSET
	QBA	Initialize_rcv_context
	
FB_CHECK_QUEUE_4:
	LDI	RX_CONTEXT_OFFSET , HOST_Q4_RX_CONTEXT_OFFSET
	
Initialize_rcv_context:
	QBBC	FB_FILL_RCV_CONTEXT_PORT_QUEUE, MII_RCV.rx_flags, 0	 ;replaced: QBBC	FB_FILL_RCV_CONTEXT_PORT_QUEUE, MII_RCV.rx_flags.host_rcv_flag 
	; Read the RX Context of Host Port of 8 bytes
	LBCO	&MII_RCV.base_buffer_index, ICSS_SHARED_CONST, RX_CONTEXT_OFFSET, 8	
	
FB_FILL_RCV_CONTEXT_PORT_QUEUE:
	; OPT: If R0.b0 is not changed then remove below instruction
	LDI	R0.b0, SHIFT_NONE	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_RCV, $sizeof(MII_RCV)	; store task parameters in parameter bank
	.else
	XOUT	BANK2, &MII_RCV, $sizeof(MII_RCV)	; store task parameters in parameter bank
	.endif
	
	;The following check is required in case of firmware lag
	;when the firmware runs late compared to RX L2 FIFO.
	;This was being experienced in Profinet Switch and the same is possible here.
	;Haven't been able to reproduce this in EMAC.
	XIN	RX_L2_BANK0_ID, &R18, RANGE_R18_b0	
	QBGT	FB_RCV_EXIT, R18.b0, 32	
	LDI	CURRENT_TASK_POINTER, TX_TASK_POINTER	
	JMP	FN_RCV_NB
	
FB_RCV_EXIT:
	JMP	CALL_REG	
	
	
;****************************************************************************
;
;     NAME		: FN_RCV_NB
;     DESCRIPTION	: receives the next 32Byte block of RX L2
;     RETURNS		: 
;     ARGS		: 
;     USES 		: 
;     INVOKES 		: 
;
;****************************************************************************
FN_RCV_NB:
	
	; for XIN, make sure that shift is set to 0
	LDI	R0.b0, SHIFT_NONE	
	; restore task parameters in parameter bank
	.if $isdefed("PRU0")	
	XIN	BANK1, &MII_RCV, $sizeof(MII_RCV)	
	.else
	XIN	BANK2, &MII_RCV, $sizeof(MII_RCV)	
	.endif
	; this task is getting called by MS, first check is to see if we are currently receiving
	QBBC	NB_DONE_NO_PARAM_STORE, R23, 1	 ;replaced: QBBC	NB_DONE_NO_PARAM_STORE, Rcv_active 
	QBBS	NB_DONE_NO_PARAM_STORE, MII_RCV.rx_flags, 4	 ;replaced: QBBS	NB_DONE_NO_PARAM_STORE, MII_RCV.rx_flags.rx_frame_error 
	
	; depending on the bank index, we load bank 0 or bank 1
	QBBS	NB_XIN_UPPER_BANK, MII_RCV.rx_flags, 3	 ;replaced: QBBS	NB_XIN_UPPER_BANK, MII_RCV.rx_flags.rx_bank_index 
	
NB_XIN_LOWER_BANK:
	; OPT: Just one XIN is needed
	XIN	RX_L2_BANK0_ID, &R18, RANGE_R18_b0	
	XIN	RX_L2_BANK0_ID, &R2, RANGE_R2_R13	; XIN RX L2 bank 0
	QBA	NB_CHECK_AMOUNT_OF_BYTES
NB_XIN_UPPER_BANK:
	; OPT: Just one XIN is needed
	XIN	RX_L2_BANK1_ID, &R18, RANGE_R18_b0	
	XIN	RX_L2_BANK1_ID, &R2, RANGE_R2_R13	; XIN RX L2 bank 0
	
NB_CHECK_AMOUNT_OF_BYTES:
	QBBS	NB_CHECK_AMOUNT_OF_BYTES_BIGGER_32_BANK1, MII_RCV.rx_flags, 3	 ;replaced: QBBS	NB_CHECK_AMOUNT_OF_BYTES_BIGGER_32_BANK1, MII_RCV.rx_flags.rx_bank_index 
	
	; for bank 0, R18.b0 >=32 bytes
	QBGT	NB_DONE, R18_RCV_BYTECOUNT, 32	
	;LDI	R1.b3, buffer_ptr
	QBA	NB_PROCESS_32BYTES
	
NB_CHECK_AMOUNT_OF_BYTES_BIGGER_32_BANK1:
	
	; for bank 1, R18.b0 <32 bytes
	QBLE	NB_DONE, R18_RCV_BYTECOUNT, 32	
	LDI	PREVIOUS_R18_RCV_BYTECOUNT, 0x00	
	
;***********************************
; 32 bytes handling, no cut through
;***********************************
NB_PROCESS_32BYTES:	; 32 Bytes of new data are in the buffer
	
	LDI	R1.b3, buffer_ptr	
	
NB_PROCESS_CHECK_BYTE_CNTR:
	; if this is the first 32 bytes of data, need to init the buffer queues
	QBNE	NB_PROCESS_32BYTES_CHECK_FLAGS, MII_RCV.byte_cntr, 0
	
	;Initialize the wrkng_wr_ptr and rd_ptr here as the other PRU might have changed them between Now and RCV_FB
	LBCO	&RCV_QUEUE_DESC_REG, QUEUE_DESP_BASE, MII_RCV.rcv_queue_pointer, 4	
	AND MII_RCV.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr , RCV_QUEUE_DESC_REG.rd_ptr	;Warning: converted from MOV
	AND MII_RCV.wrkng_wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr , RCV_QUEUE_DESC_REG.wr_ptr	;Warning: converted from MOV
	; Compute the adress in L3 RAM where the packet is received
	SUB	RCV_BUFFER_DESC_OFFSET, MII_RCV.wrkng_wr_ptr, MII_RCV.base_buffer_desc_offset	
	LSL	RCV_BUFFER_DESC_OFFSET, RCV_BUFFER_DESC_OFFSET, 3	
	ADD	MII_RCV.buffer_index, MII_RCV.base_buffer_index, RCV_BUFFER_DESC_OFFSET	
	
NB_PROCESS_32BYTES_CHECK_FLAGS:
	
	SBCO	&Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, 32	
	ADD	MII_RCV.byte_cntr , MII_RCV.byte_cntr ,  32
	
	; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
	QBNE	RCV_NB_NO_QUEUE_WRAP, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
	AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset	;Warning: converted from MOV
	AND MII_RCV.buffer_index , MII_RCV.base_buffer_index , MII_RCV.base_buffer_index	;Warning: converted from MOV
	QBA	RCV_NB_QUEUE_WRAPPED
RCV_NB_NO_QUEUE_WRAP:
	ADD	MII_RCV.buffer_index, MII_RCV.buffer_index,  32
	ADD	MII_RCV.wrkng_wr_ptr,  MII_RCV.wrkng_wr_ptr,  4
	
RCV_NB_QUEUE_WRAPPED:
	
	; Prepare for next call of RCV_NB ..whether next 32 bytes can be received or not
	QBNE	NB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
	
	CLR	MII_RCV.rx_flags , MII_RCV.rx_flags , 0 
	SET	MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , 6 
	;For EMAC mode, set rx_frame_error bit. This saves cycles in FN_RCV_LB.
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 4 
	
NB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL:
	
	XOR		MII_RCV.rx_flags, MII_RCV.rx_flags, (1<<rx_bank_index_shift)	; toggle rx_bank_index flag
	
NB_DONE:
	
	; restore call register pointer
	AND CALL_REG , L1_CALL_REG , L1_CALL_REG
	
	; store task parameters from parameter bank
NB_STORE_CONTEXT:
	LDI	R0.b0, SHIFT_NONE	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_RCV, $sizeof(MII_RCV)	
	.else
	XOUT	BANK2, &MII_RCV, $sizeof(MII_RCV)	
	.endif
	
	.if $isdefed("SOC_AM335x")	
	M_RCV_RX_EOF_CHECK_AM335x
	.endif
	.if $isdefed("SOC_AM571x")	
	M_RCV_RX_EOF_CHECK_AM571x
	.endif
	
NB_DONE_NO_PARAM_STORE:
	JMP		TASK_EXECUTION_FINISHED
	
process_rx_eof_rx_nb:
	JMP		FN_RCV_LB
	
;****************************************************************************
;
;     NAME			: FN_RCV_LB
;     DESCRIPTION	: receives the last block(s) of RX L2
;     RETURNS		: 
;     ARGS			: 
;     USES 		: 
;     INVOKES 		: 
;
;****************************************************************************
FN_RCV_LB:
	
	; Check if RCV_Active is set. If not drop the frame. It handles the case of undersize errors
	QBBS	RCV_LB_PROCESS_NORMAL, R23, 1	 ;replaced: QBBS	RCV_LB_PROCESS_NORMAL, Rcv_active 
	
LB_CHECK_ERRORS:
	;Short frame received
	LDI	RCV_TEMP_REG_3 , RX_ERROR_OFFSET
	LBCO	&RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	ADD	RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1	
	SBCO	&RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	;check R31 error
	QBBC	NO_R31_ERROR, R31, 19	 ;replaced: QBBC	NO_R31_ERROR, R31.D_RX_ERROR_FLAG_BITNUM 
	;else clear the error
	M_CMD16 D_RX_ERROR_CLEAR
	
NO_R31_ERROR:
	;check for SFD Errors
	.if $isdefed("PRU0")	
	LBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1	
	QBBC	CHECK_FOR_SHORT_SFD1, RCV_TEMP_REG_3, 1	 ;replaced: QBBC    CHECK_FOR_SHORT_SFD1, RCV_TEMP_REG_3.t1 
	;clear error and writeback
	SET	RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1 
	SBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1	
	QBA     COUNT_SFD_ERROR1
CHECK_FOR_SHORT_SFD1:            
	QBBC	NO_PREAMBLE_ERROR, RCV_TEMP_REG_3, 0	 ;replaced: QBBC     NO_PREAMBLE_ERROR, RCV_TEMP_REG_3.t0 
	;clear error and writeback
	SET	RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0 
	SBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1	
	.else
	LBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1	
	QBBC	CHECK_FOR_SHORT_SFD1, RCV_TEMP_REG_3, 1	 ;replaced: QBBC     CHECK_FOR_SHORT_SFD1, RCV_TEMP_REG_3.t1 
	;clear error and writeback
	SET	RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 1 
	SBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1	
	QBA     COUNT_SFD_ERROR1
CHECK_FOR_SHORT_SFD1:            
	QBBC	NO_PREAMBLE_ERROR, RCV_TEMP_REG_3, 0	 ;replaced: QBBC    NO_PREAMBLE_ERROR, RCV_TEMP_REG_3.t0 
	;clear error and writeback
	SET	RCV_TEMP_REG_3 , RCV_TEMP_REG_3 , 0 
	SBCO	&RCV_TEMP_REG_3.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1	
	.endif
	
COUNT_SFD_ERROR1:
	LDI	RCV_TEMP_REG_3 , SFD_ERROR_OFFSET
	LBCO	&RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	ADD	RCV_TEMP_REG_2, RCV_TEMP_REG_2, 1	
	SBCO	&RCV_TEMP_REG_2, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	.endif ;HALF_DUPLEX_ENABLED
NO_PREAMBLE_ERROR:
	
	; RCV_CONTEXT is not initialized for this error frame.
	; reset RX FIFO, this places the R18 counter back to position 0
	CLR	R23 , R23 , 1 
	M_SET_CMD	D_RESET_RXFIFO
	QBA		LB_NO_RX_STAT
RCV_LB_PROCESS_NORMAL:
	
	; save call register pointer
	;MOV		L1_CALL_REG, CALL_REG
	; for XIN, make sure that shift is set to 0
	LDI	R0.b0, SHIFT_NONE	
	; restore task parameters from parameter bank
	.if $isdefed("PRU0")	
	XIN	BANK1, &MII_RCV, $sizeof(MII_RCV)	
	.else
	XIN	BANK2, &MII_RCV, $sizeof(MII_RCV)	
	.endif
	QBBS	LB_RESET_RX_FIFO, MII_RCV.rx_flags, 4	 ;replaced: QBBS	LB_RESET_RX_FIFO, MII_RCV.rx_flags.rx_frame_error 
	; depending on the bank index, we load bank 0 or bank 1
	QBBS	LB_XIN_UPPER_BANK, MII_RCV.rx_flags, 3	 ;replaced: QBBS	LB_XIN_UPPER_BANK, MII_RCV.rx_flags.rx_bank_index 
	
LB_XIN_LOWER_BANK:
	
	XIN	RX_L2_BANK0_ID, &R18, RANGE_R18_b0	
	XIN	RX_L2_BANK0_ID, &R2, RANGE_R2_R13	; XIN RX L2 bank 0
	; have we received more than 32 bytes?
	QBGE	LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK, R18_RCV_BYTECOUNT, 32	
	QBA		LB_STORE_FIRST_32_BYTES
	
LB_XIN_UPPER_BANK:
	XIN	RX_L2_BANK1_ID, &R18, RANGE_R18_b0	
	XIN	RX_L2_BANK1_ID, &R2, RANGE_R2_R13	; XIN RX L2 bank 1
	; have we received more than 32 bytes?
	QBLE	LB_XIN_STORE_LESS_THAN_32_FROM_UPPER_BANK, R18_RCV_BYTECOUNT, 32	
	
LB_STORE_FIRST_32_BYTES:
	
	SBCO	&Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, 32	
	ADD		MII_RCV.byte_cntr, MII_RCV.byte_cntr,  32
	
	; Update the buffer descriptor for the received packet
	; Compare current wrk pointer to top_most queue desc pointer ..check for wrap around
	QBNE	RCV_LB_NO_QUEUE_WRAP_LOWER, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
	AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset	;Warning: converted from MOV
	AND MII_RCV.buffer_index , MII_RCV.base_buffer_index , MII_RCV.base_buffer_index	;Warning: converted from MOV
	QBA		RCV_LB_QUEUE_WRAPPED_LOWER
RCV_LB_NO_QUEUE_WRAP_LOWER:
	ADD		MII_RCV.buffer_index, MII_RCV.buffer_index,  32
	ADD		MII_RCV.wrkng_wr_ptr,  MII_RCV.wrkng_wr_ptr,  4
	
RCV_LB_QUEUE_WRAPPED_LOWER:
	; Check if the queue got completely filled with the last few bytes and the remaining bytes cannot be added.
	;This scenario of queue overflow has been verified by dry run.
	QBNE	LB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL_1, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
	CLR	MII_RCV.rx_flags , MII_RCV.rx_flags , 0 
	SET	MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , 6 
	;For EMAC mode, set rx_frame_error bit.
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 4 
	
LB_PROCESS_32BYTES_CHECK_FLAGS_QUEUE_NOT_FULL_1:
	
	QBBC	LB_STORE_UPPER_DATA, MII_RCV.rx_flags, 3	 ;replaced: QBBC	LB_STORE_UPPER_DATA, MII_RCV.rx_flags.rx_bank_index 
	
	; get and store lower data
	XIN	RX_L2_BANK0_ID, &R2, RANGE_R2_R9	
	QBA		LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK
LB_STORE_UPPER_DATA:
	; get and store upper data
	XIN	RX_L2_BANK1_ID, &R2, RANGE_R2_R13	
	
LB_XIN_STORE_LESS_THAN_32_FROM_UPPER_BANK:
	SUB	R0.b1, R18, 32	
	QBA		LB_STORE_FROM_UPPER_BUFFER
LB_XIN_STORE_LESS_THAN_32_FROM_LOWER_BANK:
	AND R0.b1 , R18 , R18
LB_STORE_FROM_UPPER_BUFFER:
	; Check if 0 bytes are there to store
	QBEQ	LB_PROCESS_CHECK_FWD_FLAG, R0.b1, 0	
	
	; Receive for Host Queue
	SBCO	&Ethernet, L3_OCMC_RAM_CONST, MII_RCV.buffer_index, b1	
	
	ADD	MII_RCV.byte_cntr, MII_RCV.byte_cntr, R0.b1	
	QBGE	LB_PROCESS_CHECK_FWD_FLAG, R0.b1, 4	
	QBNE	RCV_LB_NO_QUEUE_WRAP_2, MII_RCV.wrkng_wr_ptr, MII_RCV.top_most_buffer_desc_offset
	AND MII_RCV.wrkng_wr_ptr , MII_RCV.base_buffer_desc_offset , MII_RCV.base_buffer_desc_offset	;Warning: converted from MOV
	QBA		RCV_LB_QUEUE_WRAPPED_2
RCV_LB_NO_QUEUE_WRAP_2:
	ADD		MII_RCV.wrkng_wr_ptr,  MII_RCV.wrkng_wr_ptr,  4
RCV_LB_QUEUE_WRAPPED_2:
	; Check if the queue got completely filled with the last few bytes.
	;If yes, the wr_ptr and rd_prt might become equal and there could be
	;possible data overwrite when the next packet arrives.
	;This has been verfied by dry run.
	QBNE	LB_PROCESS_CHECK_FLAGS_QUEUE_NOT_FULL, MII_RCV.wrkng_wr_ptr, MII_RCV.rd_ptr
	CLR	MII_RCV.rx_flags , MII_RCV.rx_flags , 0 
	SET	MII_RCV.rx_flags_extended , MII_RCV.rx_flags_extended , 6 
	;For EMAC mode, set rx_frame_error bit
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 4 
	
LB_PROCESS_CHECK_FLAGS_QUEUE_NOT_FULL:
LB_PROCESS_CHECK_FWD_FLAG:
	
	; Check for CRC Error in the received frame
	LDI	RCV_TEMP_REG_1.w0, 0x0204	
	LBCO	&RCV_TEMP_REG_2, ICSS_INTC_CONST, RCV_TEMP_REG_1.w0, 4	
	
;check odd nibble error	
CHECK_MISALIGNMENT_ERROR:
	.if $isdefed("PRU0")	
	QBBC	CHECK_CRC_ERROR, RCV_TEMP_REG_2, 5	 ;replaced: QBBC	CHECK_CRC_ERROR, RCV_TEMP_REG_2.t5 
	.else
	QBBC	CHECK_CRC_ERROR, RCV_TEMP_REG_2, 17	 ;replaced: QBBC	CHECK_CRC_ERROR, RCV_TEMP_REG_2.t17 
	.endif
	LDI	RCV_TEMP_REG_3 , RX_MISALIGNMENT_COUNT_OFFSET
	
;Add to statistics counter
	LBCO	&RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	ADD	RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1	
	SBCO	&RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 4 
	
CHECK_CRC_ERROR:
	.if $isdefed("PRU0")	
	QBBC	LB_CHECK_MIN_FRM_ERR, RCV_TEMP_REG_2, 4	 ;replaced: QBBC	LB_CHECK_MIN_FRM_ERR, RCV_TEMP_REG_2.t4 
	.else
	QBBC	LB_CHECK_MIN_FRM_ERR, RCV_TEMP_REG_2, 16	 ;replaced: QBBC	LB_CHECK_MIN_FRM_ERR, RCV_TEMP_REG_2.t16 
	.endif
	LDI	RCV_TEMP_REG_3 , RX_CRC_COUNT_OFFSET
	
;Add to statistics counter
	LBCO	&RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	ADD	RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1	
	SBCO	&RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 4 
	
	;Check whether received frame length is less then defined min value
LB_CHECK_MIN_FRM_ERR:
	.if $isdefed("PRU0")	
	LBCO	&RCV_TEMP_REG_2.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1	
	.else
	LBCO	&RCV_TEMP_REG_2.b0, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1	
	.endif
	QBBC	LB_CHECK_MAX_FRM_ERR, RCV_TEMP_REG_2, 2	 ;replaced: QBBC	LB_CHECK_MAX_FRM_ERR, RCV_TEMP_REG_2.b0.t2 
	LDI	RCV_TEMP_REG_3 , RX_UNDERSIZED_FRAME_OFFSET
	QBA		LB_CLR_RX_ERROR_REG
	
	;Check whether received frame length is more then defined max value
LB_CHECK_MAX_FRM_ERR:
	QBBC	LB_RESET_RX_FIFO, RCV_TEMP_REG_2, 3	 ;replaced: QBBC	LB_RESET_RX_FIFO, RCV_TEMP_REG_2.b0.t3 
	LDI	RCV_TEMP_REG_3 , RX_OVERSIZED_FRAME_OFFSET
	
LB_CLR_RX_ERROR_REG:
	
;Add to statistics counter
	LBCO	&RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	ADD	RCV_TEMP_REG_1, RCV_TEMP_REG_1, 1	
	SBCO	&RCV_TEMP_REG_1, PRU_DMEM_ADDR, RCV_TEMP_REG_3, 4	
	
	; Clear the RX MIN or RX MAX ERROR
	LDI	RCV_TEMP_REG_2.b1, 0x0c	
	.if $isdefed("PRU0")	
	SBCO	&RCV_TEMP_REG_2.b1, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR0, 1	
	.else
	SBCO	&RCV_TEMP_REG_2.b1, MII_RT_CFG_CONST, ICSS_MIIRT_RXERR1, 1	
	.endif
	SET	MII_RCV.rx_flags , MII_RCV.rx_flags , 4 
	
LB_RESET_RX_FIFO:
	; reset RX fifo, this places the R18 counter back to position 0
	M_SET_CMD	D_RESET_RXFIFO
	
	QBBC	LB_NO_RX_FRAME_ERROR, MII_RCV.rx_flags, 4	 ;replaced: QBBC	LB_NO_RX_FRAME_ERROR, MII_RCV.rx_flags.rx_frame_error 
	;clear RX flags
	CLR	R22 , R22 , 28 
	CLR	R22 , R22 , 27 
	JMP		LB_RELEASE_QUEUE   ; Clear the EOF and other possible error flags.
	
LB_NO_RX_FRAME_ERROR:
	
	LDI	R0.b0, 0	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_RCV, $sizeof(MII_RCV)	; store task parameters from parameter bank
	.else
	XOUT	BANK2, &MII_RCV, $sizeof(MII_RCV)	; store task parameters from parameter bank
	.endif
	
	; For Host Receive
	LDI	R0.b0, SHIFT_R2_TO_R26	
	.if $isdefed("PRU0")	
	XIN	BANK1, &RCV_CONTEXT, $sizeof(MII_RCV_PORT)	; store task parameters from parameter bank
	.else
	XIN	BANK2, &RCV_CONTEXT, $sizeof(MII_RCV_PORT)	; store task parameters from parameter bank
	.endif
	
	;store the length of the packet for statistics
	LDI	RCV_TEMP_REG_2 , RX_PKT_SIZE_OFFSET
	SBCO	&RCV_CONTEXT.byte_cntr, PRU_DMEM_ADDR, RCV_TEMP_REG_2, 2	
	
	; Update the Receive Buffer Descriptor
	; Read the wr_ptr of first buffer descriptor
	LBCO	&RCV_TEMP_REG_1, ICSS_SHARED_CONST, RCV_CONTEXT.rcv_queue_pointer, 4	
	; clear length field (18..28) and update length with current received frame
	LDI	RCV_TEMP_REG_2.w0, 0	
	
	SUB	RCV_TEMP_REG_2.w2, RCV_CONTEXT.byte_cntr, 4	;4 byte of FCS
	LSL	RCV_TEMP_REG_2.w2, RCV_TEMP_REG_2.w2, 2	
	;Set the Port number on which packet was received
	.if $isdefed("PRU0")	
	SET	RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 16 ; Port 1
	.else
	SET	RCV_TEMP_REG_2 , RCV_TEMP_REG_2 , 17 ;Port 2	
	.endif
	
	; the first buffer descriptor of the frame has been updated with length and port information
	SBCO	&RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w2, 4	
	
	;Update the queue max fill level
	QBGT 	LB_RCV_QUEUE_WRAP, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.rd_ptr
	SUB	RCV_TEMP_REG_2.w0, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.rd_ptr	
	JMP     SKIP_LB_RCV_QUEUE_WRAP
	
LB_RCV_QUEUE_WRAP:
	; add queue size to rd_ptr and then subtract wr_ptr
	SUB	RCV_TEMP_REG_2.w0, RCV_CONTEXT.top_most_buffer_desc_offset, RCV_CONTEXT.rd_ptr	
	ADD	RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, 4	
	SUB	RCV_TEMP_REG_2.w2, RCV_CONTEXT.wrkng_wr_ptr, RCV_CONTEXT.base_buffer_desc_offset	
	ADD	RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w2	
	
SKIP_LB_RCV_QUEUE_WRAP:
	;divide the queue fill level by 4
	LSR	RCV_TEMP_REG_2.w0, RCV_TEMP_REG_2.w0, 2	
	;Read the queue max fill level
	ADD	RCV_TEMP_REG_1.w0, RCV_CONTEXT.rcv_queue_pointer, Q_MAX_FILL_LEVEL_OFFSET	
	LBCO	&RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1	
	
	;compare the new queue fill level with max fill level
	QBGE	LB_SKIP_NEW_FILL_LEVEL, RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b2	
	AND RCV_TEMP_REG_2.b2 , RCV_TEMP_REG_2.b0 , RCV_TEMP_REG_2.b0
	; store the new max fill level
	SBCO	&RCV_TEMP_REG_2.b2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 1	
	
LB_SKIP_NEW_FILL_LEVEL:
	; Update the Queue Descriptor with the new wr_ptr
	ADD	RCV_TEMP_REG_1.w0, RCV_CONTEXT.rcv_queue_pointer, Q_RD_PTR_SIZE	
	SBCO	&RCV_CONTEXT.wrkng_wr_ptr, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, Q_WR_PTR_SIZE	
	
LB_RELEASE_QUEUE:
	;Release the Receive Queue. De-assert the Queue busy bit
	; PRU0 is master so it clear's only "busy_m" bit
	.if $isdefed("PRU0")	
	ADD	RCV_TEMP_REG_1.w0, MII_RCV.rcv_queue_pointer, Q_STATUS_OFFSET	
	LBCO	&RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3	
	
	AND	RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0xFC	; !(1<<Q_BUSY_M_BIT | 1<<Q_COLLISION_BIT)
	QBBC	LB_NO_HOST_QUEUE_OVERFLOW_OCCURED, MII_RCV.rx_flags_extended, 6	 ;replaced: QBBC	LB_NO_HOST_QUEUE_OVERFLOW_OCCURED, MII_RCV.rx_flags_extended.host_queue_overflow 
	OR	RCV_TEMP_REG_2.b0, RCV_TEMP_REG_2.b0, 0x04	; set the overflow bit
	ADD	RCV_TEMP_REG_2.b2, RCV_TEMP_REG_2.b2, 1	; increment the overflow count by 1 
LB_NO_HOST_QUEUE_OVERFLOW_OCCURED:	
	SBCO	&RCV_TEMP_REG_2.b0, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 3	
	
	.else
	; PRU1 is slave so it clear's only "busy_s" bit
	ADD	RCV_TEMP_REG_1.w0, MII_RCV.rcv_queue_pointer, Q_BUSY_S_OFFSET	
	LBCO	&RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 4	
	LDI	RCV_TEMP_REG_2.b0, 0	
	QBBC	LB_NO_HOST_QUEUE_OVERFLOW_OCCURED_SLAVE, MII_RCV.rx_flags_extended, 6	 ;replaced: QBBC	LB_NO_HOST_QUEUE_OVERFLOW_OCCURED_SLAVE, MII_RCV.rx_flags_extended.host_queue_overflow 
	OR	RCV_TEMP_REG_2.b1, RCV_TEMP_REG_2.b1, 0x04	; set the overflow bit
	ADD	RCV_TEMP_REG_2.b3, RCV_TEMP_REG_2.b3, 1	; increment the overflow count by 1 
LB_NO_HOST_QUEUE_OVERFLOW_OCCURED_SLAVE:	
	SBCO	&RCV_TEMP_REG_2, ICSS_SHARED_CONST, RCV_TEMP_REG_1.w0, 4	
	.endif
	
	CLR	R23 , R23 , 1 ; indicate that rcv has been completed  
	QBBS	LB_NO_RX_STAT, MII_RCV.rx_flags, 4	 ;replaced: QBBS	LB_NO_RX_STAT, MII_RCV.rx_flags.rx_frame_error 
	SET	R23 , R23 , 3 
	
	; Give a interrupt to host as frame has been received
	; two interrupts for two ports in MAC mode
	.if $isdefed("PRU0")	
	LDI	R31, 0x24	; Maps to system event 20, 0x24 = 10 0100
	.else
	LDI	R31, 0x25	; Maps to system event 20, 0x24 = 10 0100
	.endif
	
LB_NO_RX_STAT:
	
	.if $isdefed("SOC_AM335x")	
	M_RCV_RX_EOF_CLEAR_INTC_AM335x
	.endif	;SOC_AM335x
	
	.if $isdefed("SOC_AM571x")	
	M_RCV_RX_EOF_CLEAR_INTC_AM571x
	.endif	;SOC_AM571x
	
	; Execute the TX Task as next task
	QBBC	TASK_EXECUTION_FINISHED_inter, R23, 0	 ;replaced: QBBC	TASK_EXECUTION_FINISHED_inter, Xmt_active 
	LDI	CURRENT_TASK_POINTER, BG_TASK_POINTER	
	JMP		XMT_QUEUE
	
TASK_EXECUTION_FINISHED_inter:
	JMP	TASK_EXECUTION_FINISHED
	
	.endif  ; e/o MII_Rcv_p
