emailler/drivers/w5100.s

536 lines
11 KiB
ArmAsm

;
; Copyright (c) 2013, Oliver Schmidt
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
; 1. Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
; 3. Neither the name of the Institute nor the names of its contributors
; may be used to endorse or promote products derived from this software
; without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
; ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
; SUCH DAMAGE.
;
; This file is part of the Contiki operating system.
;
; Author: Oliver Schmidt <ol.sc@web.de>
;
;---------------------------------------------------------------------
.macpack module
module_header _w5100
; Driver signature
.byte $65, $74, $68 ; "eth"
.byte $01 ; Ethernet driver API version number
; Ethernet address
mac: .byte $00, $08, $DC ; OUI of WIZnet
.byte $A2, $A2, $A2
; Buffer attributes
bufaddr:.res 2 ; Address
bufsize:.res 2 ; Size
; Jump table.
jmp init
jmp poll
jmp send
jmp exit
;---------------------------------------------------------------------
.if DYN_DRV
.zeropage
sp: .res 2 ; Stack pointer (Do not trash !)
reg: .res 2 ; Pointer Register content
ptr: .res 2 ; Indirect addressing pointer
len: .res 2 ; Data length
cnt: .res 2 ; Data length counter
adv: .res 2 ; Data pointer advancement
dir: .res 1 ; Transfer direction
bas: .res 1 ; Socket 0 Base Address (hibyte)
lim: .res 1 ; Socket 0 memory limit (hibyte)
tmp: .res 1 ; Temporary value
.else
.include "zeropage.inc"
reg := ptr1 ; Pointer Register content
ptr := ptr2 ; Indirect addressing pointer
len := ptr3 ; Data length
cnt := ptr4 ; Data length counter
adv := sreg ; Data pointer advancement
dir := tmp1 ; Transfer direction
bas := tmp2 ; Socket 0 Base Address (hibyte)
lim := tmp3 ; Socket 0 memory limit (hibyte)
tmp := tmp4 ; Temporary value
.endif
;=====================================================================
.rodata
fixup: .byte fixup02-fixup01, fixup03-fixup02, fixup04-fixup03
.byte fixup05-fixup04, fixup06-fixup05, fixup07-fixup06
.byte fixup08-fixup07, fixup09-fixup08, fixup10-fixup09
.byte fixup11-fixup10, fixup12-fixup11, fixup13-fixup12
.byte fixup14-fixup13, fixup15-fixup14, fixup16-fixup15
.byte fixup17-fixup16, fixup18-fixup17, fixup19-fixup18
.byte fixup20-fixup19, fixup21-fixup20, fixup22-fixup21
.byte fixup23-fixup22, fixup24-fixup23, fixup25-fixup24
.byte fixup26-fixup25, fixup27-fixup26, fixup28-fixup27
.byte fixup29-fixup28, fixup30-fixup29, fixup31-fixup30
.byte fixup32-fixup31
fixups = * - fixup
;---------------------------------------------------------------------
; The addresses are fixed up at runtime
mode := $C084
addr := $C085
data := $C087
;---------------------------------------------------------------------
.data
init:
; Convert slot number to slot I/O offset
asl
asl
asl
asl
sta reg
; Start with first fixup location
lda #<(fixup01+1)
ldx #>(fixup01+1)
sta ptr
stx ptr+1
ldx #$FF
ldy #$00
; Fixup address at location
: lda (ptr),y
and #%10001111 ; Allow for re-init
ora reg
sta (ptr),y
; Advance to next fixup location
inx
cpx #fixups
bcs :+
lda ptr
clc
adc fixup,x
sta ptr
bcc :-
inc ptr+1
bcs :- ; Always
:
;=====================================================================
; Indirect Bus I/F mode, Address Auto-Increment
fixup01:lda mode
ora #$03
fixup02:sta mode
; Retry Time-value Register: = 2000 ?
ldx #$00 ; Hibyte
ldy #$17 ; Lobyte
jsr set_addr
lda #$07^$D0
fixup03:eor data
fixup04:eor data
beq :+
sec
rts
; Check for W5100 shared access
; RX Memory Size Register: Assign 4+2+1+1KB to socket 0 to 3 ?
: ; ldx #$00 ; Hibyte
ldy #$1A ; Lobyte
jsr set_addr
fixup05:lda data
cmp #$06
beq :+++
; S/W Reset
lda #$80
fixup06:sta mode
:
fixup07:lda mode
bmi :-
; Indirect Bus I/F mode, Address Auto-Increment, Ping Block
lda #$13
fixup08:sta mode
; Source Hardware Address Register: MAC Address
ldx #$00 ; Hibyte
ldy #$09 ; Lobyte
jsr set_addr
: lda mac,x
fixup09:sta data
inx
cpx #$06
bcc :-
; RX Memory Size Register: Assign 4KB each to socket 0 and 1
; TX Memory Size Register: Assign 4KB each to socket 0 and 1
ldx #$00 ; Hibyte
ldy #$1A ; Lobyte
jsr set_addr
lda #$0A
fixup10:sta data
fixup11:sta data
; MAC Address: Source Hardware Address Register
: ; ldx #$00 ; Hibyte
ldy #$09 ; Lobyte
jsr set_addr
:
fixup12:lda data
sta mac,x
inx
cpx #$06
bcc :-
; Socket 0 Mode Register: MACRAW, MAC Filter
; Socket 0 Command Register: OPEN
ldy #$00
jsr set_addrsocket0
lda #$44
fixup13:sta data
lda #$01
fixup14:sta data
tya
tax
clc
rts
;---------------------------------------------------------------------
poll:
; Check for completion of previous command
; Socket 0 Command Register: = 0 ?
jsr set_addrcmdreg0
fixup15:lda data
beq :++
; No data available
lda #$00
: tax
sec
rts
; Socket 0 RX Received Size Register: != 0 ?
: ldy #$26 ; Socket RX Received Size Register
jsr set_addrsocket0
fixup16:lda data ; Hibyte
fixup17:ora data ; Lobyte
beq :--
; Process the incoming data
; -------------------------
; Set parameters for receiving data
lda #>$6000 ; Socket 0 RX Base Address
ldx #$00 ; Read
jsr set_parameters
; ldy #$28 ; Socket RX Read Pointer Register
; jsr set_addrsocket0
; Calculate and set physical address
jsr set_addrphysical
; Move physical address shadow to $F000-$FFFF
ora #>$F000
tax
; Read MAC raw 2byte packet size header
jsr get_datacheckaddr ; Hibyte
sta adv+1
jsr get_datacheckaddr ; Lobyte
sta adv
; Subtract 2byte header and set length
sec
sbc #<$0002
sta len
sta cnt
lda adv+1
sbc #>$0002
sta len+1
sta cnt+1
; Is bufsize < length ?
lda bufsize
cmp len
lda bufsize+1
sbc len+1
bcs :+
; Set data length = 0 and skip read
lda #$00
sta len
sta len+1
beq :++ ; Always
; Read data
: jsr mov_data
; Set parameters for common code
: lda #$40 ; RECV
ldy #$28 ; Socket 0 RX Read Pointer Register
; Advance pointer register
common: jsr set_addrsocket0
tay ; Save command
clc
lda reg
adc adv
tax
lda reg+1
adc adv+1
fixup18:sta data ; Hibyte
fixup19:stx data ; Lobyte
; Set command register
tya ; Restore command
jsr set_addrcmdreg0
fixup20:sta data
; Return data length (will be ignored for send)
lda len
ldx len+1
clc
rts
;---------------------------------------------------------------------
send:
; Save data length
sta len
stx len+1
sta cnt
stx cnt+1
sta adv
stx adv+1
; Set parameters for transmitting data
lda #>$4000 ; Socket 0 TX Base Address
ldx #$01 ; Write
jsr set_parameters
; Wait for completion of previous command
; Socket 0 Command Register: = 0 ?
: jsr set_addrcmdreg0
fixup21:lda data
bne :-
; Socket 0 TX Free Size Register: < length ?
: ldy #$20 ; Socket TX Free Size Register
jsr set_addrsocket0
fixup22:lda data ; Hibyte
fixup23:ldx data ; Lobyte
cpx len
sbc len+1
bcc :-
; Send the data
; -------------
ldy #$24 ; Socket TX Write Pointer Register
jsr set_addrsocket0
; Calculate and set pyhsical address
jsr set_addrphysical
; Write data
jsr mov_data
; Set parameters for common code
lda #$20 ; SEND
ldy #$24 ; Socket TX Write Pointer Register
bne common ; Always
;---------------------------------------------------------------------
exit:
rts
;---------------------------------------------------------------------
set_addrphysical:
fixup24:lda data ; Hibyte
fixup25:ldy data ; Lobyte
sty reg
sta reg+1
and #>$0FFF ; Socket Mask Address (hibyte)
ora bas ; Socket Base Address (hibyte)
tax
set_addr:
fixup26:stx addr ; Hibyte
fixup27:sty addr+1 ; Lobyte
rts
set_addrcmdreg0:
ldy #$01 ; Socket Command Register
set_addrsocket0:
ldx #>$0400 ; Socket 0 register base address
bne set_addr ; Always
set_addrbase:
ldx bas ; Socket Base Address (hibyte)
ldy #<$0000 ; Socket Base Address (lobyte)
beq set_addr ; Always
get_datacheckaddr:
fixup28:lda data
iny ; Physical address shadow (lobyte)
bne :+
inx ; Physical address shadow (hibyte)
beq set_addrbase
: rts
;---------------------------------------------------------------------
set_parameters:
; Setup variables in zero page
sta bas ; Socket Base Address
clc
adc #>$1000 ; Socket memory size
sta lim ; Socket memory limit
stx dir ; Transfer direction
; Set indirect addressing pointer
lda bufaddr
ldx bufaddr+1
sta ptr
stx ptr+1
rts
;---------------------------------------------------------------------
mov_data:
; Calculate highest R/W address allowing
; to R/W without address wraparound
sec
lda #<$0000 ; Socket memory limit (lobyte)
sbc len
tay
lda lim ; Socket memory limit (hibyte)
sbc len+1
tax
tya
; R/W without address wraparound possible because
; highest R/W address > actual R/W address ?
; sec
fixup29:sbc addr+1 ; Lobyte
tay
txa
fixup30:sbc addr ; Hibyte
tax
tya
bcs :+
; Calculate length of first chunk
; clc
adc len
sta cnt
tay
txa
adc len+1
sta cnt+1
tax
tya
; R/W first chunk
jsr rw_data
; Wraparound R/W address
jsr set_addrbase
; Set buffer pointer for second chunk
clc
lda bufaddr
adc cnt
sta ptr
lda bufaddr+1
adc cnt+1
sta ptr+1
; Calculate length of second chunk
sec
lda len
sbc cnt
sta cnt
lda len+1
sbc cnt+1
sta cnt+1
; Get length of (second) chunk
: lda cnt
ldx cnt+1
; R/W (second) chunk
rw_data:eor #$FF ; Two's complement part 1
tay
iny ; Two's complement part 2
sty tmp
sec
lda ptr
sbc tmp
sta ptr
lda ptr+1
sbc #$00
sta ptr+1
lda dir ; Transfer direction
bne :++
; Read data
:
fixup31:lda data
sta (ptr),y
iny
bne :-
inc ptr+1
dex
bpl :-
rts
; Write data
: lda (ptr),y
fixup32:sta data
iny
bne :-
inc ptr+1
dex
bpl :-
rts
;---------------------------------------------------------------------