ip65 technical reference
File : drivers/lan91c96.s
Ethernet driver for SMC LAN91C96 chip
functions
function | description |
---|
eth_init | initialize the ethernet adaptor
inputs: none
outputs: carry flag is set if there was an error, clear otherwise
|
eth_rx | receive a packet
inputs: none
outputs:
if there was an error receiving the packet (or no packet was ready) then carry flag is set
if packet was received correctly then carry flag is clear,
eth_inp contains the received packet,
and eth_inp_len contains the length of the packet
|
eth_tx | send a packet
inputs:
eth_outp: packet to send
eth_outp_len: length of packet to send
outputs:
if there was an error sending the packet then carry flag is set
otherwise carry flag is cleared
|
constants
constants | description | value |
---|
eth_driver_io_base | | fixlan01+1
|
eth_driver_name | | "LANceGS (91C96)"
|
implementation
; Ethernet driver for SMC LAN91C96 chip
;
.ifndef KPR_API_VERSION_NUMBER
.define EQU =
.include "../inc/kipper_constants.i"
.endif
.include "../inc/common.i"
.export eth_init
.export eth_rx
.export eth_tx
.export eth_driver_name
.export eth_driver_io_base
.import eth_inp
.import eth_inp_len
.import eth_outp
.import eth_outp_len
.import cfg_mac
; LANceGS hardware addresses
ethbsr := $c00E ; Bank select register R/W (2B)
; Register bank 0
ethtcr := $c000 ; Transmission control register R/W (2B)
ethephsr := $c002 ; EPH status register R/O (2B)
ethrcr := $c004 ; Receive control register R/W (2B)
ethecr := $c006 ; Counter register R/O (2B)
ethmir := $c008 ; Memory information register R/O (2B)
ethmcr := $c00A ; Memory Config. reg. +0 R/W +1 R/O (2B)
; Register bank 1
ethcr := $c000 ; Configuration register R/W (2B)
ethbar := $c002 ; Base address register R/W (2B)
ethiar := $c004 ; Individual address register R/W (6B)
ethgpr := $c00A ; General address register R/W (2B)
ethctr := $c00C ; Control register R/W (2B)
; Register bank 2
ethmmucr := $c000 ; MMU command register W/O (1B)
ethautotx := $c001 ; AUTO TX start register R/W (1B)
ethpnr := $c002 ; Packet number register R/W (1B)
etharr := $c003 ; Allocation result register R/O (1B)
ethfifo := $c004 ; FIFO ports register R/O (2B)
ethptr := $c006 ; Pointer register R/W (2B)
ethdata := $c008 ; Data register R/W (4B)
ethist := $c00C ; Interrupt status register R/O (1B)
ethack := $c00C ; Interrupt acknowledge register W/O (1B)
ethmsk := $c00D ; Interrupt mask register R/W (1B)
; Register bank 3
ethmt := $c000 ; Multicast table R/W (8B)
ethmgmt := $c008 ; Management interface R/W (2B)
ethrev := $c00A ; Revision register R/W (2B)
ethercv := $c00C ; Early RCV register R/W (2B)
.segment "IP65ZP" : zeropage
eth_packet: .res 2
.data
;initialize the ethernet adaptor
;inputs: none
;outputs: carry flag is set if there was an error, clear otherwise
eth_init:
jsr lan_self_modify
lda #$01
fixlan00:
sta ethbsr ; Select register bank 1
fixlan01:
lda ethcr ; Read first four bytes - $31, $20, $67, $18
cmp #$31
bne lanerror
fixlan03:
lda ethbar
cmp #$67
bne lanerror
fixlan04:
lda ethbar+1
cmp #$18
bne lanerror
; we have the magic signature
; Reset ETH card
lda #$00 ; Bank 0
fixlan05:
sta ethbsr
lda #%10000000 ; Software reset
fixlan06:
sta ethrcr+1
ldy #$00
fixlan07:
sty ethrcr
fixlan08:
sty ethrcr+1
; Delay
: cmp ($FF,x) ; 6 cycles
cmp ($FF,x) ; 6 cycles
iny ; 2 cycles
bne :- ; 3 cycles
; 17 * 256 = 4352 -> 4,4 ms
; Enable transmit and receive
lda #%10000001 ; Enable transmit TXENA, PAD_EN
ldx #%00000011 ; Enable receive, strip CRC ???
fixlan09:
sta ethtcr
fixlan10:
stx ethrcr+1
lda #$01 ; Bank 1
fixlan11:
sta ethbsr
fixlan12:
lda ethcr+1
ora #%00010000 ; No wait (IOCHRDY)
fixlan13:
sta ethcr+1
lda #%00001001 ; Auto release
fixlan14:
sta ethctr+1
; Set MAC address
lda cfg_mac
ldx cfg_mac + 1
fixlan15:
sta ethiar
fixlan16:
stx ethiar + 1
lda cfg_mac + 2
ldx cfg_mac + 3
fixlan17:
sta ethiar + 2
fixlan18:
stx ethiar + 3
lda cfg_mac + 4
ldx cfg_mac + 5
fixlan19:
sta ethiar + 4
fixlan20:
stx ethiar + 5
; Set interrupt mask
lda #$02 ; Bank 2
fixlan21:
sta ethbsr
lda #%00000000 ; No interrupts
fixlan22:
sta ethmsk
clc
rts
lanerror:
sec
rts
;receive a packet
;inputs: none
;outputs:
; if there was an error receiving the packet (or no packet was ready) then carry flag is set
; if packet was received correctly then carry flag is clear,
; eth_inp contains the received packet,
; and eth_inp_len contains the length of the packet
eth_rx:
fixlan38:
lda ethist
and #%00000001 ; Check receive interrupt
bne :+
sec ; No packet available
rts
: lda #$00
ldx #%11100000 ; Receive, Auto Increment, Read
fixlan39:
sta ethptr
fixlan40:
stx ethptr + 1
; Last word contains 'last data byte' and $60 or 'fill byte' and $40
fixlan41:
lda ethdata ; Status word
fixlan42:
lda ethdata ; Only need high byte
; Move ODDFRM bit into carry:
; - Even packet length -> carry clear -> subtract 6 bytes
; - Odd packet length -> carry set -> subtract 5 bytes
lsr
lsr
lsr
lsr
lsr
; The packet contains 3 extra words
fixlan43:
lda ethdata ; Total number of bytes
sbc #$05 ; Actually 5 or 6 depending on carry
sta eth_inp_len
fixlan44:
lda ethdata
sbc #$00
sta eth_inp_len+1
; Read bytes into buffer
lda #eth_inp
sta eth_packet
stx eth_packet+1
ldx eth_inp_len+1
ldy #$00
lanread:
fixlan46:
lda ethdata
sta (eth_packet),y
iny
bne :+
inc eth_packet+1
: cpy eth_inp_len
bne lanread
dex
bpl lanread
; Remove and release RX packet from the FIFO
lda #%10000000
fixlan47:
sta ethmmucr
clc
rts
; send a packet
;inputs:
; eth_outp: packet to send
; eth_outp_len: length of packet to send
;outputs:
; if there was an error sending the packet then carry flag is set
; otherwise carry flag is cleared
eth_tx:
lda eth_outp_len + 1 ;
ora #%00100000
fixlan23:
sta ethmmucr ; Allocate memory for transmission
fixlan24:
lda ethist
and #%00001000 ; Allocation interrupt
bne :+
sec
rts ; Not able to allocate; bail
: lda #%00001000
fixlan25:
sta ethack ; Acknowledge interrupt
fixlan26:
lda etharr
fixlan27:
sta ethpnr ; Set packet number
lda #$00
ldx #%01000000 ; Auto increment
fixlan28:
sta ethptr
fixlan29:
stx ethptr + 1
lda #$00 ; Status written by CSMA
fixlan30:
sta ethdata
fixlan31:
sta ethdata
lda eth_outp_len
eor #$01
lsr
lda eth_outp_len
adc #$05 ; Actually will be 5 or 6 depending on carry
fixlan32:
sta ethdata
lda eth_outp_len + 1
adc #$00
fixlan33:
sta ethdata
lda #eth_outp
sta eth_packet
stx eth_packet + 1
ldx eth_outp_len + 1
ldy #$00
lanwrite:
lda (eth_packet),y
fixlan34:
sta ethdata
iny
bne :+
inc eth_packet + 1
: cpy eth_outp_len
bne lanwrite
dex
bpl lanwrite
lda eth_outp_len ; Odd packet length?
lsr
bcc :+
lda #%001000000 ; Yes, Odd
bne fixlan36 ; Always
: lda #$00 ; No
fixlan35:
sta ethdata ; Fill byte
fixlan36:
sta ethdata ; Control byte
lda #%11000000 ; Enqueue packet - transmit
fixlan37:
sta ethmmucr
clc
rts
;
; lan_self_modify - make all entry points variable so we can move the
; LANceGS card around in the Apple
;
lan_self_modify:
lda #$C0 ; FIXME - hardcoded to slot 4
clc ; We'll be adding later, so clear carry
; Make the accumulator contain slot number plus $80
; i.e. Slot 1 = $90
; i.e. Slot 2 = $A0
; i.e. Slot 3 = $B0
; i.e. Slot 4 = $C0
; i.e. Slot 5 = $D0
; i.e. Slot 6 = $E0
; i.e. Slot 7 = $F0
; $C0s0: Save off all ethtcr, ethcr, ethmmucr, and ethmt mods
sta fixlan01 + 1
sta fixlan09 + 1
sta fixlan23 + 1
sta fixlan37 + 1
; sta fixlan45 + 1 ; Removed
sta fixlan47 + 1
; $C0s1: Save off all ethtcr+1, ethcr+1, ethmmucr+1, and ethmt+1 mods
adc #$01
; sta fixlan02 + 1 ; Removed
sta fixlan12 + 1
sta fixlan13 + 1
; $C0s2: Save off all ethephsr, ethbar, and ethpnr mods
adc #$01
sta fixlan03 + 1
sta fixlan27 + 1
; $C0s3: Save off all ethephsr+1, ethbar+1, ethpnr+1, and etharr mods
adc #$01
sta fixlan04 + 1
sta fixlan26 + 1
; $C0s4: Save off all ethrcr, ethiar, and ethfifo mods
adc #$01
sta fixlan07 + 1
sta fixlan15 + 1
; $C0s5: Save off all ethrcr+1, ethiar+1, and ethfifo+1 mods
adc #$01
sta fixlan06 + 1
sta fixlan08 + 1
sta fixlan10 + 1
sta fixlan16 + 1
; $C0s6: Save off all ethecr, ethptr, and ethiar+2 mods
adc #$01
sta fixlan17 + 1
sta fixlan28 + 1
sta fixlan39 + 1
; $C0s7: Save off all ethecr+1, ethptr+1, and ethiar+3 mods
adc #$01
sta fixlan18 + 1
sta fixlan29 + 1
sta fixlan40 + 1
; $C0s8: Save off all ethmir, ethdata, ethmgmt, and ethiar+4 mods
adc #$01
sta fixlan19 + 1
sta fixlan30 + 1
sta fixlan31 + 1
sta fixlan32 + 1
sta fixlan33 + 1
sta fixlan34 + 1
sta fixlan35 + 1
sta fixlan36 + 1
sta fixlan41 + 1
sta fixlan42 + 1
sta fixlan43 + 1
sta fixlan44 + 1
sta fixlan46 + 1
; $C0s9: Save off all ethmir+1, ethdata+1, ethmgmt+1, and ethiar+5 mods
adc #$01
sta fixlan20 + 1
; $C0sA: Save off all ethmcr, ethgpr, and ethrev mods
; $C0sB: Save off all ethmcr+1, ethgpr+1, and ethrev+1 mods
; None
; $C0sC: Save off all ethctr, ethist, ethack, and ethercv mods
adc #$03 ; Because there were no a or b mods
sta fixlan24 + 1
sta fixlan25 + 1
sta fixlan38 + 1
; $C0sD: Save off all ethmsk, ethctr+1 mods
adc #$01
sta fixlan14 + 1
sta fixlan22 + 1
; $C0sE: Save off all ethbsr mods
adc #$01
sta fixlan00 + 1
sta fixlan05 + 1
sta fixlan11 + 1
sta fixlan21 + 1
rts
.rodata
eth_driver_name:
.asciiz "LANceGS (91C96)"
eth_driver_io_base=fixlan01+1
; The contents of this file are subject to the Mozilla Public License
; Version 1.1 (the "License"); you may not use this file except in
; compliance with the License. You may obtain a copy of the License at
; http://www.mozilla.org/MPL/
;
; Software distributed under the License is distributed on an "AS IS"
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
; License for the specific language governing rights and limitations
; under the License.
;
; The Original Code is ip65.
;
; The Initial Developer of the Original Code is David Schmidt
; Portions created by the Initial Developer is Copyright (C) 2011
; All Rights Reserved.
; -- LICENSE END --