****************************************************************************
*                                                                          *
*                   NIC ETHERNET CONTROLLER RTL8012                        *
*                           LOW LEVEL DRIVER                               *
*                                                                          *
*         Computer: ATARI ST/TT/FALCON                                     *
*         OS      : TOS/MagiC                                              *
*         Language: PASM 68K                                               *
*         Author  : Vassilis Papathanassiou                                *
*         Version : 2.0                                                    *
*         Date    : 16 JUN 1999                                            *
*                                                                          *
****************************************************************************

		EXPORT	NIC_make_table
		EXPORT	RAMtest, Reset, Table
		EXPORT	chk_packet, RxBuffer, getpac, Txpacket
		EXPORT	Set_Ether_ID, Stop_RTL
		IMPORT	address

Chip93C46	equ	0		; let Chip93C46= 0 if use 93C46.
						; let Chip93C46=-1 if use 74S288

OLD_PL		equ 0
OLD_ZOT		equ	0
;**********************************************************************
;
;----------------------------------------------------------------------
;    8 Data Modes are provided (PC only)
;
;	+--------+---------------+-------------+
;	|  Mode  |     Read	 	 |    Write    |
;	+--------+---------------+-------------+
;	|   0	 |   LptCtrl	 |   LptData   |
;	+--------+---------------+-------------+
;	|   1	 |   LptCtrl	 |   LptCtrl   |
;	+--------+---------------+-------------+
;	|   2	 |   LptCtrl*2	 |   LptData   |
;	+--------+---------------+-------------+
;	|   3	 |   LptCtrl*2	 |   LptCtrl   |
;	+--------+---------------+-------------+
;	|   4	 |   LptData	 |   LptData   |
;	+--------+---------------+-------------+
;	|   5	 |   LptData	 |   LptCtrl   |
;	+--------+---------------+-------------+
;	|   6	 |   LptData*2	 |   LptData   |
;	+--------+---------------+-------------+
;	|   7	 |   LptData*2	 |   LptCtrl   |
;	+--------+---------------+-------------+
;	Pin 17 active with $8000
;	Pin	14 active with $2000
;
;**********************************************************************
LF		equ	$0a
CR		equ	$0d

; 8259 commands
;CtrlReg_8259	equ	$20		; 8259 control register
;IMR_8259		equ	$21		; 8259 interrupt mask command
;Read8259IRR	equ	$0a		; read 8259 IRR command
;Read8259ISR	equ	$0b		; read 8259 IMR command
;EOI			equ	$20		; non-specific EOI command
;IRQ5		equ	%00100000	; interrupt bit location
;IRQ7		equ	%10000000	; interrupt bit location

; PAGE 0 of EPLC registers
IDR0		equ	00
IDR1		equ	01
IDR2		equ	02
IDR3		equ	03
IDR4		equ	04
IDR5		equ	05
TBCR0		equ	06
TBCR1		equ	07
TSR		equ	08
RSR		equ	09
ISR		equ	$0A
IMR		equ	$0B
CMR1		equ	$0C
CMR2		equ	$0D
;-------
IF	OLD_ZOT	= 1
	MAR		equ	$0E		; Memory access register
ELSE
	MODSEL		equ	$0E
	MODDEL		equ	$0F
ENDIF
;-------
PNR		equ	TBCR0
COLR		equ	TBCR1

; PAGE 1 of EPLC registers
MAR0		equ	00
MAR1		equ	01
MAR2		equ	02
MAR3		equ	03
MAR4		equ	04
MAR5		equ	05
MAR6		equ	06
MAR7		equ	07
PCMR		equ	TBCR0
PDR		equ	TBCR1

; The followings define remote DMA command through LptCtrl
ATFD			equ	3	; ATFD bit in Lpt's Control register
					; -> ATFD bit is added for Xircom's MUX
Ctrl_LNibRead	equ	08+ATFD		; specify low  nibble
Ctrl_HNibRead	equ	0+ATFD		; specify high nibble
Ctrl_SelData	equ	04+ATFD		; not through LptCtrl but through LptData
Ctrl_IRQEN	equ	$10		; set IRQEN of lpt control register

; Here define constants to construct the required read/write commands
IF	OLD_ZOT	= 1
	WrAddr		equ		$40		; set address of EPLC write register
	RdAddr		equ		$0C0
ELSE
	WrAddr		equ		$C0		; set address of EPLC write register
	RdAddr		equ		$40		; set address of EPLC read register
ENDIF
EOR			equ		$020		; ORed to make 'end of read',set CSB=1
EOW			equ		$0E0		; end of write, R/WB=A/DB=CSB=1
EOC			equ		$0E0		; End Of r/w Command, R/WB=A/DB=CSB=1
HNib		equ		$10

; EPLC register contents
EPLC_RBER	equ	01		; ISR, HNib
EPLC_ROK	equ	04		; ISR
EPLC_TER	equ	02		; ISR
EPLC_TOK	equ	01		; ISR

EPLC_POV	equ	04		; RSR, HNib
EPLC_BUFO	equ	01		; RSR, HNib

EPLC_RST	equ	04		; CMR1, HNib
EPLC_RxE	equ	02		; CMR1, HNib
EPLC_TxE	equ	01		; CMR1, HNib
EPLC_RETX	equ	08		; CMR1
EPLC_TRA	equ	04		; CMR1
EPLC_IRQ	equ	02		; CMR1
WRPAC		equ 02		; CMR1	16/8/95
RDPAC		equ	01		; CMR1	16/8/95
EPLC_BUFE	equ	01		; CMR1
EPLC_JmpPac	equ	EPLC_BUFE	; RTL 8002 only

EPLC_AM1		equ	02			; CMR2, HNib
EPLC_AM0		equ	01			; CMR2, HNib
EPLC_PAGE		equ	04			; CMR2
IF	OLD_ZOT	= 1
	EPLC_RAMTST		equ	02+8
ELSE
	EPLC_RAMTST		equ	02		; CMR2
	EPLC_LOOPBK		equ	04		; CMR2
ENDIF
EPLC_IRQOUT		equ	01		; CMR2	< May 11, 8012 >
EPLC_CMR2Null	equ	00		; CMR2	< May 11, 8012 >

EPLC_AddrMode	equ	02		; accept physical & broadcast packets
							; reject error packets
RxMode			equ	HNib+EPLC_AddrMode

RxCount			equ	2
IF	OLD_ZOT = 1
	RxStatus		equ	4
	RxMSB			equ	3
	RxLSB			equ	2
ELSE
	RxStatus		equ	5
	RxMSB			equ	4
	RxLSB			equ	3
ENDIF
_hz_200           EQU $4BA
;-------------------------------------------------------------------------
;	Wait tick no of ms
;-------------------------------------------------------------------------
MACRO slowly tick
	LOCAL	loop
	move.w	sr,d1
	move.w 	#$2300,SR
	move.l	_hz_200.W,d0
	add.w	#tick,d0
loop:
	cmp.l	_hz_200.W,d0
	bpl.s	loop
	move.w	d1,SR
ENDM
;-------------------------------------------------------------------------
;	Look up table
;-------------------------------------------------------------------------
MACRO LUP
	add.w	d2,d2
	IF	OLD_PL = 0
		move.w	(LUT,d2.w),d2
	ENDIF
ENDM
;-------------------------------------------------------------------------
;	Parallel port control signals macros
;-------------------------------------------------------------------------
MACRO P14_16_17_UP
	lea		$FBE000,a5		;DMACSB,INITB,CLK up ie P14,P17,P17 up
	move.b	(a5),d0
ENDM

MACRO CSB_DN_CLK_UP
	lea 	$FB2000,a5		;DMACSB down, INITB,CLK up
	move.b	(a5),d0
ENDM

;-------------------------------------------------------------------------
;	To read a nibble from 'rreg' register.
;	> 'End Of Read' command is not issued
;	> used for general register read
;
;	entry : rreg must be defined as a constant
;
;	exit  : d0 <- readen nibble
;
;-------------------------------------------------------------------------
MACRO RdNib	rreg
	move.w	#EOC+rreg,d2
	LUP
	move.b	(CAL,d2.w),d2

	move.w	#RdAddr+rreg,d2
	LUP
	move.w	(CAL,d2.w),d0
	move.w	(CAL),d0		; Read nib
IF	OLD_PL = 1
	lsr.w	#3,d0
ENDIF
	andi.w	#$F,d0
ENDM

MACRO RdBytEP
	move.w	(CAL),d0
	andi.w	#$0F,d0			; get lo nib

	move.b	(FB0),d2		; CLK down
	nop
	move.w	(CAL),d1		; get hi nib
	lsl.b	#4,d1
;	andi.b	#$F0,d1
	or.b	d1,d0
	nop
	lea 	$FB2000,a5		;CLK up
	move.b	(a5),d2
ENDM

;-------------------------------------------------------------------------
;	To write a nibble to one register.
;	> wreg must be a constant
;	> The nibble maybe constant, register or memory
;	> 'End Of Write' is issued.
;	> used for general register write
;-------------------------------------------------------------------------
MACRO WrNib wreg,wdata
	move.w	wreg,d2
	move.w	d2,d3			; save
	ori.w	#EOC,d2
	LUP
	move.b	(CAL,d2.w),d2	; Output end_of_write

	move.w	d3,d2
	ori.w	#WrAddr,d2
	move.w	d2,d3
	LUP
	move.b	(CAL,d2.w),d2	; Prepare address

	move.w	d3,d2
	and.w	#$00F0,d2
	or.w	wdata,d2
	LUP
	move.b	(CAL,d2.w),d2	; Write address

	move.w	wdata,d2
	add.w	#$80,d2
	move.w	d2,d3
	LUP
	move.b	(CAL,d2.w),d2	; Write data

	move.w	d3,d2
	or.b	#EOC,d2
	LUP
	move.b	(CAL,d2.w),d2	; End Of Write
ENDM
MACRO WrByte wreg,wdata
	move.w	wreg,d2
	ori.w	#EOC,d2
	LUP
	move.b	(CAL,d2.w),d2	; Output end_of_write

	move.w	wreg,d2
	ori.w	#WrAddr,d2
	move.w	d2,d3			; Save
	LUP
	move.b	(CAL,d2.w),d2	; Write address

	move.w	d3,d2
	and.w	#$00F0,d2
	move.w	wdata,d3
	andi.w	#$000F,d3
	or.w	d3,d2
	LUP
	move.b	(CAL,d2.w),d2	; Prepare low nib

	move.w	d3,d2
	add.w	#$80,d2
	LUP
	move.b	(CAL,d2.w),d2	; Write low nib
; ------>
	move.w	wreg,d2
	ori.w	#WrAddr+HNib,d2
	move.w	d2,d3			; Save
	LUP
	move.b	(CAL,d2.w),d2	; Write address hi-nib

	move.w	d3,d2
	andi.w	#$00F0,d2
	move.w	wdata,d3
	lsr.w	#4,d3
	or.w	d3,d2
	LUP
	move.b	(CAL,d2.w),d2	; Prepare hi-nib

	move.w	d3,d2
	ori.w	#$80+HNib,d2
	move.w	d2,d3
	LUP
	move.b	(CAL,d2.w),d2	; Write high nib

	move.w	d3,d2
	ori.w	#EOC,d2
;	and.b	#$7F,d2
	LUP
	move.b	(CAL,d2.w),d2	; End of write
ENDM

MACRO WrEPWordd1ToDRAM
	divs	d0,d0
	move.w	d1,d2		;1st byte
	lsr.w	#8,d2
	and.w	#$FF,d2
	LUP
	move.b	(CAL,d2.w),d2

	move.b	(FB0),d0	;CLK down

	move.w	d1,d2		;2nd byte
	and.w	#$FF,d2
	LUP
	move.b	(CAL,d2.w),d2

	move.w	#$2000,d0	;CLK up
	move.b	(FB0,d0.w),d0
ENDM

MACRO WrEPByted1ToDRAM
	move.w	d1,d2		;1st byte
	and.w	#$FF,d2
	LUP
	move.b	(CAL,d2.w),d2

	move.w	#$2000,d0	;CLK up/down
	eor.w	d0,d4
	move.b	(FB0,d4.w),d0
ENDM
;-------------------------------------------------------------------------

          TEXT
          SUPER

STACK		=    A0
CAL			=    A1
LUT			=    A2
FB0			=	 A4

****************************************************************************

Reset:
	lea		$FA0000,CAL
	lea		$FB0000,FB0
	lea		Table,LUT
	P14_16_17_UP

IF	OLD_ZOT	= 0
	WrNib	#MODSEL,#0
	WrNib	#MODSEL+HNib,#HNib+2
	RdNib	MODSEL+HNib
	cmpi.b	#2,d0
	beq.s	do_reset
	moveq	#0,d0
	rts
ENDIF
do_reset:
	WrNib	#CMR1+HNib, #HNib+EPLC_RST
	slowly	10
wait_reset:
	RdNib	CMR1+HNib		; must be 1
	btst	#2,d0
	bne.s	wait_reset		; Reset not finished
	nop
	WrNib	#ISR, #EPLC_ROK+EPLC_TER+EPLC_TOK  ;Clear ISR
	WrNib	#ISR+HNib, #HNib+EPLC_RBER

	RdNib	CMR2+HNib	;must be 2 (EPLC_AM1)
	nop
	nop
	WrNib	#CMR2+HNib, #RxMode
	WrNib	#CMR1+HNib, #HNib+EPLC_RxE+EPLC_TxE		; enable Rx & Tx

	moveq	#1,d0
	rts

;--------------------------------------------------------------------------
; Set an Ethernet Address to IDR0-5 registers and mask 0xFFFFFFFF multicast
;--------------------------------------------------------------------------
Set_Ether_ID:
	movem.l	a2-a5/d3-d7,-(sp)
	lea		$FA0000,CAL
	lea		Table,LUT

	lea 	address,a3
	move.w	#IDR0,d0
	moveq	#0,d5
	moveq	#5,d7
next_ID:
	move.b	(a3)+,d5
	WrByte	d0,d5
	addq	#1,d0
	dbf 	d7,next_ID

; Now set NIC to accept broadcast

	WrNib	#CMR2,#EPLC_PAGE		; point to page 1
	move.w	#MAR0,d0
	move.l	#$000000FF,d5
	moveq	#7,d7
next_mask:
	WrByte	d0,d5
	addq	#1,d0
	dbf 	d7,next_mask
	WrNib  #CMR2, #EPLC_CMR2Null	; back to page 0

	movem.l	(a7)+,a2-a5/d3-d7
	rts

; void Stop_RTL (void)
; Stop the adapter from receiving packets
; --------------------------------------------------------------
Stop_RTL:
	movem.l	a2-a5/d3-d7,-(sp)
	lea		$FA0000,CAL
	lea		Table,LUT
	WrNib	#CMR2+HNib, #HNib		; Set 'No Acception'
	WrNib	#CMR1+HNib, #HNib		; disable Tx & Rx
	movem.l	(a7)+,a2-a5/d3-d7
	rts
; ======================= Packet Transmition ===================
; - Input
; A0 = packet buffer from STinG
; D0 = Number of bytes to transmit
; - Returns:
; Nothing!
; ======================= Packet Transmition ===================
wait_txcomplete:
	RdNib	CMR1
	btst	#2,d0
	bne.s	wait_txcomplete
	move.w	#2,tx_page_cnt
	clr.w	TxInProgress
	bra 	proceed_tx

Txpacket:
	movem.l	a2-a5/d3-d7,-(a7)
	lea		$FA0000,CAL
	lea		$FB0000,FB0
	lea		Table,LUT
	move.w	d0,d6			; save count
	move.w	d0,d7
	subq	#1,d7			; -1 for dbf

	P14_16_17_UP
	RdNib	CMR1
	btst	#2,d0			; still transmitting ?
	beq.s	proceed_tx
check_page:
	move.w	tx_page_cnt(PC),d0
	subq	#1,d0
	beq 	wait_txcomplete	; No xmit pages left
	move.w	#1,TxInProgress	; check later

proceed_tx:
;	WrNib	#MODSEL,#0				;Mode A
	WrNib	#MODSEL+HNib,#HNib+3	;Mode C to Write packet
	CSB_DN_CLK_UP
	REPT 4
	nop
	ENDM
	move.w	#$2000,d4			;set clock value (clock up)
PacktWrite:
	move.b	(a0)+,d1
	WrEPByted1ToDRAM
	dbf		d7,PacktWrite
	nop
	nop
	P14_16_17_UP				;Set CLK & P17 high
	WrNib	#CMR1,#WRPAC

	move.w	TxInProgress(PC),d0
	beq.s	set_TRA				; else we have to wait
wait_tx2:
	RdNib	CMR1
	btst	#2,d0
	bne.s	wait_tx2
	clr.w	TxInProgress
	addq	#1,tx_page_cnt
set_TRA:
;-- Now write packet length and init transmission
	move.w	d6,d5
	andi.w	#$00FF,d5
	WrByte	#TBCR0,d5
	lsr.w	#8,d6
	WrNib	#TBCR1,d6
	WrNib	#CMR1,#EPLC_TRA		;start transmission

;	RdNib	TSR					; Read Transmit Status Reg. (no need !)
no_TRA_exit:
	movem.l	(a7)+,a2-a5/d3-d7
	rts

; END OF TRANSMITION
; -------------------------- Buffer Overflow ----------------------------
; - Input: Nothing
; - Returns: Nothing
; -----------------------------------------------------------------------
Buff_overflow:
	WrNib	#CMR2+HNib, #HNib 		;EPLC BufferOverflow Handle process
									;Configure "no acception" mode.
	WrNib	#ISR+HNib, #HNib+EPLC_RBER	;11/6/99
	move.w	#1,overfl_flag
	bra 	read_packet

; ----------------------- Checking Packet arrival -----------------------
; - Input: Nothing
; - Returns:
; Yes or No in D0
; -----------------------------------------------------------------------

chk_packet:
	movem.l	a2/a4,-(sp)
	lea		$FA0000,CAL
	lea		Table,LUT
	RdNib	CMR1
	movem.l	(sp)+,a2/a4
	btst	#0,d0
	beq.s	have_pack
	clr.l	d0
	rts
have_pack:
	moveq	#1,d0
	rts

; ------------------------- Packet reception ----------------------------
; - Input: Nothing
; - Returns:
; Number of readen bytes in D0
; -----------------------------------------------------------------------

getpac:
	movem.l	a2-a5/d3-d7,-(sp)
	lea		$FA0000,CAL
	lea		$FB0000,FB0
	lea		Table,LUT
	RdNib	CMR1
	btst	#1,d0
	bne 	Buff_overflow
read_packet:
	WrNib	#CMR1,#RDPAC
	WrNib	#MODSEL,#0
	WrNib	#MODSEL+HNib,#HNib+1		;switch to RD0-3
	CSB_DN_CLK_UP
	REPT 4
	 nop
	ENDM
	moveq	#8-1,d7
	lea		RxBuffer,a3
	clr.l	d6
LookAhead:
	RdBytEP
	move.b	d0,(a3)+
	dbf		d7,LookAhead

	lea		RxBuffer,a3
;	move.b	RxStatus(a3),d0
	move.b	RxMSB(a3),d0
	lsl.w	#8,d0
	move.b	RxLSB(a3),d0
	move.w	d0,d7
	cmpi.w	#8,d7
	blt		exit_rcv
	cmpi.w	#2048,d7
	blt.s	normal_packet
	move.w	#1536+4,d7		; A full ethernet packet plus CRC
normal_packet:
	subq	#4,d7			; 4 CRC + 1 for dbf
	move.w	d7,d6			; Save for return
	subq	#1,d7			; -1 for dbf
	lea		RxBuffer,a3
	addq	#8,a3
Rdpack:
	RdBytEP
	move.b	d0,(a3)+
	dbf		d7,Rdpack

	P14_16_17_UP
exit_rcv:
	tst.w	overfl_flag
	beq.s	recv_ret
	clr.w	overfl_flag
	WrNib	#CMR2+HNib, #RxMode					;Accept all packets
recv_ret:
	move.w	d6,d0
	movem.l	(sp)+, a2-a5/d3-d7
	rts

*-------------------------------------------------------------------------

RAMtest:
	lea		$FA0000,CAL
	lea		$FB0000,FB0
	lea		Table,LUT
	P14_16_17_UP
	WrNib	#MODSEL,#0			;Mode A
	WrNib	#MODDEL,#0			;0-450ns
	WrNib	#CMR1+HNib, #HNib				;1.disable Tx & Rx
	WrNib	#CMR2, #EPLC_RAMTST				;2.enter RAM test mode
	WrNib	#CMR1+HNib, #HNib				;3.disable Tx & Rx
	WrNib	#CMR1+HNib,#HNib+EPLC_RxE+EPLC_TxE ;4.enable Tx & Rx
	RdNib	CMR1+HNib

	WrNib	#MODSEL+HNib,#HNib+3	;Mode C to Write test pattern

	CSB_DN_CLK_UP
	slowly	1
	move.w	#28-1,d7
	lea		RAMTestPattern,a3
RAMTest2Write:
	move.w	(a3)+,d1
	WrEPWordd1ToDRAM
	dbf		d7,RAMTest2Write

	P14_16_17_UP
	slowly	1					;Set CLK & P17 high
	WrNib	#CMR1, #WRPAC
	slowly	1					;Set CLK & P17 high
	WrNib	#MODSEL,#0			;Mode A
	WrNib	#CMR1+HNib, #HNib					;6.disable Tx & Rx
	WrNib	#CMR1+HNib,#HNib+EPLC_RxE+EPLC_TxE	;7.enable Tx & Rx
	RdNib	CMR1+HNib
	WrNib	#CMR1, #RDPAC
	CSB_DN_CLK_UP
	WrNib	#MODSEL+HNib,#HNib+1	;Read

	move.w	#28-1,d7			;+1 for 4 trivial reads
	lea		VerifyPattern,a3
	moveq	#0,d6

RAMTest2Read:
	RdBytEP
	lsl.w	#8,d0
	move.w	d0,d6
	RdBytEP
	or.w	d0,d6
	move.w	d6,(a3)+
	dbf		d7,RAMTest2Read
	nop
	nop
	P14_16_17_UP

	WrNib	#CMR1+HNib, #HNib			; 9.disable Tx & Rx
										; before leaving RAM test mode
	WrNib  #CMR2, #EPLC_CMR2Null		; 10.leave RAM test mode

	WrNib	#CMR1+HNib,#HNib+EPLC_RxE+EPLC_TxE	;Enable Rx TEST ONLY!!!
	WrNib	#CMR2+HNib, #RxMode					;Accept physical and broadcast

	lea 	VerifyPattern,a3
	lea 	RAMTestPattern,a4
	move.w	#20-1,d7
cmp_loop:
	cmpm.w	(a4)+,(a3)+
	dbne	d7,cmp_loop
	cmpi.w	#-1,d7
	beq.s	test_ok
	clr.l	d0
	rts
test_ok:
	moveq	#1,d0
	rts


NIC_make_table:
	lea		Table,a1
	move.w	#0,d0
	move.w	#255,d2
Tloop:
	moveq	#0,d1
	btst	#0,d0
	beq.s	no_A8
	bset	#8,d0
no_A8:
	add.w	d0,d1
	bclr	#0,d1
	move.w	d1,(a1)+
	bclr	#8,d0
	addq.w	#1,d0
	dbra	d2,Tloop
	rts

DATA
overfl_flag:	dc.w	0
tx_page_cnt:	dc.w	2
TxInProgress:	dc.w	0
ContNoECB:		dc.w	0
NoECBFlag:		dc.w	0

RAMTestPattern:	dc.b	'RTL8012 REALTEK"s Ethernet Pocket LAN Controller'
				dc.b	$5A, $3C, $78, $0F0, $0A5, $0C3, $87, $0F
				dcb.b	10,0

BSS
Table:
				ds.w	256
RxBuffer:
				ds.b	2048
VerifyPattern:
				ds.b	128
