TriOS/lib/driver_enc28j60.spin

1042 lines
29 KiB
Plaintext

{{
ENC28J60 Ethernet MAC / PHY Driver
----------------------------------
Copyright (c) 2006-2009 Harrison Pham <harrison@harrisonpham.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
The latest version of this software can be obtained from
http://hdpham.com/PropTCP and http://obex.parallax.com/
Constant Names / Code Logic based on code from
Microchip Technology, Inc.'s enc28j60.c / enc28j60.h source files
}}
CON
version = 6 ' major version
release = 0 ' minor version
CON
' ***************************************
' ** ENC28J60 SRAM Defines **
' ***************************************
' ENC28J60 Frequency
enc_freq = 25_000_000
' ENC28J60 SRAM Usage Constants
MAXFRAME = 1518 ' 6 (src addr) + 6 (dst addr) + 2 (type) + 1500 (data) + 4 (FCS CRC) = 1518 bytes
TX_BUFFER_SIZE = 1518
TXSTART = 8192 - (TX_BUFFER_SIZE + 8)
TXEND = TXSTART + (TX_BUFFER_SIZE + 8)
RXSTART = $0000
RXSTOP = (TXSTART - 2) | $0001 ' must be odd (B5 Errata)
RXSIZE = (RXSTOP - RXSTART + 1)
DAT
' ***************************************
' ** MAC Address Vars / Defaults **
' ***************************************
' ** This is the default MAC address used by this driver. The parent object
' can override this by passing a pointer to a new MAC address in the public
' start() method. It is recommend that this is done to provide a level of
' abstraction and makes tcp stack design easier.
' ** This is the ethernet MAC address, it is critical that you change this
' if you have more than one device using this code on a local network.
' ** If you plan on commercial deployment, you must purchase MAC address
' groups from IEEE or some other standards organization.
eth_mac byte $02, $00, $00, $00, $00, $01
' ***************************************
' ** Global Variables **
' ***************************************
rxlen word 0
tx_end word 0
packetheader byte 0[6]
'packet byte 0[MAXFRAME]
PUB start(_cs, _sck, _si, _so, xtalout, macptr)
'' Starts the driver (uses 1 cog for spi engine)
' Since some people don't have 25mhz crystals, we use the cog counters
' to generate a 25mhz frequency for the ENC28J60 (I love the Propeller)
' Note: This requires a main crystal that is a multiple of 25mhz (5mhz works).
spi_start(_cs, _sck, _so, _si, xtalout)
' If a MAC address pointer is provided (addr > -1) then copy it into
' the MAC address array (this kind of wastes space, but simplifies usage).
if macptr > -1
bytemove(@eth_mac, macptr, 6)
delay_ms(50)
init_ENC28J60
' return the chip silicon version
banksel(EREVID)
return rd_cntlreg(EREVID)
PUB stop
'' Stops the driver, frees 1 cog
spi_stop
PUB rd_macreg(address) : data
'' Read MAC Control Register
spi_out_cs(cRCR | address)
spi_out_cs(0) ' transmit dummy byte
data := spi_in ' get actual data
PUB rd_cntlreg(address) : data
'' Read ETH Control Register
spi_out_cs(cRCR | address)
data := spi_in
PUB wr_reg(address, data)
'' Write MAC and ETH Control Register
spi_out_cs(cWCR | address)
spi_out(data)
PUB bfc_reg(address, data)
'' Clear Control Register Bits
spi_out_cs(cBFC | address)
spi_out(data)
PUB bfs_reg(address, data)
'' Set Control Register Bits
spi_out_cs(cBFS | address)
spi_out(data)
PUB soft_reset
'' Soft Reset ENC28J60
spi_out(cSC)
PUB banksel(register)
'' Select Control Register Bank
bfc_reg(ECON1, %0000_0011)
bfs_reg(ECON1, register >> 8) ' high byte
PUB rd_phy(register) | low, high
'' Read ENC28J60 PHY Register
banksel(MIREGADR)
wr_reg(MIREGADR, register)
wr_reg(MICMD, MICMD_MIIRD)
banksel(MISTAT)
repeat while ((rd_macreg(MISTAT) & MISTAT_BUSY) > 0)
banksel(MIREGADR)
wr_reg(MICMD, $00)
low := rd_macreg(MIRDL)
high := rd_macreg(MIRDH)
return (high << 8) + low
PUB wr_phy(register, data)
'' Write ENC28J60 PHY Register
banksel(MIREGADR)
wr_reg(MIREGADR, register)
wr_reg(MIWRL, data)
wr_reg(MIWRH, data >> 8)
banksel(MISTAT)
repeat while ((rd_macreg(MISTAT) & MISTAT_BUSY) > 0)
PUB rd_sram : data
'' Read ENC28J60 8k Buffer Memory
spi_out_cs(cRBM)
data := spi_in
PUB wr_sram(data)
'' Write ENC28J60 8k Buffer Memory
spi_out_cs(cWBM)
spi_out(data)
PUB init_ENC28J60 | i
'' Init ENC28J60 Chip
repeat
i := rd_cntlreg(ESTAT)
while (i & $08) OR (!i & ESTAT_CLKRDY)
soft_reset
delay_ms(5) ' reset delay
bfc_reg(ECON1, ECON1_RXEN) ' stop send / recv
bfc_reg(ECON1, ECON1_TXRTS)
bfs_reg(ECON2, ECON2_AUTOINC) ' enable auto increment of sram pointers (already default)
packetheader[nextpacket_low] := RXSTART
packetheader[nextpacket_high] := constant(RXSTART >> 8)
banksel(ERDPTL)
wr_reg(ERDPTL, RXSTART)
wr_reg(ERDPTH, constant(RXSTART >> 8))
banksel(ERXSTL)
wr_reg(ERXSTL, RXSTART)
wr_reg(ERXSTH, constant(RXSTART >> 8))
wr_reg(ERXRDPTL, RXSTOP)
wr_reg(ERXRDPTH, constant(RXSTOP >> 8))
wr_reg(ERXNDL, RXSTOP)
wr_reg(ERXNDH, constant(RXSTOP >> 8))
wr_reg(ETXSTL, TXSTART)
wr_reg(ETXSTH, constant(TXSTART >> 8))
banksel(MACON1)
wr_reg(MACON1, constant(MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN))
wr_reg(MACON3, constant(MACON3_TXCRCEN | MACON3_PADCFG0 | MACON3_FRMLNEN))
' don't timeout transmissions on saturated media
wr_reg(MACON4, MACON4_DEFER)
' collisions occur at 63rd byte
wr_reg(MACLCON2, 63)
wr_reg(MAIPGL, $12)
wr_reg(MAIPGH, $0C)
wr_reg(MAMXFLL, MAXFRAME)
wr_reg(MAMXFLH, constant(MAXFRAME >> 8))
' back-to-back inter-packet gap time
' full duplex = 0x15 (9.6us)
' half duplex = 0x12 (9.6us)
wr_reg(MABBIPG, $12)
wr_reg(MAIPGL, $12)
wr_reg(MAIPGH, $0C)
' write mac address to the chip
banksel(MAADR1)
wr_reg(MAADR1, eth_mac[0])
wr_reg(MAADR2, eth_mac[1])
wr_reg(MAADR3, eth_mac[2])
wr_reg(MAADR4, eth_mac[3])
wr_reg(MAADR5, eth_mac[4])
wr_reg(MAADR6, eth_mac[5])
' half duplex
wr_phy(PHCON2, PHCON2_HDLDIS)
wr_phy(PHCON1, $0000)
' set LED options
wr_phy(PHLCON, $0742) ' $0472 => ledA = link, ledB = tx/rx
' $0742 => ledA = tx/rx, ledB = link
' enable packet reception
bfs_reg(ECON1, ECON1_RXEN)
PUB get_frame(pktptr) | packet_addr, new_rdptr
'' Get Ethernet Frame from Buffer
banksel(ERDPTL)
wr_reg(ERDPTL, packetheader[nextpacket_low])
wr_reg(ERDPTH, packetheader[nextpacket_high])
repeat packet_addr from 0 to 5
packetheader[packet_addr] := rd_sram
rxlen := (packetheader[rec_bytecnt_high] << 8) + packetheader[rec_bytecnt_low]
'bytefill(@packet, 0, MAXFRAME) ' Uncomment this if you want to clean out the buffer first
' otherwise, leave commented since it's faster to just leave stuff
' in the buffer
' protect from oversized packet
if rxlen =< MAXFRAME
rd_block(pktptr, rxlen)
{repeat packet_addr from 0 to rxlen - 1
BYTE[@packet][packet_addr] := rd_sram}
new_rdptr := (packetheader[nextpacket_high] << 8) + packetheader[nextpacket_low]
' handle errata read pointer start (must be odd)
--new_rdptr
if (new_rdptr < RXSTART) OR (new_rdptr > RXSTOP)
new_rdptr := RXSTOP
bfs_reg(ECON2, ECON2_PKTDEC)
banksel(ERXRDPTL)
wr_reg(ERXRDPTL, new_rdptr)
wr_reg(ERXRDPTH, new_rdptr >> 8)
PUB start_frame
'' Start frame - Inits the NIC and sets stuff
banksel(EWRPTL)
wr_reg(EWRPTL, TXSTART)
wr_reg(EWRPTH, constant(TXSTART >> 8))
tx_end := constant(TXSTART - 1) ' start location is really address 0, so we are sending a count of - 1
wr_frame(cTXCONTROL)
PUB wr_frame(data)
'' Write frame data
wr_sram(data)
++tx_end
PUB wr_block(startaddr, count)
blockwrite(startaddr, count)
tx_end += count
PUB rd_block(startaddr, count)
blockread(startaddr, count)
PUB send_frame
'' Sends frame
'' Will retry on send failure up to 15 times with a 1ms delay in between repeats
repeat 15
if p_send_frame ' send packet, if successful then quit retry loop
quit
delay_ms(1)
PRI p_send_frame | i, eirval
' Sends the frame
banksel(ETXSTL)
wr_reg(ETXSTL, TXSTART)
wr_reg(ETXSTH, constant(TXSTART >> 8))
banksel(ETXNDL)
wr_reg(ETXNDL, tx_end)
wr_reg(ETXNDH, tx_end >> 8)
' B5 Errata #10 - Reset transmit logic before send
bfs_reg(ECON1, ECON1_TXRST)
bfc_reg(ECON1, ECON1_TXRST)
' B5 Errata #10 & #13: Reset interrupt error flags
bfc_reg(EIR, constant(EIR_TXERIF | EIR_TXIF))
' trigger send
bfs_reg(ECON1, ECON1_TXRTS)
' fix for transmit stalls (derived from errata B5 #13), watches TXIF and TXERIF bits
' also implements a ~3.75ms (15 * 250us) timeout if send fails (occurs on random packet collisions)
' btw: this took over 10 hours to fix due to the elusive undocumented bug
i := 0
repeat
eirval := rd_cntlreg(EIR)
if ((eirval & constant(EIR_TXERIF | EIR_TXIF)) > 0)
quit
if (++i => 15)
eirval := EIR_TXERIF
quit
delay_us(250)
' B5 Errata #13 - Reset TXRTS if failed send then reset logic
bfc_reg(ECON1, ECON1_TXRTS)
if ((eirval & EIR_TXERIF) == 0)
return true ' successful send (no error interrupt)
else
return false ' failed send (error interrupt)
PUB get_mac_pointer
'' Gets mac address pointer
return @eth_mac
PUB get_rxlen
'' Gets received packet length
return rxlen - 4 ' knock off the 4 byte Frame Check Sequence CRC, not used anywhere outside of this driver (pg 31 datasheet)
PRI delay_us(Duration)
waitcnt(((clkfreq / 1_000_000 * Duration - 3928)) + cnt)
PRI delay_ms(Duration)
waitcnt(((clkfreq / 1_000 * Duration - 3932)) + cnt)
' ***************************************
' ** ASM SPI Engine **
' ***************************************
DAT
cog long 0
command long 0
CON
SPIOUT = %0000_0001
SPIIN = %0000_0010
SRAMWRITE = %0000_0100
SRAMREAD = %0000_1000
CSON = %0001_0000
CSOFF = %0010_0000
CKSUM = %0100_0000
SPIBITS = 8
PRI spi_out(value)
setcommand(constant(SPIOUT | CSON | CSOFF), @value)
PRI spi_out_cs(value)
setcommand(constant(SPIOUT | CSON), @value)
PRI spi_in : value
setcommand(constant(SPIIN | CSON | CSOFF), @value)
PRI spi_in_cs : value
setcommand(constant(SPIIN | CSON), @value)
PRI blockwrite(startaddr, count)
setcommand(SRAMWRITE, @startaddr)
PRI blockread(startaddr, count)
setcommand(SRAMREAD, @startaddr)
PUB chksum_add(startaddr, count)
setcommand(CKSUM, @startaddr)
return startaddr
PRI spi_start(_cs, _sck, _di, _do, _freqpin)
spi_stop
cspin := |< _cs
dipin := |< _di
dopin := |< _do
clkpin := |< _sck
ctramode := %0_00100_00_0000_0000_0000_0000_0000_0000 + _sck
ctrbmode := %0_00100_00_0000_0000_0000_0000_0000_0000 + _do
spi_setupfreqsynth(_freqpin)
cog := cognew(@init, @command) + 1
PRI spi_stop
if cog
cogstop(cog~ - 1)
ctra := 0
command~
PRI setcommand(cmd, argptr)
command := cmd << 16 + argptr 'write command and pointer
repeat while command 'wait for command to be cleared, signifying receipt
PRI spi_setupfreqsynth(pin)
if pin < 0
' pin num was negative -> disable freq synth
return
dira[pin] := 1
ctra := constant(%00010 << 26) '..set PLL mode
ctra |= constant((>|((enc_freq - 1) / 1_000_000)) << 23) 'set PLLDIV
frqa := spi_fraction(enc_freq, CLKFREQ, constant(4 - (>|((enc_freq - 1) / 1_000_000)))) 'Compute FRQA/FRQB value
ctra |= pin 'set PINA to complete CTRA/CTRB value
PRI spi_fraction(a, b, shift) : f
if shift > 0 'if shift, pre-shift a or b left
a <<= shift 'to maintain significant bits while
if shift < 0 'insuring proper result
b <<= -shift
repeat 32 'perform long division of a/b
f <<= 1
if a => b
a -= b
f++
a <<= 1
DAT
org
init or dira, cspin 'pin directions
andn dira, dipin
or dira, dopin
or dira, clkpin
or outa, cspin 'turn off cs (bring it high)
mov frqb, #0 'disable ctrb increment
mov ctrb, ctrbmode
loop wrlong zero,par 'zero command (tell spin we are done processing)
:subloop rdlong t1,par wz 'wait for command
if_z jmp #:subloop
mov addr, t1 'used for holding return addr to spin vars
rdlong arg0, t1 'arg0
add t1, #4
rdlong arg1, t1 'arg1
mov lkup, addr 'get the command var from spin
shr lkup, #16 'extract the cmd from the command var
test lkup, #CSON wz 'turn on cs
if_nz andn outa, cspin
test lkup, #SPIOUT wz 'spi out
if_nz call #spi_out_
test lkup, #SPIIN wz 'spi in
if_nz call #xspi_in_
test lkup, #SRAMWRITE wz 'sram block write
if_nz jmp #sram_write_
test lkup, #SRAMREAD wz 'sram block read
if_nz jmp #sram_read_
test lkup, #CSOFF wz 'cs off
if_nz or outa, cspin
test lkup, #CKSUM wz 'perform checksum
if_nz call #csum16
jmp #loop ' no cmd found
spi_out_ andn outa, clkpin
shl arg0, #24
mov phsb, arg0 ' data to write
mov frqa, freqw ' 20MHz write frequency
mov phsa, #0 ' start at clocking at 0
mov ctra, ctramode ' send data @ 20MHz
rol phsb, #1
rol phsb, #1
rol phsb, #1
rol phsb, #1
rol phsb, #1
rol phsb, #1
rol phsb, #1
mov ctra, #0 ' disable
andn outa, clkpin
spi_out__ret ret
spi_in_ andn outa, clkpin
mov phsa, phsr ' start phs for clock
mov frqa, freqr ' 10MHz read frequency
nop
mov ctra, ctramode ' start clocking
test dipin, ina wc
rcl arg0, #1
test dipin, ina wc
rcl arg0, #1
test dipin, ina wc
rcl arg0, #1
test dipin, ina wc
rcl arg0, #1
test dipin, ina wc
rcl arg0, #1
test dipin, ina wc
rcl arg0, #1
test dipin, ina wc
rcl arg0, #1
test dipin, ina wc
mov ctra, #0 ' stop clocking
rcl arg0, #1
andn outa, clkpin
spi_in__ret ret
xspi_in_ call #spi_in_
wrbyte arg0, addr ' write byte back to spin result var
xspi_in__ret ret
' SRAM Block Read/Write
sram_write_ ' block write (arg0=hub addr, arg1=count)
mov t1, arg0
mov t2, arg1
andn outa, cspin
mov arg0, #cWBM
call #spi_out_
:loop rdbyte arg0, t1
call #spi_out_
add t1, #1
djnz t2, #:loop
or outa, cspin
jmp #loop
sram_read_ ' block read (arg0=hub addr, arg1=count)
mov t1, arg0
mov t2, arg1
andn outa, cspin
mov arg0, #cRBM
call #spi_out_
:loop call #spi_in_
wrbyte arg0, t1
add t1, #1
djnz t2, #:loop
or outa, cspin
jmp #loop
csum16 ' performs checksum 16bit additions on the data
' arg0=hub addr, arg1=length, writes sum to first arg
mov t1, #0 ' clear sum
:loop rdbyte t2, arg0 ' read two bytes (16 bits)
add arg0, #1
rdbyte t3, arg0
add arg0, #1
shl t2, #8 ' build the word
add t2, t3
add t1, t2 ' add numbers
mov t2, t1 ' add lower and upper words together
shr t2, #16
and t1, hffff
add t1, t2
sub arg1, #2
cmp arg1, #1 wz, wc
if_nc_and_nz jmp #:loop
if_z rdbyte t2, arg0 ' add last byte (odd)
if_z shl t2, #8
if_z add t1, t2
wrlong t1, addr ' return result back to SPIN
csum16_ret ret
zero long 0 'constants
'values filled by spin code before launching
cspin long 0 ' chip select pin
dipin long 0 ' data in pin (enc28j60 -> prop)
dopin long 0 ' data out pin (prop -> enc28j60)
clkpin long 0 ' clock pin (prop -> enc28j60)
ctramode long 0 ' ctr mode for CLK
ctrbmode long 0 ' ctr mode for SPI Out
hffff long $FFFF
freqr long $2000_0000 'frequency of SCK /8 for receive
freqw long $4000_0000 'frequency of SCK /4 for send
phsr long $6000_0000
'temp variables
t1 res 1 ' loop and cog shutdown
t2 res 1 ' loop and cog shutdown
t3 res 1 ' Used to hold DataValue SHIFTIN/SHIFTOUT
t4 res 1 ' Used to hold # of Bits
t5 res 1 ' Used for temporary data mask
addr res 1 ' Used to hold return address of first Argument passed
lkup res 1 ' Used to hold command lookup
'arguments passed to/from high-level Spin
arg0 res 1 ' bits / start address
arg1 res 1 ' value / count
CON
' ***************************************
' ** ENC28J60 Control Constants **
' ***************************************
' ENC28J60 opcodes (OR with 5bit address)
cWCR = %010 << 5 ' write control register command
cBFS = %100 << 5 ' bit field set command
cBFC = %101 << 5 ' bit field clear command
cRCR = %000 << 5 ' read control register command
cRBM = (%001 << 5) | $1A ' read buffer memory command
cWBM = (%011 << 5) | $1A ' write buffer memory command
cSC = (%111 << 5) | $1F ' system command
' This is used to trigger TX in the ENC28J60, it shouldn't change, but you never know...
cTXCONTROL = $0E
' Packet header format (tail of the receive packet in the ENC28J60 SRAM)
#0,nextpacket_low,nextpacket_high,rec_bytecnt_low,rec_bytecnt_high,rec_status_low,rec_status_high
' ***************************************
' ** ENC28J60 Register Defines **
' ***************************************
' Bank 0 registers --------
ERDPTL = $00
ERDPTH = $01
EWRPTL = $02
EWRPTH = $03
ETXSTL = $04
ETXSTH = $05
ETXNDL = $06
ETXNDH = $07
ERXSTL = $08
ERXSTH = $09
ERXNDL = $0A
ERXNDH = $0B
ERXRDPTL = $0C
ERXRDPTH = $0D
ERXWRPTL = $0E
ERXWRPTH = $0F
EDMASTL = $10
EDMASTH = $11
EDMANDL = $12
EDMANDH = $13
EDMADSTL = $14
EDMADSTH = $15
EDMACSL = $16
EDMACSH = $17
' = $18
' = $19
' r = $1A
EIE = $1B
EIR = $1C
ESTAT = $1D
ECON2 = $1E
ECON1 = $1F
' Bank 1 registers -----
EHT0 = $100
EHT1 = $101
EHT2 = $102
EHT3 = $103
EHT4 = $104
EHT5 = $105
EHT6 = $106
EHT7 = $107
EPMM0 = $108
EPMM1 = $109
EPMM2 = $10A
EPMM3 = $10B
EPMM4 = $10C
EPMM5 = $10D
EPMM6 = $10E
EPMM7 = $10F
EPMCSL = $110
EPMCSH = $111
' = $112
' = $113
EPMOL = $114
EPMOH = $115
EWOLIE = $116
EWOLIR = $117
ERXFCON = $118
EPKTCNT = $119
' r = $11A
' EIE = $11B
' EIR = $11C
' ESTAT = $11D
' ECON2 = $11E
' ECON1 = $11F
' Bank 2 registers -----
MACON1 = $200
MACON2 = $201
MACON3 = $202
MACON4 = $203
MABBIPG = $204
' = $205
MAIPGL = $206
MAIPGH = $207
MACLCON1 = $208
MACLCON2 = $209
MAMXFLL = $20A
MAMXFLH = $20B
' r = $20C
MAPHSUP = $20D
' r = $20E
' = $20F
' r = $210
MICON = $211
MICMD = $212
' = $213
MIREGADR = $214
' r = $215
MIWRL = $216
MIWRH = $217
MIRDL = $218
MIRDH = $219
' r = $21A
' EIE = $21B
' EIR = $21C
' ESTAT = $21D
' ECON2 = $21E
' ECON1 = $21F
' Bank 3 registers -----
MAADR5 = $300
MAADR6 = $301
MAADR3 = $302
MAADR4 = $303
MAADR1 = $304
MAADR2 = $305
{MAADR1 = $300
MAADR0 = $301
MAADR3 = $302
MAADR2 = $303
MAADR5 = $304
MAADR4 = $305}
EBSTSD = $306
EBSTCON = $307
EBSTCSL = $308
EBSTCSH = $309
MISTAT = $30A
' = $30B
' = $30C
' = $30D
' = $30E
' = $30F
' = $310
' = $311
EREVID = $312
' = $313
' = $314
ECOCON = $315
' EPHTST $316
EFLOCON = $317
EPAUSL = $318
EPAUSH = $319
' r = $31A
' EIE = $31B
' EIR = $31C
' ESTAT = $31D
' ECON2 = $31E
' ECON1 = $31F
{******************************************************************************
* PH Register Locations
******************************************************************************}
PHCON1 = $00
PHSTAT1 = $01
PHID1 = $02
PHID2 = $03
PHCON2 = $10
PHSTAT2 = $11
PHIE = $12
PHIR = $13
PHLCON = $14
{******************************************************************************
* Individual Register Bits
******************************************************************************}
' ETH/MAC/MII bits
' EIE bits ----------
EIE_INTIE = (1<<7)
EIE_PKTIE = (1<<6)
EIE_DMAIE = (1<<5)
EIE_LINKIE = (1<<4)
EIE_TXIE = (1<<3)
EIE_WOLIE = (1<<2)
EIE_TXERIE = (1<<1)
EIE_RXERIE = (1)
' EIR bits ----------
EIR_PKTIF = (1<<6)
EIR_DMAIF = (1<<5)
EIR_LINKIF = (1<<4)
EIR_TXIF = (1<<3)
EIR_WOLIF = (1<<2)
EIR_TXERIF = (1<<1)
EIR_RXERIF = (1)
' ESTAT bits ---------
ESTAT_INT = (1<<7)
ESTAT_LATECOL = (1<<4)
ESTAT_RXBUSY = (1<<2)
ESTAT_TXABRT = (1<<1)
ESTAT_CLKRDY = (1)
' ECON2 bits --------
ECON2_AUTOINC = (1<<7)
ECON2_PKTDEC = (1<<6)
ECON2_PWRSV = (1<<5)
ECON2_VRTP = (1<<4)
ECON2_VRPS = (1<<3)
' ECON1 bits --------
ECON1_TXRST = (1<<7)
ECON1_RXRST = (1<<6)
ECON1_DMAST = (1<<5)
ECON1_CSUMEN = (1<<4)
ECON1_TXRTS = (1<<3)
ECON1_RXEN = (1<<2)
ECON1_BSEL1 = (1<<1)
ECON1_BSEL0 = (1)
' EWOLIE bits -------
EWOLIE_UCWOLIE = (1<<7)
EWOLIE_AWOLIE = (1<<6)
EWOLIE_PMWOLIE = (1<<4)
EWOLIE_MPWOLIE = (1<<3)
EWOLIE_HTWOLIE = (1<<2)
EWOLIE_MCWOLIE = (1<<1)
EWOLIE_BCWOLIE = (1)
' EWOLIR bits -------
EWOLIR_UCWOLIF = (1<<7)
EWOLIR_AWOLIF = (1<<6)
EWOLIR_PMWOLIF = (1<<4)
EWOLIR_MPWOLIF = (1<<3)
EWOLIR_HTWOLIF = (1<<2)
EWOLIR_MCWOLIF = (1<<1)
EWOLIR_BCWOLIF = (1)
' ERXFCON bits ------
ERXFCON_UCEN = (1<<7)
ERXFCON_ANDOR = (1<<6)
ERXFCON_CRCEN = (1<<5)
ERXFCON_PMEN = (1<<4)
ERXFCON_MPEN = (1<<3)
ERXFCON_HTEN = (1<<2)
ERXFCON_MCEN = (1<<1)
ERXFCON_BCEN = (1)
' MACON1 bits --------
MACON1_LOOPBK = (1<<4)
MACON1_TXPAUS = (1<<3)
MACON1_RXPAUS = (1<<2)
MACON1_PASSALL = (1<<1)
MACON1_MARXEN = (1)
' MACON2 bits --------
MACON2_MARST = (1<<7)
MACON2_RNDRST = (1<<6)
MACON2_MARXRST = (1<<3)
MACON2_RFUNRST = (1<<2)
MACON2_MATXRST = (1<<1)
MACON2_TFUNRST = (1)
' MACON3 bits --------
MACON3_PADCFG2 = (1<<7)
MACON3_PADCFG1 = (1<<6)
MACON3_PADCFG0 = (1<<5)
MACON3_TXCRCEN = (1<<4)
MACON3_PHDRLEN = (1<<3)
MACON3_HFRMEN = (1<<2)
MACON3_FRMLNEN = (1<<1)
MACON3_FULDPX = (1)
' MACON4 bits --------
MACON4_DEFER = (1<<6)
MACON4_BPEN = (1<<5)
MACON4_NOBKOFF = (1<<4)
MACON4_LONGPRE = (1<<1)
MACON4_PUREPRE = (1)
' MAPHSUP bits ----
MAPHSUP_RSTRMII = (1<<3)
' MICON bits --------
MICON_RSTMII = (1<<7)
' MICMD bits ---------
MICMD_MIISCAN = (1<<1)
MICMD_MIIRD = (1)
' EBSTCON bits -----
EBSTCON_PSV2 = (1<<7)
EBSTCON_PSV1 = (1<<6)
EBSTCON_PSV0 = (1<<5)
EBSTCON_PSEL = (1<<4)
EBSTCON_TMSEL1 = (1<<3)
EBSTCON_TMSEL0 = (1<<2)
EBSTCON_TME = (1<<1)
EBSTCON_BISTST = (1)
' MISTAT bits --------
MISTAT_NVALID = (1<<2)
MISTAT_SCAN = (1<<1)
MISTAT_BUSY = (1)
' ECOCON bits -------
ECOCON_COCON2 = (1<<2)
ECOCON_COCON1 = (1<<1)
ECOCON_COCON0 = (1)
' EFLOCON bits -----
EFLOCON_FULDPXS = (1<<2)
EFLOCON_FCEN1 = (1<<1)
EFLOCON_FCEN0 = (1)
' PHY bits
' PHCON1 bits ----------
PHCON1_PRST = (1<<15)
PHCON1_PLOOPBK = (1<<14)
PHCON1_PPWRSV = (1<<11)
PHCON1_PDPXMD = (1<<8)
' PHSTAT1 bits --------
PHSTAT1_PFDPX = (1<<12)
PHSTAT1_PHDPX = (1<<11)
PHSTAT1_LLSTAT = (1<<2)
PHSTAT1_JBSTAT = (1<<1)
' PHID2 bits --------
PHID2_PID24 = (1<<15)
PHID2_PID23 = (1<<14)
PHID2_PID22 = (1<<13)
PHID2_PID21 = (1<<12)
PHID2_PID20 = (1<<11)
PHID2_PID19 = (1<<10)
PHID2_PPN5 = (1<<9)
PHID2_PPN4 = (1<<8)
PHID2_PPN3 = (1<<7)
PHID2_PPN2 = (1<<6)
PHID2_PPN1 = (1<<5)
PHID2_PPN0 = (1<<4)
PHID2_PREV3 = (1<<3)
PHID2_PREV2 = (1<<2)
PHID2_PREV1 = (1<<1)
PHID2_PREV0 = (1)
' PHCON2 bits ----------
PHCON2_FRCLNK = (1<<14)
PHCON2_TXDIS = (1<<13)
PHCON2_JABBER = (1<<10)
PHCON2_HDLDIS = (1<<8)
' PHSTAT2 bits --------
PHSTAT2_TXSTAT = (1<<13)
PHSTAT2_RXSTAT = (1<<12)
PHSTAT2_COLSTAT = (1<<11)
PHSTAT2_LSTAT = (1<<10)
PHSTAT2_DPXSTAT = (1<<9)
PHSTAT2_PLRITY = (1<<5)
' PHIE bits -----------
PHIE_PLNKIE = (1<<4)
PHIE_PGEIE = (1<<1)
' PHIR bits -----------
PHIR_PLNKIF = (1<<4)
PHIR_PGIF = (1<<2)
' PHLCON bits -------
PHLCON_LACFG3 = (1<<11)
PHLCON_LACFG2 = (1<<10)
PHLCON_LACFG1 = (1<<9)
PHLCON_LACFG0 = (1<<8)
PHLCON_LBCFG3 = (1<<7)
PHLCON_LBCFG2 = (1<<6)
PHLCON_LBCFG1 = (1<<5)
PHLCON_LBCFG0 = (1<<4)
PHLCON_LFRQ1 = (1<<3)
PHLCON_LFRQ0 = (1<<2)
PHLCON_STRCH = (1<<1)