1124 lines
23 KiB
NASM
Executable File
1124 lines
23 KiB
NASM
Executable File
; ------------------------------------------------------------------------------
|
|
; | SPI Lowlevel Access to SD-Card slot of Vampire 500/600 cards |
|
|
; | Henryk Richter <henryk.richter@gmx.net> |
|
|
; ------------------------------------------------------------------------------
|
|
;
|
|
; Note: This code is in some places intentionally saving more registers than
|
|
; required by the AmigaOS ABI.
|
|
;
|
|
ifnd _LVOSignal
|
|
_LVOSignal EQU -324
|
|
endc
|
|
|
|
; enable debugging code block
|
|
DEBUG EQU 0
|
|
;
|
|
_OPT_CFGSPEED_BYTE EQU 0 ;write SPI clock divider as byte (1) or word (0)
|
|
_OPT_WriteOp_Delay EQU 0 ;delay after writeOp (1) or no delay (0)
|
|
_OPT_READ_CONST EQU $ff ;output bits in read mode (default 0xff, for testing 0x00)
|
|
_OPT_SHORT_DELAY EQU 1 ;small delays by a single CIA read
|
|
;
|
|
;
|
|
; SPI Hardware dependent routines
|
|
;
|
|
;
|
|
;lowlevel register read/write
|
|
XDEF _enc28j60l_ReadOp
|
|
XDEF _enc28j60l_WriteOp
|
|
|
|
;write buffer, read buffer
|
|
XDEF _enc28j60l_ReadBuffer
|
|
XDEF _enc28j60l_WriteBuffer
|
|
|
|
; of these, only SPISpeed bangs the hardware
|
|
XDEF _enc28j60l_Init
|
|
XDEF _enc28j60l_Shutdown
|
|
XDEF _enc28j60l_SetSPISpeed
|
|
|
|
ifd PROTO_V2EXPNET
|
|
; interrupt stuff, used only with V2EXPETH right now
|
|
XDEF _enc28j60l_IntServer_List
|
|
XDEF _enc28j60l_EnableInterrupt
|
|
XDEF _enc28j60l_DisableInterrupt
|
|
endc
|
|
;
|
|
;
|
|
; hardware support functions without SPI register banging
|
|
; (moved into ASM source to have easy debugging in ASM-One)
|
|
;
|
|
;
|
|
;read/write one 8 Bit Register
|
|
XDEF _enc28j60l_ReadRegByte
|
|
XDEF _enc28j60l_WriteRegByte
|
|
;
|
|
XDEF _enc28j60l_SetBank
|
|
|
|
;read/write one 16 Bit Register
|
|
XDEF _enc28j60l_ReadReg
|
|
XDEF _enc28j60l_WriteReg
|
|
|
|
;delay min. D0 microseconds
|
|
XDEF _enc28j60l_UMinDelay
|
|
|
|
;machine 68020
|
|
|
|
; section code,code
|
|
|
|
; Register definitions (used only in Debug mode so far)
|
|
;
|
|
ADDR_MASK EQU $1F
|
|
BANK_MASK EQU $60
|
|
SPRD_MASK EQU $80
|
|
BANK23_MASK EQU $40
|
|
|
|
;// All-bank registers
|
|
EIE EQU $1B
|
|
EIR EQU $1C
|
|
ESTAT EQU $1D
|
|
ECON2 EQU $1E
|
|
ECON1 EQU $1F
|
|
;// Bank 0 registers
|
|
ERDPT EQU ($00|$00)
|
|
EWRPT EQU ($02|$00)
|
|
ETXST EQU ($04|$00)
|
|
ETXND EQU ($06|$00)
|
|
ERXST EQU ($08|$00)
|
|
ERXND EQU ($0A|$00)
|
|
ERXRDPT EQU ($0C|$00)
|
|
;// ERXWRPT ($0E|$00)
|
|
EDMAST EQU ($10|$00)
|
|
EDMAND EQU ($12|$00)
|
|
;// EDMADST ($14|$00)
|
|
EDMACS EQU ($16|$00)
|
|
;// Bank 1 registers
|
|
EHT0 EQU ($00|$20)
|
|
EHT1 EQU ($01|$20)
|
|
EHT2 EQU ($02|$20)
|
|
EHT3 EQU ($03|$20)
|
|
EHT4 EQU ($04|$20)
|
|
EHT5 EQU ($05|$20)
|
|
EHT6 EQU ($06|$20)
|
|
EHT7 EQU ($07|$20)
|
|
EPMM0 EQU ($08|$20)
|
|
EPMM1 EQU ($09|$20)
|
|
EPMM2 EQU ($0A|$20)
|
|
EPMM3 EQU ($0B|$20)
|
|
EPMM4 EQU ($0C|$20)
|
|
EPMM5 EQU ($0D|$20)
|
|
EPMM6 EQU ($0E|$20)
|
|
EPMM7 EQU ($0F|$20)
|
|
EPMCS EQU ($10|$20)
|
|
EWOLIE EQU ($16|$20)
|
|
EWOLIR EQU ($17|$20)
|
|
ERXFCON EQU ($18|$20)
|
|
EPKTCNT EQU ($19|$20)
|
|
;// Bank 2 registers
|
|
MACON1 EQU ($00|$40|$80)
|
|
MACON2 EQU ($01|$40|$80)
|
|
MACON3 EQU ($02|$40|$80)
|
|
MACON4 EQU ($03|$40|$80)
|
|
MABBIPG EQU ($04|$40|$80)
|
|
MAIPG EQU ($06|$40|$80)
|
|
MACLCON1 EQU ($08|$40|$80)
|
|
MACLCON2 EQU ($09|$40|$80)
|
|
MAMXFL EQU ($0A|$40|$80)
|
|
MAPHSUP EQU ($0D|$40|$80)
|
|
MICON EQU ($11|$40|$80)
|
|
MICMD EQU ($12|$40|$80)
|
|
MIREGADR EQU ($14|$40|$80)
|
|
MIWR EQU ($16|$40|$80)
|
|
MIRD EQU ($18|$40|$80)
|
|
;// Bank 3 registers
|
|
MAADR1 EQU ($00|$60|$80)
|
|
MAADR0 EQU ($01|$60|$80)
|
|
MAADR3 EQU ($02|$60|$80)
|
|
MAADR2 EQU ($03|$60|$80)
|
|
MAADR5 EQU ($04|$60|$80)
|
|
MAADR4 EQU ($05|$60|$80)
|
|
EBSTSD EQU ($06|$60)
|
|
EBSTCON EQU ($07|$60)
|
|
EBSTCS EQU ($08|$60)
|
|
MISTAT EQU ($0A|$60|$80)
|
|
EREVID EQU ($12|$60)
|
|
ECOCON EQU ($15|$60)
|
|
EFLOCON EQU ($17|$60)
|
|
EPAUS EQU ($18|$60)
|
|
|
|
BANK23REG EQU $40 ;used to check for MII and MAC registers
|
|
|
|
ifne 0
|
|
|
|
;// ENC28J60 ERXFCON Register Bit Definitions
|
|
ERXFCON_UCEN $80
|
|
ERXFCON_ANDOR $40
|
|
ERXFCON_CRCEN $20
|
|
ERXFCON_PMEN $10
|
|
ERXFCON_MPEN $08
|
|
ERXFCON_HTEN $04
|
|
ERXFCON_MCEN $02
|
|
ERXFCON_BCEN $01
|
|
;// ENC28J60 EIE Register Bit Definitions
|
|
EIE_INTIE $80
|
|
EIE_PKTIE $40
|
|
EIE_DMAIE $20
|
|
EIE_LINKIE $10
|
|
EIE_TXIE $08
|
|
EIE_WOLIE $04
|
|
EIE_TXERIE $02
|
|
EIE_RXERIE $01
|
|
;// ENC28J60 EIR Register Bit Definitions
|
|
EIR_PKTIF $40
|
|
EIR_DMAIF $20
|
|
EIR_LINKIF $10
|
|
EIR_TXIF $08
|
|
EIR_WOLIF $04
|
|
EIR_TXERIF $02
|
|
EIR_RXERIF $01
|
|
|
|
endc
|
|
|
|
;// ENC28J60 ESTAT Register Bit Definitions
|
|
ESTAT_INT EQU $80
|
|
ESTAT_LATECOL EQU $10
|
|
ESTAT_RXBUSY EQU $04
|
|
ESTAT_TXABRT EQU $02
|
|
ESTAT_CLKRDY EQU $01
|
|
;// ENC28J60 ECON2 Register Bit Definitions
|
|
ECON2_AUTOINC EQU $80
|
|
ECON2_PKTDEC EQU $40
|
|
ECON2_PWRSV EQU $20
|
|
ECON2_VRPS EQU $08
|
|
;// ENC28J60 ECON1 Register Bit Definitions
|
|
ECON1_TXRST EQU $80
|
|
ECON1_RXRST EQU $40
|
|
ECON1_DMAST EQU $20
|
|
ECON1_CSUMEN EQU $10
|
|
ECON1_TXRTS EQU $08
|
|
ECON1_RXEN EQU $04
|
|
ECON1_BSEL1 EQU $02
|
|
ECON1_BSEL0 EQU $01
|
|
|
|
ifne 0
|
|
;// ENC28J60 MACON1 Register Bit Definitions
|
|
MACON1_LOOPBK $10
|
|
MACON1_TXPAUS $08
|
|
MACON1_RXPAUS $04
|
|
MACON1_PASSALL $02
|
|
MACON1_MARXEN $01
|
|
;// ENC28J60 MACON2 Register Bit Definitions
|
|
MACON2_MARST $80
|
|
MACON2_RNDRST $40
|
|
MACON2_MARXRST $08
|
|
MACON2_RFUNRST $04
|
|
MACON2_MATXRST $02
|
|
MACON2_TFUNRST $01
|
|
;// ENC28J60 MACON3 Register Bit Definitions
|
|
MACON3_PADCFG2 $80
|
|
MACON3_PADCFG1 $40
|
|
MACON3_PADCFG0 $20
|
|
MACON3_TXCRCEN $10
|
|
MACON3_PHDRLEN $08
|
|
MACON3_HFRMLEN $04
|
|
MACON3_FRMLNEN $02
|
|
MACON3_FULDPX $01
|
|
;// ENC28J60 MICMD Register Bit Definitions
|
|
MICMD_MIISCAN $02
|
|
MICMD_MIIRD $01
|
|
;// ENC28J60 MISTAT Register Bit Definitions
|
|
MISTAT_NVALID $04
|
|
MISTAT_SCAN $02
|
|
MISTAT_BUSY $01
|
|
|
|
;// ENC28J60 EBSTCON Register Bit Definitions
|
|
EBSTCON_PSV2 $80
|
|
EBSTCON_PSV1 $40
|
|
EBSTCON_PSV0 $20
|
|
EBSTCON_PSEL $10
|
|
EBSTCON_TMSEL1 $08
|
|
EBSTCON_TMSEL0 $04
|
|
EBSTCON_TME $02
|
|
EBSTCON_BISTST $01
|
|
|
|
;// PHY registers
|
|
PHCON1 $00
|
|
PHSTAT1 $01
|
|
PHHID1 $02
|
|
PHHID2 $03
|
|
PHCON2 $10
|
|
PHSTAT2 $11
|
|
PHIE $12
|
|
PHIR $13
|
|
PHLCON $14
|
|
|
|
;// ENC28J60 PHY PHCON1 Register Bit Definitions
|
|
PHCON1_PRST $8000
|
|
PHCON1_PLOOPBK $4000
|
|
PHCON1_PPWRSV $0800
|
|
PHCON1_PDPXMD $0100
|
|
;// ENC28J60 PHY PHSTAT1 Register Bit Definitions
|
|
PHSTAT1_PFDPX $1000
|
|
PHSTAT1_PHDPX $0800
|
|
PHSTAT1_LLSTAT $0004
|
|
PHSTAT1_JBSTAT $0002
|
|
;// ENC28J60 PHY PHCON2 Register Bit Definitions
|
|
PHCON2_FRCLINK $4000
|
|
PHCON2_TXDIS $2000
|
|
PHCON2_JABBER $0400
|
|
PHCON2_HDLDIS $0100
|
|
|
|
;// ENC28J60 Packet Control Byte Bit Definitions
|
|
PKTCTRL_PHUGEEN $08
|
|
PKTCTRL_PPADEN $04
|
|
PKTCTRL_PCRCEN $02
|
|
PKTCTRL_POVERRIDE $01
|
|
|
|
|
|
endc
|
|
|
|
;// SPI operation codes
|
|
ENC28J60_READ_CTRL_REG EQU $00
|
|
ENC28J60_READ_BUF_MEM EQU $3A
|
|
ENC28J60_WRITE_CTRL_REG EQU $40
|
|
ENC28J60_WRITE_BUF_MEM EQU $7A
|
|
ENC28J60_BIT_FIELD_SET EQU $80
|
|
ENC28J60_BIT_FIELD_CLR EQU $A0
|
|
ENC28J60_SOFT_RESET EQU $FF
|
|
|
|
RXSTART_INIT EQU $0000 // start of RX buffer, room for 4 packets
|
|
RXSTOP_INIT EQU $19FF // end of RX buffer
|
|
|
|
TXSTART_INIT EQU $1A00 // start of TX buffer, room for 1 packet
|
|
TXSTOP_INIT EQU $1FFF // end of TX buffer
|
|
|
|
;// max frame length which the conroller will accept:
|
|
;// (note: maximum ethernet frame length would be 1518)
|
|
MAX_FRAMELEN EQU 1518
|
|
|
|
|
|
;Amiga custom registers
|
|
OCS_VHPOSR EQU $DFF006
|
|
|
|
;
|
|
;
|
|
;// Vampire SDCard Registers
|
|
;
|
|
;
|
|
ifd PROTO_V2EXPNET
|
|
SDCARD_DATA_W EQU $00DE0010
|
|
SDCARD_DATA_R EQU $00DE0010
|
|
SDCARD_CFG_W EQU $00DE0014
|
|
SDCARD_STATUS_R EQU $00DE0016
|
|
SDCARD_CFG_SPEED EQU $00DE001C
|
|
SDCARD_INT_ENABLE EQU $00DE0018
|
|
else ;PROTO_V2EXPNET
|
|
; PROTO_SDNET
|
|
SDCARD_DATA_W EQU $00DE0000
|
|
SDCARD_DATA_R EQU $00DE0000
|
|
SDCARD_CFG_W EQU $00DE0004
|
|
SDCARD_STATUS_R EQU $00DE0006
|
|
SDCARD_CFG_SPEED EQU $00DE000C
|
|
SDCARD_INT_ENABLE EQU $00DE0008
|
|
endc ;PROTO_V2EXPNET
|
|
|
|
SDCARD_SPEED EQU $20 ;this one is obsolete
|
|
SDCARD_CS EQU $1
|
|
SDCARD_CSn EQU $0
|
|
|
|
|
|
CSDELAY macro
|
|
ifne _OPT_SHORT_DELAY
|
|
tst.w $DFF00A ;1 chipset access 560ns
|
|
;tst.b $BFE301 ;1 CIA access = 1.4 us
|
|
endc
|
|
endm
|
|
|
|
|
|
SPI_ENABLE macro
|
|
;lea.l SDCARD_CFG_W,a0
|
|
;move.w #SDCARD_CSn+SDCARD_SPEED,(a0)
|
|
move.w #SDCARD_CSn+SDCARD_SPEED,SDCARD_CFG_W
|
|
endm
|
|
|
|
SPI_DISABLE macro
|
|
;lea.l SDCARD_CFG_W,a0
|
|
;move.w #SDCARD_CS+SDCARD_SPEED,(a0)
|
|
move.w #SDCARD_CS+SDCARD_SPEED,SDCARD_CFG_W
|
|
endm
|
|
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; | |
|
|
; | Test/Debug code |
|
|
; | |
|
|
; ------------------------------------------------------------------------------
|
|
ifne DEBUG
|
|
|
|
ExecBase EQU 4 ; Exec.Base()
|
|
OpenLibrary EQU -552 ; D0:libBase = Exec.OpenLibrary(A1:libName,D0:version)
|
|
CloseLibrary EQU -414 ; Exec.CloseLibrary(A1:libBase)
|
|
PutStr EQU -948 ; DOS.PutStr(D1:str)
|
|
_LVODelay EQU -198
|
|
|
|
START:
|
|
opendos:
|
|
move.l ExecBase,a6
|
|
lea DosLibrary,a1
|
|
moveq #0,d0
|
|
jsr OpenLibrary(a6)
|
|
tst.l d0
|
|
beq error
|
|
move.l d0,a6
|
|
|
|
moveq #0,d7 ;no error
|
|
|
|
; bsr cardCSn
|
|
; bsr cardCS
|
|
; bsr cardCSn
|
|
|
|
;
|
|
;_enc28j60l_WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
|
;
|
|
move.b #ENC28J60_SOFT_RESET,d3
|
|
move.b #0,d0
|
|
move.b #ENC28J60_SOFT_RESET,d1
|
|
bsr _enc28j60l_WriteOp
|
|
|
|
;delay 1/50s = 20ms (2ms would be sufficient)
|
|
moveq #1,d1
|
|
jsr _LVODelay(a6)
|
|
|
|
move #$fff,d2
|
|
|
|
move.b #ENC28J60_READ_CTRL_REG,d3
|
|
move.b #ESTAT,d0
|
|
bsr _enc28j60l_ReadOp
|
|
|
|
and.b #ESTAT_CLKRDY,d0 ; (=1)
|
|
bne.s .foundrdy
|
|
dbf d2,.loop
|
|
or.b #1,d7 ;searchtest error
|
|
.foundrdy
|
|
|
|
|
|
|
|
move.b #ECON1,d0
|
|
move.b #4,d1
|
|
bsr _enc28j60l_WriteRegByte
|
|
|
|
move.b #MACON3,d0
|
|
bsr _enc28j60l_SetBank
|
|
|
|
move.b #ECON1,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
|
|
|
|
|
|
moveq #1,d0
|
|
lea $DE000C,A0 ;SDCARD_CFG_SPEED
|
|
move.w d0,(a0)
|
|
|
|
|
|
move #$1ff,d6 ;
|
|
.loop
|
|
move.b #MACON3,d0
|
|
move.b #48+1,d1
|
|
bsr _enc28j60l_WriteRegByte
|
|
|
|
move.b #ECON1,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
|
|
move.b #MACON1,d0
|
|
move.b #$d,d1
|
|
bsr _enc28j60l_WriteRegByte
|
|
|
|
move.b #MACON3,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
cmp.b #48+1,d0
|
|
beq.s .ok
|
|
or.b #2,d7 ;MACON write error
|
|
.ok
|
|
dbf d6,.loop
|
|
;btst #6,$bfe001
|
|
;bne.s .loop
|
|
|
|
|
|
move.b #MACON1,d0
|
|
move.b #$d,d1
|
|
bsr _enc28j60l_WriteRegByte
|
|
|
|
move.b #MACON4,d0
|
|
move.b #64,d1
|
|
bsr _enc28j60l_WriteRegByte
|
|
|
|
|
|
move.b #MACON1,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
cmp.b #$ff,d0
|
|
beq.s .skip
|
|
nop
|
|
.skip
|
|
|
|
move.b #EIR,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
|
|
|
|
; while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) {
|
|
move.b #ENC28J60_READ_CTRL_REG,d3
|
|
move.b #ESTAT,d0
|
|
bsr _enc28j60l_ReadOp
|
|
|
|
|
|
move.b #EREVID,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
|
|
;bsr carddetect
|
|
;bsr cardCS
|
|
|
|
move.b #MACON1,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
|
|
|
|
move.b #EWRPT,d0
|
|
move.w #TXSTART_INIT,d1
|
|
bsr _enc28j60l_WriteReg
|
|
|
|
bsr _enc28j60l_ReadReg
|
|
cmp.w d0,d1
|
|
beq.s .ewrptmatch
|
|
or.b #4,d7
|
|
.ewrptmatch
|
|
|
|
|
|
move.b #EWRPT,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
move.b #EWRPT+1,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
|
|
|
|
|
|
;----------- write custom MAC address and compare afterwards ---------
|
|
|
|
lea mactest,a0
|
|
moveq #6-1,d4
|
|
.macwr
|
|
move.b (a0)+,d1
|
|
move.b -1+macdest-mactest(a0),d0
|
|
bsr _enc28j60l_WriteRegByte
|
|
dbf d4,.macwr
|
|
|
|
lea mactest,a0
|
|
moveq #6-1,d4
|
|
.macrd
|
|
move.b macdest-mactest(a0),d0
|
|
addq.l #1,a0
|
|
bsr _enc28j60l_ReadRegByte
|
|
move.b d0,-1+mactestr-mactest(a0)
|
|
dbf d4,.macrd
|
|
|
|
lea mactest,a0
|
|
moveq #6-1,d4
|
|
.macver
|
|
move.b (a0)+,d0
|
|
cmp.b -1+mactestr-mactest(a0),d0
|
|
beq.s .match
|
|
or.b #8,d7
|
|
.match
|
|
dbf d4,.macver
|
|
|
|
|
|
;------------------ READBUFFER/WRITEBUFFER TEST -----------------------
|
|
|
|
lea mactest,a1
|
|
move.w #32,d0
|
|
move.w #TXSTART_INIT,d1
|
|
movem.l d0-d1/a0-a1,-(sp)
|
|
bsr _enc28j60l_WriteBuffer
|
|
movem.l (sp)+,d0-d1/a0-a1
|
|
|
|
;Dest Ptr to HW
|
|
moveq #ERDPT,d0
|
|
move.w #TXSTART_INIT+1,d1 ;skip status byte
|
|
bsr _enc28j60l_WriteReg
|
|
|
|
lea readframe,a1
|
|
move.w #32,d0
|
|
movem.l d0-d1/a0-a1,-(sp)
|
|
bsr _enc28j60l_ReadBuffer
|
|
movem.l (sp)+,d0-d1/a0-a1
|
|
|
|
rts
|
|
|
|
DosLibrary: dc.b "dos.library",0
|
|
mactest: dc.b $00,$80,$10,$b,$a,$ff
|
|
mactestr: dc.b 0,0,0,0,0,0
|
|
macdest: dc.b MAADR5,MAADR4,MAADR3,MAADR2,MAADR1,MAADR0
|
|
dc.b $de,$ad,$be,$ef,$fe,$ed,$fa,$ce
|
|
dc.b 1,2,3,4,5,6
|
|
|
|
readframe: ds.b 32
|
|
|
|
endc
|
|
; ------------------------------------------------------------------------------
|
|
; | |
|
|
; | END Test/Debug code |
|
|
; | |
|
|
; ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------------------------------
|
|
;------------------------------------------------------------------------------------------------
|
|
;
|
|
; SPI HW dependent functions
|
|
;
|
|
;------------------------------------------------------------------------------------------------
|
|
;------------------------------------------------------------------------------------------------
|
|
|
|
|
|
; Initialize SPI hardware
|
|
;
|
|
; Not much to be done right now, just initialize the SPI clock divider and that's it
|
|
;
|
|
; In: void
|
|
;
|
|
; Out:
|
|
; D0 <= 0 - failure
|
|
; 1
|
|
_enc28j60l_Init:
|
|
|
|
SPI_DISABLE
|
|
|
|
moveq #3,d0 ;conservative default for Chip initialization
|
|
bsr _enc28j60l_SetSPISpeed ;keeps all regs
|
|
|
|
SPI_DISABLE ;/CS = HIGH
|
|
|
|
;moveq #1,d0
|
|
rts
|
|
|
|
|
|
|
|
|
|
; Shutdown SPI hardware
|
|
;
|
|
; In: void
|
|
; Out: void
|
|
_enc28j60l_Shutdown:
|
|
|
|
SPI_DISABLE ;/CS = HIGH
|
|
|
|
rts
|
|
|
|
|
|
|
|
|
|
; Set SPI clock divider
|
|
;
|
|
; In: D0 = 1...$1ff
|
|
; Out: void
|
|
_enc28j60l_SetSPISpeed:
|
|
move.l d0,-(sp)
|
|
|
|
cmp.w #0,d0 ;1
|
|
bgt.s speed_minok$ ;
|
|
moveq #0,d0 ;1
|
|
speed_minok$
|
|
|
|
cmp.w #$7f,d0 ;we don't want to be too slow!
|
|
blt.s speed_maxok$
|
|
move.w #$7f,d0
|
|
speed_maxok$
|
|
|
|
ifne _OPT_CFGSPEED_BYTE
|
|
move.b d0,SDCARD_CFG_SPEED
|
|
else
|
|
move.w d0,SDCARD_CFG_SPEED
|
|
endc
|
|
|
|
move.l (sp)+,d0
|
|
rts
|
|
|
|
; Read a number of Bytes from the ENC28J60
|
|
; note: ENC28J60 Read pointer assumed to be written already
|
|
;A1 = Ptr
|
|
;D0 = Size (>=2)
|
|
_enc28j60l_ReadBuffer:
|
|
|
|
SPI_ENABLE
|
|
movem.l d3-d5,-(sp)
|
|
;CSDELAY
|
|
lea.l SDCARD_DATA_W,a0 ;SPI_OUT
|
|
|
|
move.b #ENC28J60_READ_BUF_MEM,(a0)
|
|
move.b #_OPT_READ_CONST,d4 ;_OPT_READ_CONST
|
|
move.b (a0),d3 ;wait ;write and read register are the same on Vampire
|
|
|
|
move.b d4,(a0) ;provide clock (0xff here)
|
|
subq.l #1,d0 ;we start a second transfer in main loop
|
|
bra.s .loop_enter
|
|
.loop:
|
|
move.b d5,(a1)+
|
|
subq.l #1,d0
|
|
ble.s .loop_done ;finish last transfer outside
|
|
.loop_enter:
|
|
move.b (a0),d5
|
|
move.b d4,(a0)
|
|
bra.s .loop
|
|
.loop_done:
|
|
move.b (a0),(a1)+
|
|
|
|
movem.l (sp)+,d3-d5
|
|
|
|
;CSDELAY
|
|
SPI_DISABLE
|
|
|
|
rts
|
|
|
|
; Write a number of Bytes to the ENC28J60
|
|
;
|
|
;A1 = Ptr
|
|
;D0 = Size
|
|
;D1 = DestPtr on 28j60
|
|
_enc28j60l_WriteBuffer:
|
|
movem.l d3-d5,-(sp)
|
|
|
|
;Dest Ptr to HW
|
|
move.l d0,d4 ;save length
|
|
moveq #EWRPT,d0
|
|
bsr _enc28j60l_WriteReg
|
|
|
|
;now one header byte via SPI and then the Data
|
|
SPI_ENABLE
|
|
|
|
CSDELAY
|
|
|
|
;-> COMMAND
|
|
lea.l SDCARD_DATA_W,a0 ;SPI_OUT
|
|
move.b #ENC28J60_WRITE_BUF_MEM,(a0)
|
|
move.b (a0),d0 ;wait
|
|
|
|
;-> 1st byte is control byte
|
|
move.b #$f,(a0) ;1=Override, 2=CRCGEN, 4=PADDING, 8=HUGE ENABLE
|
|
|
|
.loopwb:
|
|
move.b (a1)+,d1
|
|
move.b (a0),d0
|
|
|
|
move.b d1,(a0)
|
|
|
|
subq.l #1,d4
|
|
bne.s .loopwb
|
|
|
|
move.b (a0),d0 ;last wait
|
|
|
|
movem.l (sp)+,d3-d5 ;restore registers before SPI_DISABLE
|
|
|
|
; CSDELAY
|
|
SPI_DISABLE
|
|
|
|
rts
|
|
|
|
|
|
|
|
;static void _enc28j60l_WriteOp (uint8_t op, uint8_t address, uint8_t data) {
|
|
; spi_enable_eth();
|
|
; spi_out(op | (address & ADDR_MASK));
|
|
; spi_out(data);
|
|
; spi_disable_eth();
|
|
;}
|
|
; D0 - address
|
|
; D1 - data
|
|
; D3 - Op
|
|
_enc28j60l_WriteOp:
|
|
movem.l d0/d2/d3/a0,-(sp)
|
|
|
|
SPI_ENABLE
|
|
|
|
moveq #BANK23_MASK,d2
|
|
and.b d0,d2
|
|
|
|
and.b #ADDR_MASK,d0
|
|
or.b d0,d3
|
|
|
|
lea.l SDCARD_DATA_W,a0 ;SPI_OUT
|
|
move.b d3,(a0)
|
|
move.b (a0),d3 ;wait
|
|
|
|
;lea.l SDCARD_DATA_W,a0 ;SPI_OUT
|
|
move.b d1,(a0)
|
|
move.b (a0),d3 ;wait
|
|
|
|
ifeq _OPT_WriteOp_Delay
|
|
tst.b d2 ;MAC or MII-Register ?
|
|
beq.s nodelay1$
|
|
endc
|
|
|
|
moveq #10,d0 ;wait some more to let the data sink in
|
|
noplop$
|
|
CSDELAY
|
|
dbf d0,noplop$
|
|
|
|
nodelay1$
|
|
|
|
SPI_DISABLE
|
|
|
|
;move.b $BFD400,d3 ;stall a little to fulfull /CS high minimum requirements (50ns)
|
|
nop
|
|
nop
|
|
|
|
ifne 0
|
|
|
|
moveq #60,d0 ;wait some more to fulfill minimal /CS delays (this delay is clearly too much right now...)
|
|
noplop2$:
|
|
nop
|
|
dbf d0,noplop2$
|
|
|
|
endc
|
|
|
|
movem.l (sp)+,d0/d2/d3/a0
|
|
rts
|
|
|
|
|
|
; D3 - Op
|
|
; D0 - Address
|
|
;
|
|
; ret: D0 - result
|
|
_enc28j60l_ReadOp:
|
|
move.l a0,-(sp)
|
|
|
|
SPI_ENABLE
|
|
|
|
move.l d1,-(sp)
|
|
|
|
move.b #$80,d1 ;address & 0x80
|
|
and.b d0,d1
|
|
|
|
and.b #ADDR_MASK,d0
|
|
or.b d3,d0
|
|
|
|
lea.l SDCARD_DATA_W,a0 ;SPI_OUT
|
|
move.b d0,(a0)
|
|
|
|
tst.b d1
|
|
beq.s noD1$
|
|
|
|
move.b (a0),d0 ;wait (on first SPI_OUT)
|
|
|
|
move.b #0,(a0) ;if( address & 0x80 ) spi_out(0)
|
|
noD1$
|
|
move.b (a0),d0 ;wait (on first or second SPI_OUT)
|
|
|
|
move.b #_OPT_READ_CONST,(a0) ;$ff, provide clock
|
|
lea.l SDCARD_DATA_R,a0 ;SPI_OUT
|
|
move.b (a0),d0
|
|
|
|
move.l (sp)+,d1 ;ensure the 10ns CS hold time
|
|
|
|
SPI_DISABLE
|
|
|
|
move.l (sp)+,a0
|
|
rts
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------------------------------
|
|
;------------------------------------------------------------------------------------------------
|
|
;
|
|
; Generic SPI HW independent functions
|
|
;
|
|
;------------------------------------------------------------------------------------------------
|
|
;------------------------------------------------------------------------------------------------
|
|
|
|
;
|
|
;delay at least D0 microseconds (<= $0fffffff or ~268.000.000)
|
|
;
|
|
; Important:
|
|
; No guarantee can be given right now by how much the given delay time is exceeded.
|
|
; All this function tries to achieve is to wait long enough in order to meet certain
|
|
; mimimal hardware delay requirements
|
|
;
|
|
; Notes:
|
|
;
|
|
;Input: D0 = delay in microseconds
|
|
;Output: void
|
|
_enc28j60l_UMinDelay:
|
|
movem.l d0/d1/a0,-(sp)
|
|
|
|
ifne 1
|
|
;
|
|
; this one relies on CIA access time 1.4 us
|
|
;
|
|
moveq #-1,d1
|
|
lsr.l #4,d1 ;$0fffffff
|
|
cmp.l d1,d0
|
|
blo.s .ok ;unsigned compare
|
|
move.l d1,d0 ;268 seconds
|
|
.ok
|
|
lsl.l #3,d0 ;us * 8
|
|
|
|
moveq #12,d1 ;1.5
|
|
.loop
|
|
eor.b #7,d1 ;switch between 12/8 and 11/8 -> 1.4375 effective count per CIA access
|
|
tst.b $BFE301 ;1 CIA access = 1.4 us
|
|
sub.l d1,d0 ;us*8 - (1.5 or 1.375)*8
|
|
bgt.s .loop
|
|
|
|
else
|
|
;
|
|
; method used with sdnet 0.7-1.0 -> count dependent on Amiga screen mode
|
|
;
|
|
; - A nano version should be implemented as well (280 ns horizontal resolution)
|
|
; - when the Amiga runs NON doublescan modes (OCS or disabled in P96), then this
|
|
; loop takes twice as long as desired
|
|
; -> re-implement using ECLOCK of timer.device
|
|
lea OCS_VHPOSR,a0 ;$dff006
|
|
|
|
newpos$ move.b (a0),d1
|
|
oldpos$ cmp.b (a0),d1 ;compare changes in vertical position
|
|
beq.s oldpos$
|
|
sub.l #32,d0 ;32 microseconds per line (1/31.25 kHz) - in non doublescan this would need to be 64=1/15.625 kHz
|
|
bgt.s newpos$
|
|
endc
|
|
|
|
movem.l (sp)+,d0/d1/a0
|
|
rts
|
|
|
|
|
|
;static uint8_t _enc28j60l_ReadRegByte (uint8_t address) {
|
|
; _enc28j60l_SetBank(address);
|
|
; return readOp(ENC28J60_READ_CTRL_REG, address);
|
|
;}
|
|
;In
|
|
; D0 = Address
|
|
;Out
|
|
; D0 = Result
|
|
_enc28j60l_ReadRegByte:
|
|
move.l d3,-(sp)
|
|
|
|
bsr _enc28j60l_SetBank
|
|
|
|
move.b #ENC28J60_READ_CTRL_REG,d3
|
|
bsr _enc28j60l_ReadOp
|
|
|
|
move.l (sp)+,d3
|
|
rts
|
|
|
|
|
|
;In
|
|
; D0 = Address.b
|
|
;Out
|
|
_enc28j60l_WriteRegByte:
|
|
move.l d3,-(sp)
|
|
|
|
bsr _enc28j60l_SetBank ;D0 = Address
|
|
|
|
moveq #ENC28J60_WRITE_CTRL_REG,d3
|
|
bsr _enc28j60l_WriteOp
|
|
|
|
move.l (sp)+,d3
|
|
rts
|
|
|
|
|
|
;In
|
|
; D0 = Address
|
|
;Out
|
|
; D0 = Result
|
|
_enc28j60l_ReadReg:
|
|
movem.l d1/d3/d4,-(sp)
|
|
|
|
bsr _enc28j60l_SetBank
|
|
|
|
moveq #1,d4
|
|
add.b d0,d4
|
|
|
|
move.b #ENC28J60_READ_CTRL_REG,d3
|
|
bsr _enc28j60l_ReadOp
|
|
move.b d0,d1
|
|
|
|
move.b d4,d0
|
|
move.b #ENC28J60_READ_CTRL_REG,d3
|
|
bsr _enc28j60l_ReadOp
|
|
|
|
lsl.w #8,d0
|
|
move.b d1,d0
|
|
|
|
movem.l (sp)+,d1/d3/d4
|
|
rts
|
|
|
|
|
|
;
|
|
; D0 = Address.b
|
|
; D1 = Data.w
|
|
;
|
|
_enc28j60l_WriteReg:
|
|
|
|
movem.l d0/d1/d3,-(sp)
|
|
|
|
bsr _enc28j60l_SetBank ;D0 = Address
|
|
|
|
moveq #ENC28J60_WRITE_CTRL_REG,d3
|
|
bsr _enc28j60l_WriteOp
|
|
|
|
lsr #8,d1
|
|
addq.b #1,d0
|
|
moveq #ENC28J60_WRITE_CTRL_REG,d3
|
|
bsr _enc28j60l_WriteOp
|
|
|
|
movem.l (sp)+,d0/d1/d3
|
|
rts
|
|
|
|
;
|
|
;
|
|
; Select proper register bank for subsequent write
|
|
; ignores bank switching request for ECON1
|
|
;
|
|
; Input: D0 = Address
|
|
_enc28j60l_SetBank:
|
|
cmp.b #ECON1,d0 ;these are in all 4 banks,
|
|
beq.s rts$ ;frequently used are ECON1,EIR
|
|
cmp.b #EIR,d0 ;
|
|
beq.s rts$ ;
|
|
|
|
movem.l d0/d1/d3-d5,-(sp)
|
|
|
|
moveq #BANK_MASK,d1 ;current bank
|
|
and.w d0,d1 ;address & BANK_MASK
|
|
lsr.w #5,d1 ;>>5
|
|
; cmp.b curbank,d1 ;didn't work reliably, disabled for now
|
|
; beq.s skip$
|
|
|
|
move.l d0,d4 ;address
|
|
move.l d1,d5 ;
|
|
|
|
move.w #ENC28J60_BIT_FIELD_CLR,d3
|
|
moveq #ECON1,d0
|
|
moveq #ECON1_BSEL1|ECON1_BSEL0,d1
|
|
bsr _enc28j60l_WriteOp
|
|
|
|
|
|
move.w #ENC28J60_BIT_FIELD_SET,d3
|
|
moveq #ECON1,d0
|
|
moveq #BANK_MASK,d1 ;current bank
|
|
and.w d4,d1 ;address & BANK_MASK
|
|
lsr.w #5,d1 ;>>5
|
|
move.b d1,curbank ;
|
|
bsr _enc28j60l_WriteOp
|
|
|
|
skip$
|
|
movem.l (sp)+,d0/d1/d3-d5
|
|
rts$
|
|
rts
|
|
|
|
;-----------------------------------------------------------------------
|
|
ifd PROTO_V2EXPNET
|
|
|
|
;---------------------------------------------------------------------------------------
|
|
;
|
|
; Hardware interrupt service routine for a list of boards
|
|
;
|
|
; In: A1 - is_data = board base address list
|
|
;
|
|
; Out: -
|
|
;
|
|
; Notes: - assumes that init() was called before
|
|
; - process list of board addresses and check for active interrupt(s)
|
|
; list layout:
|
|
; ULONG enableflag
|
|
; APTR board1,
|
|
; APTR board2,...
|
|
; APTR (0)
|
|
; APTR sigtask
|
|
; ULONG sigbit
|
|
;
|
|
_enc28j60l_IntServer_List:
|
|
movem.l d3/a6,-(sp)
|
|
|
|
move.l a1,d0 ;no pointer supplied ? -> return
|
|
beq.s .rts
|
|
move.l a1,a6
|
|
|
|
tst.l (a1)+ ;interrupt processing enabled ?
|
|
beq.s .rts_disable ;
|
|
|
|
moveq #0,d1
|
|
.boardloop:
|
|
move.l (a1)+,d0 ;next entry from list
|
|
beq.s .done ;
|
|
move.l d0,a0 ;current board
|
|
|
|
move.b #EPKTCNT,d0
|
|
bsr _enc28j60l_ReadRegByte
|
|
or.b d0,d1
|
|
|
|
bra.s .boardloop
|
|
.done:
|
|
tst.w d1
|
|
beq.s .rts
|
|
|
|
clr.l (a6)+ ;disable interrupt processing further on
|
|
|
|
; clear EIE_INTIE in all active boards directly from here
|
|
.intdis_loop:
|
|
move.l (a6)+,d0
|
|
beq.s .boardsdone
|
|
|
|
move.w #$0000,SDCARD_INT_ENABLE
|
|
;
|
|
;move.w #ENC28J60_BIT_FIELD_CLR,d3
|
|
;moveq #EIE,d0
|
|
;moveq #EIE_INTIE|EIE_PKTIE,d1
|
|
;bsr _enc28j60l_WriteOp
|
|
|
|
bra.s .intdis_loop
|
|
.boardsdone:
|
|
|
|
move.l (a6)+,d0 ;Sigtask
|
|
beq.s .rts
|
|
move.l d0,a1
|
|
|
|
moveq #0,d0
|
|
move.l (a6)+,d1 ;Sigbit
|
|
bset d1,d0
|
|
|
|
move.l 4.w,a6
|
|
jsr _LVOSignal(a6)
|
|
|
|
.rts:
|
|
movem.l (sp)+,d3/a6
|
|
moveq #0,d0 ;set Z flag
|
|
rts
|
|
.rts_disable: ;
|
|
move.w #$0000,SDCARD_INT_ENABLE
|
|
bra.s .rts
|
|
|
|
|
|
; TODO: enable/disable interrupt on board
|
|
_enc28j60l_EnableInterrupt:
|
|
move.w #$8000,SDCARD_INT_ENABLE
|
|
rts
|
|
|
|
_enc28j60l_DisableInterrupt:
|
|
move.w #$0000,SDCARD_INT_ENABLE
|
|
rts
|
|
|
|
endc ;ifd PROTO_V2EXPNET
|
|
;-----------------------------------------------------------------------
|
|
|
|
|
|
|
|
; DEBUG
|
|
;ifd PROTO_V2EXPNET
|
|
;dc.b "exp net variant built."
|
|
;endc
|
|
|
|
|
|
; section data,data
|
|
|
|
curbank: dc.b 0
|
|
cnop 0,4
|
|
|
|
|
|
|
|
END
|