;******************************************************************************
;+--------------------------------------------------------------------------+**
;|                            ****                                          |**
;|                            ****                                          |**
;|                            ******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_Xmt.p
;
; brief:  Transmit task.
;
;
;  (C) Copyright 2012, Texas Instruments, Inc
;
;	Version		Description								Author
;
; 	0.1     	Created									Robin Singh
;  0.2			Changed Tx fifo fill level strategy		
;  0.3         Added 10 Mbps support
;  0.4			Updated for Common Baseline				Anjandeep Sahni
;	0.5			Added TTS Support						Anjandeep Sahni
	
	.if !$isdefed("__mii_xmt_p")	
__mii_xmt_p	.set	1 
	
;;///////////////////////////////////////////////////////
; Includes Section
;;///////////////////////////////////////////////////////
	.include "icss_intc_regs.h"
	.include "icss_emacSwitch.h"
	.include "icss_defines.h"	
       	.include "micro_scheduler.h"
	.include "emac_MII_Xmt.h"
       	.include "emac_MII_Rcv.h"
        .include "icss_macros.h"
	.include "emac_MII_Xmt.h"
	.include "icss_miirt_regs.h"
     	.include "icss_iep_regs.h"
	.include "emac_tts.h"
        
        .global  FN_RCV_LB
        .global  XMT_QUEUE
        .global  MII_TX_TASK
        .global  TASK_EXECUTION_FINISHED
        .global  FN_TTS_PKT_SIZE_CHECK_AM571x
        .global  CHECK_NEXT_QUEUE
        .global  START_XMT_QUEUE
        .global  FN_TTS_PKT_SIZE_CHECK_AM335x


MII_TX_TASK:
	LDI	R0.w2 , PORT_STATUS_OFFSET
	LBCO	&R0.w0, PRU_DMEM_ADDR, R0.w2, 1	
	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	QBBS	SET_HALF_DUPLEX, R0, 1	 ;replaced: QBBS    SET_HALF_DUPLEX, R0.PORT_IS_HD 
	CLR	R22 , R22 , 23 
	QBA     CHECK_XMT_ACTIVE
SET_HALF_DUPLEX:
	SET	R22 , R22 , 23 
	
CHECK_XMT_ACTIVE:	
	.endif
	QBBS	XMT_QUEUE, R23, 0	 ;replaced: QBBS	XMT_QUEUE, Xmt_active 
	
;****************************************************************************
;
;     NAME			: FN_XMT_scheduler
;     DESCRIPTION	: if any queue is not empty then schedules the trasmit
;     RETURNS		: 
;     ARGS			: 
;     USES 		: 
;     INVOKES 		: 
;
;**************************************************************************** 
TX_QUEUE_CONT:
	;check if port link is up
	QBBS	XMT_FB_EGRESS_LINK_UP_FWD, R0, 0	 ;replaced: QBBS    XMT_FB_EGRESS_LINK_UP_FWD, R0.PORT_LINK_UP 
	QBA     NO_TRANSMIT_PACKET
	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
COLLISION_DETECTED:
	CLR	R23 , R23 , 0 
	;reset TX FIFO
	M_TX_RESET
	;Add 1 to collision counter
	
	LDI	R0 , COLLISION_COUNTER
	LBCO	&R2, PRU_DMEM_ADDR, R0, 1	
	ADD	R2.b0, R2.b0, 1	
	SBCO	&R2, PRU_DMEM_ADDR, R0, 1	
	
	;clear the stat flags
	CLR	R22 , R22 , 26 
	CLR	R22 , R22 , 25 
	
	QBBS	ADD_TX_STATS_DO_NOT_RESET_COLLISION_COUNTER, R22, 22	 ;replaced: QBBS     ADD_TX_STATS_DO_NOT_RESET_COLLISION_COUNTER, TX_LATE_COLLISION 
	QBA      NO_TRANSMIT_PACKET
	
CARRIER_SENSE_DETECTED:
	CLR	R23 , R23 , 0 
	LDI	R0 , TX_DEFERRED_OFFSET
	QBA      INCREMENT_TX_COUNT
	
ADD_TX_STATS:
	LDI	R3 , COLLISION_COUNTER
	LDI	R2.b0 , 0
	SBCO	&R2, PRU_DMEM_ADDR, R3, 1	
	QBA     INCREMENT_TX_COUNT
	
ADD_TX_STATS_DO_NOT_RESET_COLLISION_COUNTER:
	CLR	R22 , R22 , 22 
	LDI	R0 , LATE_COLLISION_OFFSET
INCREMENT_TX_COUNT:
	LBCO	&R2, PRU_DMEM_ADDR, R0, 4	
	ADD	R2, R2, 1	
	SBCO	&R2, PRU_DMEM_ADDR, R0, 4	
	.endif ;HALF_DUPLEX_ENABLED
	
NO_TRANSMIT_PACKET:
	JMP     TASK_EXECUTION_FINISHED
	
XMT_FB_EGRESS_LINK_UP_FWD:
; New optimized code for checking the transmit queues
; Loop four times as there are four transmit queues
	
	.if $isdefed("PRU0")	
	LDI	R20.w0, Q4_TX_CONTEXT_OFFSET	
	LDI	QUEUE_DESC_OFFSET , PORT_QUEUE_DESC_OFFSET - 8
	LDI	TX_CONTEXT_OFFSET , Q1_TX_CONTEXT_OFFSET - 8
CHECK_NEXT_QUEUE:
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	;skip if half duplex is not set
	QBBC	SKIP_CRS_Q, R22, 23	 ;replaced: QBBC    SKIP_CRS_Q, PORT_IS_HALF_DUPLEX 
	;defer if carrier sense is on
	LBCO	&TEMP_REG_1, MII_RT_CFG_CONST, MII_CARRIER_SENSE_REG, 1	
	QBBS	CARRIER_SENSE_DETECTED, TEMP_REG_1, 1	 ;replaced: QBBS    CARRIER_SENSE_DETECTED, TEMP_REG_1.t1 
SKIP_CRS_Q:		
	.endif ;HALF_DUPLEX_ENABLED
	QBEQ	NO_TRANSMIT_PACKET, TX_CONTEXT_OFFSET, R20.w0	
	ADD	QUEUE_DESC_OFFSET, QUEUE_DESC_OFFSET, 8	
	LBCO	&QUEUE_DESC_REG, PRU_DMEM_ADDR, QUEUE_DESC_OFFSET, 8	
	ADD	TX_CONTEXT_OFFSET, TX_CONTEXT_OFFSET, 8	
	QBEQ    CHECK_NEXT_QUEUE, QUEUE_DESC_REG.wr_ptr, QUEUE_DESC_REG.rd_ptr
	.if $isdefed("TTS")	
	M_TTS_XMT_SCHEDULER	TX_CONTEXT_OFFSET	
	.endif	;TTS
	.else
	;PRU1
	LDI	R20.w0, Q4_TX_CONTEXT_OFFSET	
	LDI	QUEUE_DESC_OFFSET , PORT_QUEUE_DESC_OFFSET - 8
	LDI	TX_CONTEXT_OFFSET , Q1_TX_CONTEXT_OFFSET - 8
CHECK_NEXT_QUEUE:
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	;skip if half duplex is not set
	QBBC	SKIP_CRS_Q, R22, 23	 ;replaced: QBBC    SKIP_CRS_Q, PORT_IS_HALF_DUPLEX 
	;defer if carrier sense is on
	LBCO	&TEMP_REG_1, MII_RT_CFG_CONST, MII_CARRIER_SENSE_REG, 1	
	QBBS	CARRIER_SENSE_DETECTED, TEMP_REG_1, 1	 ;replaced: QBBS    CARRIER_SENSE_DETECTED, TEMP_REG_1.t1 
SKIP_CRS_Q:		
	.endif ;HALF_DUPLEX_ENABLED
	QBEQ	NO_TRANSMIT_PACKET, TX_CONTEXT_OFFSET, R20.w0	
	ADD	QUEUE_DESC_OFFSET, QUEUE_DESC_OFFSET, 8	
	LBCO	&QUEUE_DESC_REG, PRU_DMEM_ADDR, QUEUE_DESC_OFFSET, 8	
	ADD	TX_CONTEXT_OFFSET, TX_CONTEXT_OFFSET, 8	
	QBEQ    CHECK_NEXT_QUEUE, QUEUE_DESC_REG.wr_ptr, QUEUE_DESC_REG.rd_ptr
	.if $isdefed("TTS")	
	M_TTS_XMT_SCHEDULER	TX_CONTEXT_OFFSET	
	.endif	;TTS
	.endif
	
;;////////////////////////////////////////////////////////////////////////////////////////
	
;****************************************************************************
;
;     NAME			: FN_XMT_queue
;     DESCRIPTION	: trasmits the first block of 32B data from the queue into TX FIFO 
;     RETURNS		: 
;     ARGS			: 
;     USES 			: 
;     INVOKES 		: 
;
;****************************************************************************
START_XMT_QUEUE:
	; Read the TX Context of 8 Bytes.
	LBCO	&BUFFER_OFFSET, PRU_DMEM_ADDR, TX_CONTEXT_OFFSET, 8	
	; init MII_XMT parameter
	SET	R23 , R23 , 0 ; set global flag to indicate an ongoing transmission
	SUB	BUFFER_DESC_OFFSET, QUEUE_DESC_REG.rd_ptr, BASE_BUFFER_DESC_OFFSET	
	LSL	BUFFER_DESC_OFFSET, BUFFER_DESC_OFFSET, 3	
	ADD	BUFFER_INDEX, BUFFER_OFFSET, BUFFER_DESC_OFFSET	
	AND     BUFFER_DESC_OFFSET , QUEUE_DESC_REG.rd_ptr , QUEUE_DESC_REG.rd_ptr	;Warning: converted from MOV
	LBCO	&BUFFER_DESC_REG, PRU_DMEM_ADDR, BUFFER_DESC_OFFSET, 4	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;LSL	Packet_Length, BUFFER_DESC_REG.Length, 3	;bit 18...28
	LSL	Packet_Length, BUFFER_DESC_REG.w2, 3	;bit 18...28
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	LSR	Packet_Length, Packet_Length, 5	
	LDI	BYTE_CNT , 0
	; Read the Phy speed and set the flag accordingly
	LDI	R2.w0, PHY_SPEED_OFFSET	
	LBCO	&R2.w2, PRU_DMEM_ADDR, R2.w0, 2	
	
	SET	R23 , R23 , 7 ; 100 Mbps
	QBEQ	XMT_FB_100Mbps_MODE, R2.b2, 100	
	CLR	R23 , R23 , 7 ; 10 Mbps
XMT_FB_100Mbps_MODE:
	
;Check RX EOF.
	.if $isdefed("SOC_AM335x")	
	M_XMT_RX_EOF_CHECK_AM335x	process_rx_eof_tx_fb
	.endif
	.if $isdefed("SOC_AM571x")	
	M_XMT_RX_EOF_CHECK_AM571x	process_rx_eof_tx_fb
	.endif
	
	LBCO	&BUFFER, L3_OCMC_RAM_CONST, BUFFER_INDEX, 32	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
;check for Half Duplex and Carrier sense	
	QBBC	CONTINUE_TX, R22, 23	 ;replaced: QBBC    CONTINUE_TX, PORT_IS_HALF_DUPLEX 
	LBCO	&R0, MII_RT_CFG_CONST, MII_CARRIER_SENSE_REG, 1	
	QBBC	CONTINUE_TX, R0, 1	 ;replaced: QBBC    CONTINUE_TX, R0.t1 
	QBA     CARRIER_SENSE_DETECTED
	
CONTINUE_TX:
	.endif ;HALF_DUPLEX_ENABLED
	
;Do TX stats here	
	QBBS	TX_IS_MC_OR_BC, R2, 0	 ;replaced: QBBS    TX_IS_MC_OR_BC, R2.t0 
	QBA     START_TX_FIFO_FILL
	
TX_IS_MC_OR_BC:
	FILL	&R0, 4  ;Fill with 0xffffffff
	QBNE	TX_IS_MC, R2, R0	;First four bytes of MAC ID
	QBNE	TX_IS_MC, R3.w0, R0.w0	;upper two bytes of MAC ID
	SET	R22 , R22 , 26 
	QBA     START_TX_FIFO_FILL
	
TX_IS_MC:
	SET	R22 , R22 , 25 
	
START_TX_FIFO_FILL:
	.if $isdefed("TTS")	
	M_TTS_TX_SOF_PREV_STORE
	.endif	;TTS
	
	.if $isdefed("SOC_AM335x")	
	LDI	TX_DATA_WORD_MASK , 0xffff
	AND TX_DATA_BYTE , BUFFER.b0 , BUFFER.b0
	M_PUSH_BYTE
	AND TX_DATA_BYTE , BUFFER.b1 , BUFFER.b1
	M_PUSH_BYTE
	.endif	;SOC_AM335x
	
PUSH_FB:
; Insert the data in Tx Fifo
	.if $isdefed("SOC_AM335x")	
	LDI	TX_DATA_POINTER, buffer_ptr + 2	
	loop	EndLoop_FB1, 15					; Inserted a word above, so left with 15 words
	MVIW	TX_DATA_WORD, *TX_DATA_POINTER	
	M_PUSH_WORD_CMD
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 2	
EndLoop_FB1:
	.endif	;SOC_AM335x
	
	.if $isdefed("SOC_AM571x")	
	LDI	TX_DATA_POINTER, buffer_ptr	
	loop	EndLoop_FB1, 8					; Insert 32 bytes
	MVID	TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER	
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 4	
EndLoop_FB1:
	.endif	;SOC_AM571x
	
	ADD	BUFFER_INDEX, BUFFER_INDEX, 32	
	ADD	BYTE_CNT, BYTE_CNT, 32	
	SET	R13 , R13 , 1 
	LDI	BYTES_TRANSFERRED_IN_LAST_CALL, 0x00	
	LDI	SHIFT_REG, SHIFT_NONE	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_TX_CONTEXT, 20	
	.else
	XOUT	BANK2, &MII_TX_CONTEXT, 20	
	.endif
	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	;check for collision on wire
	QBBC	NO_COLLISION1, R22, 23	 ;replaced: QBBC    NO_COLLISION1, PORT_IS_HALF_DUPLEX 
	LBCO	&TEMP_REG_1, MII_RT_CFG_CONST, MII_CARRIER_SENSE_REG, 1	
	QBBC	NO_COLLISION1, TEMP_REG_1, 0	 ;replaced: QBBC    NO_COLLISION1, TEMP_REG_1.t0 
	QBA     COLLISION_DETECTED
NO_COLLISION1:
	.endif ;HALF_DUPLEX_ENABLED
	
	.if $isdefed("SOC_AM335x")	
	M_XMT_RX_EOF_CHECK_AM335x	process_rx_eof_tx_fb_after_inserting_32bytes
	.endif	;SOC_AM335x
	.if $isdefed("SOC_AM571x")	
	M_XMT_RX_EOF_CHECK_AM571x	process_rx_eof_tx_fb_after_inserting_32bytes
	.endif	;SOC_AM571x
	
	; No RX EOF event so fill Tx FIFO more bytes
	QBNE	NO_QUEUE_WRAP_XMT_FB, BUFFER_DESC_OFFSET, TOP_MOST_BUFFER_DESC_OFFSET	
	AND BUFFER_DESC_OFFSET , BASE_BUFFER_DESC_OFFSET , BASE_BUFFER_DESC_OFFSET
	CLR	R13 , R13 , 1 ; Since the Queue has wrapped here itself ..no need to check for it in xmt_nb for first time
	AND BUFFER_INDEX , BUFFER_OFFSET , BUFFER_OFFSET
	
NO_QUEUE_WRAP_XMT_FB:
	
	LBCO	&BUFFER, L3_OCMC_RAM_CONST, BUFFER_INDEX, 32	
	LDI	TX_DATA_POINTER, buffer_ptr	
	
	.if $isdefed("SOC_AM335x")	
	; Insert next 22 bytes in Tx FIFO
	loop	EndLoop_FB_22bytes_more, 11
	MVIW	TX_DATA_WORD, *TX_DATA_POINTER
	M_PUSH_WORD_CMD
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 2	
EndLoop_FB_22bytes_more:
	ADD	BUFFER_INDEX, BUFFER_INDEX, 22	
	ADD	BYTE_CNT, BYTE_CNT, 22	
	LDI	BYTES_TRANSFERRED_IN_LAST_CALL, 22	
	LDI	SHIFT_REG, SHIFT_NONE	
	.endif	;SOC_AM335x
	
	.if $isdefed("SOC_AM571x")	
	; Insert next 28 bytes in Tx FIFO
	loop	EndLoop_FB_28bytes_more, 7
	MVID	TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 4	
EndLoop_FB_28bytes_more:
	ADD	BUFFER_INDEX, BUFFER_INDEX, 28	
	ADD	BYTE_CNT, BYTE_CNT, 28	
	LDI	BYTES_TRANSFERRED_IN_LAST_CALL, 28	
	LDI	SHIFT_REG, SHIFT_NONE	
	.endif	;SOC_AM571x
	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_TX_CONTEXT, 20	
	.else
	XOUT	BANK2, &MII_TX_CONTEXT, 20	
	.endif
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	;check for collision
	QBBC	NO_COLLISION2, R22, 23	 ;replaced: QBBC    NO_COLLISION2, PORT_IS_HALF_DUPLEX 
	LBCO	&TEMP_REG_1, MII_RT_CFG_CONST, MII_CARRIER_SENSE_REG, 1	
	QBBC	NO_COLLISION2, TEMP_REG_1, 0	 ;replaced: QBBC    NO_COLLISION2, TEMP_REG_1.t0 
	QBA     COLLISION_DETECTED
NO_COLLISION2:
	.endif ;HALF_DUPLEX_ENABLED
	
TASK_EXECUTION_FINISHED_intr:
	JMP		TASK_EXECUTION_FINISHED
	
process_rx_eof_tx_fb:
	CLR	R23 , R23 , 0 
process_rx_eof_tx_fb_after_inserting_32bytes:
	JAL	CALL_REG, FN_RCV_LB	
	
;****************************************************************************
;
;     NAME			: XMT_QUEUE
;     DESCRIPTION	: trasmits the next block of 32B data from the queue into TX FIFO 
;     RETURNS		: 
;     ARGS			: 
;     USES 		: 
;     INVOKES 		: 
;
;****************************************************************************	
XMT_QUEUE:
	;check if port link is up
	LDI	R0.w2 , PORT_STATUS_OFFSET
	LBCO	&R0.b0, PRU_DMEM_ADDR, R0.w2, 1	
	QBBS	XMT_QUEUE_PORT_LINK_IS_UP, R0, 0	 ;replaced: QBBS    XMT_QUEUE_PORT_LINK_IS_UP, R0.PORT_LINK_UP 
	;Port link has gone down while frame was in transmission.
	CLR	R23 , R23 , 0 
	M_TX_RESET
	SET	R22 , R22 , 31 
	JMP		TASK_EXECUTION_FINISHED
XMT_QUEUE_PORT_LINK_IS_UP:
	
	LDI	SHIFT_REG, SHIFT_NONE	
	.if $isdefed("PRU0")	
	XIN	BANK1, &MII_TX_CONTEXT, 20	
	.else
	XIN	BANK2, &MII_TX_CONTEXT, 20	
	.endif
	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	LDI	TEMP_REG_3.w2 , PORT_STATUS_OFFSET
	LBCO	&TEMP_REG_3.w0, ICSS_SHARED_CONST, TEMP_REG_3.w2, 1	
	QBBS	SET_HALF_DUPLEX1, TEMP_REG_3, 0	 ;replaced: QBBS    SET_HALF_DUPLEX1, TEMP_REG_3.t0 
	CLR	R22 , R22 , 23 
	QBA     CONTINUE_XMT_QUEUE
SET_HALF_DUPLEX1:
	SET	R22 , R22 , 23 
	.endif ;HALF_DUPLEX_ENABLED
	
CONTINUE_XMT_QUEUE:
	
	.if $isdefed("TTS")	
	M_TTS_FIFO_FILL_MOD
	.endif	;TTS
	
	.if !$isdefed("TTS")	
;Only need to read in non-TTS EMAC.
;For TTS EMAC, it is read in M_TTS_FIFO_FILL_MOD-->M_TTS_TX_SOF_COMPARE_AM335x.
	.if $isdefed("SOC_AM335x")	
	M_XMT_GET_TXSOF_AM335x
	.endif	;SOC_AM335x
	.endif	;TTS
	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	;check for collision
	QBBC	NO_COLLISION3, R22, 23	 ;replaced: QBBC    NO_COLLISION3, PORT_IS_HALF_DUPLEX 
	LBCO	&TEMP_REG_1, MII_RT_CFG_CONST, MII_CARRIER_SENSE_REG, 1	
	QBBC	NO_COLLISION3, TEMP_REG_1, 0	 ;replaced: QBBC    NO_COLLISION3, TEMP_REG_1.t0 
	QBA     COLLISION_DETECTED
NO_COLLISION3:
	.endif ;HALF_DUPLEX_ENABLED
	
	.if $isdefed("SOC_AM335x")	
	M_XMT_FILL_LEVEL_CALC_AM335x
	.endif	;SOC_AM335x
	
	.if $isdefed("SOC_AM571x")	
	M_XMT_FILL_LEVEL_CALC_AM571x
	.endif	;SOC_AM571x
	
	QBEQ	XMT_NB_DONE, FREE_SPACE_IN_FIFO, 0	
	QBGE	FILL_TX_FIFO, FREE_SPACE_IN_FIFO, 32	; At max fill only 32 bytes as read only 32 bytes from L3 ram
	LDI	FREE_SPACE_IN_FIFO, 32	
	
FILL_TX_FIFO:
	;Check for RX EOF.
	.if $isdefed("SOC_AM335x")	
	M_XMT_RX_EOF_CHECK_AM335x	process_rx_eof_tx_nb
	.endif	;SOC_AM335x
	.if $isdefed("SOC_AM571x")	
	M_XMT_RX_EOF_CHECK_AM571x	process_rx_eof_tx_nb
	.endif	;SOC_AM571x
	
	QBBC	QUEUE_WRAP_XMT, R13, 1	 ;replaced: QBBC	QUEUE_WRAP_XMT, INCREMENT_WRK_BUFFER_DESC_OFFSET 
	QBNE	NO_QUEUE_WRAP_XMT, BUFFER_DESC_OFFSET, TOP_MOST_BUFFER_DESC_OFFSET	
	AND BUFFER_DESC_OFFSET , BASE_BUFFER_DESC_OFFSET , BASE_BUFFER_DESC_OFFSET
	CLR	R13 , R13 , 1 
	AND BUFFER_INDEX , BUFFER_OFFSET , BUFFER_OFFSET
	JMP		QUEUE_WRAP_XMT
	
NO_QUEUE_WRAP_XMT:
	ADD	BUFFER_DESC_OFFSET, BUFFER_DESC_OFFSET, 4	; working rd_ptr
	CLR	R13 , R13 , 1 
QUEUE_WRAP_XMT:
	SUB	block_size, Packet_Length, BYTE_CNT	;QBLE to do
	QBLT	PUSH_NB, block_size, 32	
	LDI	SHIFT_REG, SHIFT_NONE	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_TX_CONTEXT, 20	
	.else
	XOUT	BANK2, &MII_TX_CONTEXT, 20	
	.endif
	JMP		XMT_LB
	
PUSH_NB:
	
	; Check whether BUFFER_INDEX is pointing to the top desc in TX Queue
	QBLE	fetch_data_from_ocmc, TOP_MOST_BUFFER_INDEX, BUFFER_INDEX	
	; Subtract the bytes which have been already transmitted
	SUB	TEMP_REG_3.b0, BUFFER_INDEX, TOP_MOST_BUFFER_INDEX	
	RSB	TEMP_REG_3.b1, TEMP_REG_3.b0, 32	
	QBLE	enough_data_in_top_block, TEMP_REG_3.b1, FREE_SPACE_IN_FIFO	
	AND FREE_SPACE_IN_FIFO , TEMP_REG_3.b1 , TEMP_REG_3.b1
enough_data_in_top_block:
fetch_data_from_ocmc:
	
	; Check if the RX EOF has come
	LBCO	&BUFFER, L3_OCMC_RAM_CONST, BUFFER_INDEX, 32	
	
	; Insert Tx Data in the Tx Fifo
	LDI	TX_DATA_POINTER, buffer_ptr	
	.if $isdefed("SOC_AM335x")	
	QBEQ	PUSH_ONE_BYTE, FREE_SPACE_IN_FIFO, 1	
	LSR	loop_cnt, FREE_SPACE_IN_FIFO, 1	
	LOOP	EndLoop_NB, loop_cnt	
	MVIW	TX_DATA_WORD, *TX_DATA_POINTER	
	M_PUSH_WORD_CMD
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 2	
EndLoop_NB:
	.endif	;SOC_AM335x
	
	.if $isdefed("SOC_AM571x")	
	LSR	loop_cnt, FREE_SPACE_IN_FIFO, 2	;divide by 4
	LOOP	EndLoop_NB, loop_cnt	
	MVID	TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER	
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 4	
EndLoop_NB:
	.endif	;SOC_AM571x
	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
;check for collision on wire
	QBBC	NO_COLLISION4, R22, 23	 ;replaced: QBBC    NO_COLLISION4, PORT_IS_HALF_DUPLEX 
	LBCO	&TEMP_REG_1, MII_RT_CFG_CONST, MII_CARRIER_SENSE_REG, 1	
	QBBC	NO_COLLISION4, TEMP_REG_1, 0	 ;replaced: QBBC    NO_COLLISION4, TEMP_REG_1.t0 
	QBA     COLLISION_DETECTED
NO_COLLISION4:
	.endif ;HALF_DUPLEX_ENABLED
	
;Check if any bytes are left to be added to TX FIFO.
	.if $isdefed("SOC_AM335x")	
	QBBC	FIFO_INSERTION_OVER, FREE_SPACE_IN_FIFO, 0
PUSH_ONE_BYTE:
	MVIB	TX_DATA_BYTE, *TX_DATA_POINTER
	M_PUSH_BYTE
	.endif	;SOC_AM335x
	
	.if $isdefed("SOC_AM571x")	
	AND	R20.b0, FREE_SPACE_IN_FIFO, 0x03	; Pick only last two bits
	QBEQ	FIFO_INSERTION_OVER, R20.b0, 0	
	QBEQ	PUSH_ONE_BYTE, R20.b0, 1	
	MVIW	TX_DATA_WORD, *TX_DATA_POINTER	
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 2	
	QBEQ	FIFO_INSERTION_OVER, R20.b0, 2	
PUSH_ONE_BYTE:
	MVIB	TX_DATA_BYTE, *TX_DATA_POINTER
	.endif	;SOC_AM571x
	
FIFO_INSERTION_OVER:
	ADD	BYTES_TRANSFERRED_IN_LAST_CALL, BYTES_TRANSFERRED_IN_LAST_CALL, FREE_SPACE_IN_FIFO	
	QBGT	DO_NOT_INCREMENT_BUFFER_DESC_OFFSET, BYTES_TRANSFERRED_IN_LAST_CALL, 32	
	SET	R13 , R13 , 1 
	SUB	BYTES_TRANSFERRED_IN_LAST_CALL, BYTES_TRANSFERRED_IN_LAST_CALL, 32	
DO_NOT_INCREMENT_BUFFER_DESC_OFFSET:
	ADD	BUFFER_INDEX, BUFFER_INDEX, FREE_SPACE_IN_FIFO	
	ADD	BYTE_CNT, BYTE_CNT, FREE_SPACE_IN_FIFO	
	
	LDI	SHIFT_REG, SHIFT_NONE	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_TX_CONTEXT, 20	
	.else
	XOUT	BANK2, &MII_TX_CONTEXT, 20	
	.endif
XMT_NB_DONE:
	JMP		TASK_EXECUTION_FINISHED
process_rx_eof_tx_nb:
	JAL	CALL_REG, FN_RCV_LB	
	
error_in_fill_level:
	.if $isdefed("DEBUG")	
	HALT	
	.else
	;This is debug code, flow doesn't come here if there is no error.
	M_TX_RESET							;Reset the Tx Fifo
	CLR	R23 , R23 , 0 ; clear global flag to indicate the completion of transmission	
	JMP		TASK_EXECUTION_FINISHED
	.endif
	
;****************************************************************************
;
;     NAME			: FN_XMT_LB
;     DESCRIPTION	: transmit the last block of data from the frame in TX FIFO
;     RETURNS		: 
;     ARGS			: 
;     USES 		: 
;     INVOKES 		: 
;
;****************************************************************************
XMT_LB:
	SUB	size, Packet_Length, BYTE_CNT	
	QBEQ	XMT_OVER, size, 0	
	ADD	R11.b0, size, 4	
	QBGE	PUSH_LB_FIFO, R11.b0, FREE_SPACE_IN_FIFO	
	SET	R22 , R22 , 30 
	QBGE	PUSH_LB_FIFO, size, FREE_SPACE_IN_FIFO	
	AND size , FREE_SPACE_IN_FIFO , FREE_SPACE_IN_FIFO
PUSH_LB_FIFO:
	; Check whether BUFFER_INDEX is pointing to the top desc in TX Queue
	QBLE	fetch_data_from_ocmc_lb, TOP_MOST_BUFFER_INDEX, BUFFER_INDEX	
	; Subtract the bytes which have been already transmitted
	SUB	TEMP_REG_3.b0, BUFFER_INDEX, TOP_MOST_BUFFER_INDEX	
	RSB	TEMP_REG_3.b1, TEMP_REG_3.b0, 32	
	QBLE	enough_data_in_top_block_lb, TEMP_REG_3.b1, size	
	AND size , TEMP_REG_3.b1 , TEMP_REG_3.b1
enough_data_in_top_block_lb:
fetch_data_from_ocmc_lb:
	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
;check for collision on wire
	QBBC	NO_COLLISION5, R22, 23	 ;replaced: QBBC    NO_COLLISION5, PORT_IS_HALF_DUPLEX 
	LBCO	&TEMP_REG_1, MII_RT_CFG_CONST, MII_CARRIER_SENSE_REG, 1	
	QBBC	NO_COLLISION5, TEMP_REG_1, 0	 ;replaced: QBBC    NO_COLLISION5, TEMP_REG_1.t0 
	SET	R22 , R22 , 22 
	QBA     COLLISION_DETECTED
NO_COLLISION5:
	.endif ;HALF_DUPLEX_ENABLED
	
	; Check if the RX EOF has come
	.if $isdefed("SOC_AM335x")	
	M_XMT_RX_EOF_CHECK_AM335x	process_rx_eof_tx_lb
	.endif	;SOC_AM335x
	.if $isdefed("SOC_AM571x")	
	M_XMT_RX_EOF_CHECK_AM571x	process_rx_eof_tx_lb
	.endif	;SOC_AM571x
	
	AND R0.b0 , size , size
	LBCO	&BUFFER, L3_OCMC_RAM_CONST, BUFFER_INDEX, b0	
	
	.if $isdefed("SOC_AM335x")	
	LDI	TX_DATA_POINTER, buffer_ptr	
	QBEQ	PUSH_LB_LASTBYTE, size, 1	
	LSR	loop_cnt, size, 1	
	LOOP	EndLoop_LB, loop_cnt	
	MVIW	TX_DATA_WORD, *TX_DATA_POINTER	
	M_PUSH_WORD_CMD
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 2	
EndLoop_LB:
	QBBC	LB_OVER, size, 0	
PUSH_LB_LASTBYTE:
	MVIB	TX_DATA_BYTE, *TX_DATA_POINTER	
	M_PUSH_BYTE
	.endif	;SOC_AM335x
	
	.if $isdefed("SOC_AM571x")	
	LDI	TX_DATA_POINTER, buffer_ptr	
	LSR	loop_cnt, size, 2	;divide by 4
	LOOP	EndLoop_LB, loop_cnt	
	MVID	TX_DATA_DOUBLE_WORD, *TX_DATA_POINTER	
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 4	
EndLoop_LB:
	AND	R20.b0, size, 0x03	; Pick only last two bits
	QBEQ	LB_OVER, R20.b0, 0	
	QBEQ	PUSH_LB_LASTBYTE, R20.b0, 1	
	MVIW	TX_DATA_WORD, *TX_DATA_POINTER	
	ADD	TX_DATA_POINTER, TX_DATA_POINTER, 2	
	QBEQ	LB_OVER, R20.b0, 2	
PUSH_LB_LASTBYTE:
	MVIB	TX_DATA_BYTE, *TX_DATA_POINTER	
	.endif	;SOC_AM571x
	
LB_OVER:
	ADD	BYTE_CNT, BYTE_CNT, size	
	SUB	FREE_SPACE_IN_FIFO, FREE_SPACE_IN_FIFO, size	
	ADD	BUFFER_INDEX, BUFFER_INDEX, size	
	ADD	BYTES_TRANSFERRED_IN_LAST_CALL, BYTES_TRANSFERRED_IN_LAST_CALL, size	
	QBGT	NO_BD_OFFSET_INCR, BYTES_TRANSFERRED_IN_LAST_CALL, 32	
	SUB	BYTES_TRANSFERRED_IN_LAST_CALL, BYTES_TRANSFERRED_IN_LAST_CALL, 32	
	
	QBNE	NO_QUEUE_WRAP_XMT_1, BUFFER_DESC_OFFSET, TOP_MOST_BUFFER_DESC_OFFSET	
	AND     BUFFER_DESC_OFFSET , BASE_BUFFER_DESC_OFFSET , BASE_BUFFER_DESC_OFFSET
	AND     BUFFER_INDEX , BUFFER_OFFSET , BUFFER_OFFSET
	JMP		QUEUE_WRAP_XMT_1
NO_QUEUE_WRAP_XMT_1:
	ADD	BUFFER_DESC_OFFSET, BUFFER_DESC_OFFSET, 4	; working rd_ptr for Tx Queue	
QUEUE_WRAP_XMT_1:
	
NO_BD_OFFSET_INCR:
	;Check whether we have transmitted all the bytes ..if not than call Tx Task again for this packet
	QBBS	no_xmt_over_check, R22, 30	 ;replaced: QBBS	no_xmt_over_check, Entire_Tx_Data_Not_Pushed 
	QBEQ	XMT_OVER, BYTE_CNT, Packet_Length	
no_xmt_over_check:
	CLR	R22 , R22 , 30 
	LDI	SHIFT_REG, SHIFT_NONE	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_TX_CONTEXT, 20	
	.else
	XOUT	BANK2, &MII_TX_CONTEXT, 20	
	.endif
	JMP		TASK_EXECUTION_FINISHED
	
XMT_OVER:
	QBBS	XMT_LB_1OOMbps_MODE, R23, 7	 ;replaced: QBBS	XMT_LB_1OOMbps_MODE, TX_PHY_SPEED 
	QBLE	XMT_LB_1OOMbps_MODE, FREE_SPACE_IN_FIFO, 4	
	JMP	TASK_EXECUTION_FINISHED
XMT_LB_1OOMbps_MODE:
	; Insert the CRC in the outgoing frame
	.if $isdefed("SOC_AM335x")	
	M_XMT_INSERT_CRC_AM335x
	.endif	;SOC_AM335x
	.if $isdefed("SOC_AM571x")	
	M_XMT_INSERT_CRC_AM571x
	.endif	;SOC_AM571x
	
	; Don't allow insertion of next packet in TX Fifo unless it is empty
	CLR	R22 , R22 , 31 
	CLR	R22 , R22 , 30 
	
xmt_save_context:
	
	
	LDI	SHIFT_REG, SHIFT_NONE	
	.if $isdefed("PRU0")	
	XOUT	BANK1, &MII_TX_CONTEXT, 20	
	.else
	XOUT	BANK2, &MII_TX_CONTEXT, 20	
	.endif
	
	; Set the Tx Stat Pend bit
	SET	R23 , R23 , 2 
	
	QBEQ	QUEUE_WRAP_XMT_LB, BYTES_TRANSFERRED_IN_LAST_CALL, 0	
	QBNE	NO_QUEUE_WRAP_XMT_LB, BUFFER_DESC_OFFSET, TOP_MOST_BUFFER_DESC_OFFSET	
	AND     BUFFER_DESC_OFFSET , BASE_BUFFER_DESC_OFFSET , BASE_BUFFER_DESC_OFFSET
	JMP	QUEUE_WRAP_XMT_LB
NO_QUEUE_WRAP_XMT_LB:
	ADD	BUFFER_DESC_OFFSET, BUFFER_DESC_OFFSET, 4	; working rd_ptr for Tx Queue
	
QUEUE_WRAP_XMT_LB:
	
	SBCO	&BUFFER_DESC_OFFSET, PRU_DMEM_ADDR, QUEUE_DESC_OFFSET, 2	; update rd_ptr in the Queue desp.
	
XMT_NOT_FROM_COLLISION_QUEUE:
	
	
SKIP_DESC_UPDATE:
	CLR	R23 , R23 , 0 ; clear global flag to indicate the completion of transmission	
	.if $isdefed("HALF_DUPLEX_ENABLED")	
	QBBC	DO_NOT_UPDATE_COLLISION_STATS, R22, 23	 ;replaced: QBBC    DO_NOT_UPDATE_COLLISION_STATS, PORT_IS_HALF_DUPLEX 
	
	;load collision counter
	LDI	TEMP_REG_1 , COLLISION_COUNTER
	LBCO	&TEMP_REG_2, PRU_DMEM_ADDR, TEMP_REG_1, 1	
	
;Update collision status
	QBLT	UPDATE_MULTIPLE_COLLISION, TEMP_REG_2, 1	
	QBEQ	DO_NOT_UPDATE_COLLISION_STATS, TEMP_REG_2, 0	
	LDI	TEMP_REG_1 , SINGLE_COLLISION_OFFSET
	QBA     ADD_TX_STATS
UPDATE_MULTIPLE_COLLISION:
	QBLT	UPDATE_EXCESS_COLLISION, TEMP_REG_2, 15	
	LDI	TEMP_REG_1 , MULTIPLE_COLLISION_OFFSET
	QBA     ADD_TX_STATS
	
UPDATE_EXCESS_COLLISION:
	LDI	TEMP_REG_1 , EXCESS_COLLISION_OFFSET;Reset counter for collision
	QBA     ADD_TX_STATS
	
DO_NOT_UPDATE_COLLISION_STATS:	
	.endif ;HALF_DUPLEX_ENABLED
	JMP	TASK_EXECUTION_FINISHED
	
process_rx_eof_tx_lb:
	JAL	CALL_REG, FN_RCV_LB	
	
	.endif  ; __mii_xmt_p
