SMC LAN91C92/4/6 Ethernet Driver Code

Introduction

The file Smc91C9x.fth contains the hardware driver layer for the Standard MicroSystems LAN91C92/4/6 Ethernet controller chips as used on the MPE ARM Development Kit, MPE/Hiden SA1110 StrongBox and other MPE boards. The data sheets for these devices may be found at www.smsc.com and the part number for the MPE board is LAN91C96I, which can be used at 5v or 3.3v.

The controller has 64 8 bit registers organised as four banks of 16.

The code is written for portability rather than speed and uses byte accesses only. This permits the code to be used without change on big and little endian CPUs regardless of the bus interface width (8 or 16 bits).

Hardware gotchas

This code assumes a CPU with byte addressing. A cell addressed machine, e.g. most DSPs, will require considerable changes to the source code for memory buffer transfers.

When operating with fast CPUs note the following:

Configuration

The following must be defined before the file DRIVERS\SMC91C9x.FTH is compiled.

: const equ ;   \ n -- ; -- n
If you are using a standalone target with heads and you want interactive access to all the registers and bit masks, define CONST as CONSTANT, otherwise by default CONST is defined as EQU.

$50000000 const EtherBase       \ -- addr
Define the base address of the Ethernet controller.

0 equ SMC16?    \ -- flag
If SMC16 is non-zero, the driver will use 16 bit register accesses where possible, otherwise it will use two 8 bit accesses. SMC16 should only be set non-zero for little endian CPUs.

1 equ fastCPU?  \ -- n
Set this value false if no software intervention is required to meet the 400ns timing requirement before and after changing the pointer register.

0 equ smcDiags? \ -- flag
Set this equate true to compile diagnostic code for register dumping and so on. False by default.

0 equ eeprom?   \ -- flag
Set this equate true if the LAN91C9x has an attached EEPROM for configuration data storage. False by default.

0 equ GenericIP?        \ -- flag
Set this equate true if the Generic IP device structure defined in ETHERCOM.FTH is required. This is only required for systems using multiple IP devices in future releases of PowerNet.

1 equ sniff?    \ -- flag
Set this equate true to compile the packet sniffer code, which can be used to test Ethernet reception.

create EtherAddress     \ -- addr
Holds the Ethernet MAC address (six bytes). Note that you must obtain these from the IEEE (www.ieee.org) or from other sources.

create IpAddress        \ -- addr
Holds the Ethernet IP address (four bytes).

Constants

BankSelect

Offset of bank select register

Bank0 Registers

TCRL

Transmit Control Register - lo byte

TCRH

Transmit Control Register - hi byte

TXSTATUS

Transmit Status Register

RCR

Receive Control Register

MIR

Memory Information Register

MCR

Memory Control Register

Bank1 Registers

Configl

Configuration Register - lo byte

Configh

Configuration Register - hi byte

IA0

Hardware Address, Ethernet MSB

IA1

Hardware addr

IA2

Hardware addr

IA3

Hardware addr

IA4

Hardware addr

IA5

Hardware addr

Ctrh

Control Register - hi byte

Bank2 Registers

MMU

Memory management unit cmd reg

PNR

Packet number register

ARR

Allocation result register.

Pointerl

Memory pointer register

Pointerh

Memory pointer register

Datal

Reg to send packets too...

Datah

Reg to send packets too...

IntStatus

IntMask

Misc. Constants

RelRx

MMU Command to release memory from an rx

RxRd

SMC Command to read received packet

TxWr

SMC Command to write to tx area of ram

AllocIntMask

Memory allocated mask

MaxMsgSize

Max 802.3 Ether frame size in bytes

AllocTx

bit0

Bitmask

bit1

Bitmask

bit2

Bitmask

bit3

Bitmask

bit4

Bitmask

bit5

Bitmask

bit6

Bitmask

bit7

Bitmask

EvenTx

Control byte for tx of even bytes

OddTx

Control byte for tx of odd bytes

RxTask#

Multi Task ID

Hardware Interface Layer

The default code is for a memory-mapped device at base address EtherBase.

: ec!           \ b offset --
Set an 8 bit register contents to b, in the selected bank.

: ec@           \ offset -- val
Read an 8 bit register in the selected bank.

: ew!           \ w offset --
For LITTLE-ENDIAN CPUs only. Set a 16 bit register contents to w, in the selected bank.

: ew@           \ offset -- val
For LITTLE-ENDIAN CPUs only. Read a 16 bit register in the selected bank.

: ec!           \ val offset --
VFX optimising compilers will probably produce shorter and faster code by using a compiler macro for EC!.

: ec@           \ offset -- val
VFX optimising compilers will probably produce shorter and faster code by using a compiler macro for EC@.

: ew!           \ val offset --
VFX optimising compilers will probably produce shorter and faster code by using a compiler macro for EW!.

: ew@           \ offset -- val
VFX optimising compilers will probably produce shorter and faster code by using a compiler macro for EW@.

: 400ns         \ --
For fast CPUs, use this hardware dependent word to ensure at least 400ns between back to back Ethernet chip accesses. This is required for correct operation of the pointer register. The default version here assumes 4 instructions per iteration at 5ns per instruction, and the call/return and set up overheads are ignored. See FASTCPU? above.

: 400ns         \ --
Use this version if your CPU takes at least 400 ns between back to back Ethernet chip accesses. See FASTCPU? above.

: SetBank       \ bank -- ; bank = 0 to 3
Select the active register bank.

Diagnostics

: .bank         \ --
Display register contents for currently selected SMC bank.

: .reg          \ --
Display contents of all SMC Ethernet Controller's registers

Driver Layer

: eISR@         \ -- bmask
Read the bank 2 interrupt status register (IST).

: eMMU!         \ cmd --
Send a command to the bank 2 MMU register.

: eTCRl@        \ -- bmask
Read the bank 0 TCRl register.

: EnEtherTx     \ --
Enable Ethernet transmission. Selects bank 0.

: eSoftRst      \ --
Initiate software reset - needed to clear Tx lock up.

: init-SMC      \ --
Initialise SMC chip.

: init-EtherTx  \ --
Enable Ethernet TX module.

: init-EtherRx  \ --
Enable Ethernet RX module.

: etheradd>CS   \ addr --
Store 6 byte Ethernet address into SMC chip from memory buffer.

: InitEther     \ --
Perform a full initialisation of the chip, enabling Rx and Tx, and setting up the Ethernet MAC address from ETHERADDRESS.

: EtherLink?    \ -- flag
Return true if the Ethernet link is established.

: AllocTxMem    \ n -- mask
Allocate n bytes of memory to hold a packet for transmission. Return the contents of the ARR register, or -1 for a fatal error.

: GetTxMem      \ n -- ior
Allocate n bytes of memory to hold a packet for transmission.

: WritePacket   \ addr len --
Write an Ethernet frame to chip for transmission.

: IsRx?         \ -- t|f
Check if incoming data is present, returning true if a packet is available for get_ether_pkt below.

: DiscardRX     \ --
Throw away pending input packet due to lack of memory.

: get_ether_pkt \ *dest maxlen -- len
Get pending receive packet to a buffer. Note that data is valid only when ISRX? returns true, so that you must poll with ISRX? before using GET_ETHER_PKT.

: IsTx?         \ n -- flag
Return true if a packet of length n can be sent.

: send_ether_pkt        \ addr len --
Send packet from supplied buffer. The word will block until sufficient packet memory is available. Note that you should read incoming packets regularly, otherwise it is possible to get into a situation in which SEND_ETHER_PKT blocks for ever because there is not enough space in the device for the transmission packet. Theoretically, this should not happen because 1536 bytes are reserved for transmission, but ...

Attached EEPROM

: ee!           \ word offset --
Write a 16 bit word into the EEPROM at EEPROM address offset. The EEPROM may not be present in all SMC91C9x implementations.

: ee@           \ offset -- word
Read a 16 bit word from the EEPROM at EEPROM address offset. The EEPROM may not be present in all SMC91C9x implementations.

Generic I/O for PowerNet v3 and above

The code in this section is only compiled if the equate *\fo{GenericIP?) has been defined and is non-zero.

The layout and usage of this structure is defined in the file COMMON\ETHERCOM.FTH.


create IPdevice
  ' MyInit ,       \ 0: initialisation
  ' MyTerm ,    \ 1: shutdown
  ' MyRx? ,     \ 2: receive test
  ' MyRx                \ 3: receive packet
  ' MyTx? ,     \ 4: transmit test
  ' MyTx ,              \ 5: transmit packet
  ' MyGetAddr ,    \ 6: Get device addresses
  ' MySetAddr ,    \ 7: Set device addresses
  ' MySave ,    \ 8: Save IP device state

: GetAddrs      \ -- ipaddr macaddr 0
For Generic I/O IPDGetAddr function

: SetAddrs      \ ipaddr|0 macaddr|0 mode --
Set up the Ethernet MAC and the IP addresses. At present mode is always 0, but will be used in future releases to indicate data formats. If ipaddr or macaddr are zero, the stored data will not be changed.

create SMCvector        \ -- addr
The device vector needed by PowerNet v3+ and COMMON\ETHERCOM.FTH.

SMCvector constant IPDevice     \ -- addr
IPDevice is the default device name required by ETHERCOM.FTH. If you have multiple ports, only one should be named IPDevice.

System test

This code is only compiled if the equate SNIFF? is non-zero.

1536 buffer: pbuff      \ -- addr
Buffer for SNIFF.

: sniff         \ --
Listens to the network and displays all the traffic that has a broadcast destination or is for this device. SNIFF can be used to test reception.