From a5d7a06027f19dcb89793e2ae2fdc546fcf3821a Mon Sep 17 00:00:00 2001
From: Oliver Schmidt
Date: Thu, 12 Jun 2014 22:56:35 +0200
Subject: [PATCH] Enhanced Ethernet drivers.
Made Ethernet drivers easier to consume by assembly programs.
* Replaced function pointers with JMP instructions.
* Provide return values additionally via Carry flag.
Reset Ethernet chips on initialization.
Both for the CS8900A and the W5100 the data sheets just say that
the RESET bit is automatically cleared after the RESET. This may
be interpreted in two ways:
1) There's no need to be afraid of reading the RESET bit as 1 and
unintentionally trigger a RESET by writing it back after ORing in
some other bit.
2) The RESET process isn't complete before the RESET bit hasn't
become 0 again.
It's impossible for me to empirically falsify the latter option
as the drivers are supposed to work on faster machines than the
ones I have access to. And if the RESET process includes things
like oscillators then the time to complete the RESET could differ
even between multiple exemplars of the same chip. Therefore I
opted to presume the latter option.
However that means a non-exsistent chip may cause an infinite
loop while waiting for the RESET bit to be cleared so I finally
added code to detect the presence of the Ethernet chips. There's
a risk of a chip being locked up in a way that makes the detection
fail - and therefore the RESET not being performed. This catch-22
needs to be solved by the user doing a hard RESET.
---
cpu/6502/net/cs8900a.S | 91 ++++++++++++++++++++++++-------------
cpu/6502/net/ethernet.c | 11 ++++-
cpu/6502/net/lan91c96.S | 99 +++++++++++++++++++++++------------------
cpu/6502/net/w5100.S | 85 ++++++++++++++++++++++-------------
4 files changed, 177 insertions(+), 109 deletions(-)
diff --git a/cpu/6502/net/cs8900a.S b/cpu/6502/net/cs8900a.S
index 784f1673e..9bc648704 100644
--- a/cpu/6502/net/cs8900a.S
+++ b/cpu/6502/net/cs8900a.S
@@ -48,10 +48,10 @@ bufaddr:.res 2 ; Address
bufsize:.res 2 ; Size
; Jump table.
- .addr init
- .addr poll
- .addr send
- .addr exit
+ jmp init
+ jmp poll
+ jmp send
+ jmp exit
;---------------------------------------------------------------------
@@ -85,6 +85,8 @@ fixup: .byte fixup02-fixup01, fixup03-fixup02, fixup04-fixup03
.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
fixups = * - fixup
@@ -143,6 +145,29 @@ fixup01:lda isq+1
ora #$01 ; Set clockport bit
fixup02:sta isq+1
+ ; Check EISA registration number of Crystal Semiconductor
+ ; PACKETPP = $0000, PPDATA == $630E ?
+ lda #$00
+ tax
+ jsr packetpp_ax
+ lda #$63^$0E
+fixup03:eor ppdata
+fixup04:eor ppdata+1
+ beq :+
+ sec
+ rts
+
+ ; Initiate a chip-wide reset
+ ; PACKETPP = $0114, PPDATA = $0040
+: lda #$14
+ jsr packetpp_a1
+ ldy #$40
+fixup05:sty ppdata
+: jsr packetpp_a1
+fixup06:ldy ppdata
+ and #$40
+ bne :-
+
; Accept valid unicast + broadcast frames
; PACKETPP = $0104, PPDATA = $0D05
lda #$04
@@ -173,6 +198,8 @@ fixup02:sta isq+1
lda #$D3
ldx #$00
jsr ppdata_ax
+ txa
+ clc
rts
;---------------------------------------------------------------------
@@ -183,27 +210,22 @@ poll:
; PACKETPP = $0124, PPDATA & $0D00 ?
lda #$24
jsr packetpp_a1
-fixup03:lda ppdata+1
+fixup07:lda ppdata+1
and #$0D
- bne :+
-
- ; No frame ready
- tax
- rts
+ beq :+
; Process the incoming frame
; --------------------------
; Read receiver event and discard it
; RXTXREG
-:
-fixup04:ldx rxtxreg+1
-fixup05:lda rxtxreg
+fixup08:ldx rxtxreg+1
+fixup09:lda rxtxreg
; Read frame length
; cnt = len = RXTXREG
-fixup06:ldx rxtxreg+1
-fixup07:lda rxtxreg
+fixup10:ldx rxtxreg+1
+fixup11:lda rxtxreg
sta len
stx len+1
sta cnt
@@ -217,23 +239,24 @@ fixup07:lda rxtxreg
cmp cnt
lda bufsize+1
sbc cnt+1
- bcs :+
+ bcs :++
; Yes, skip frame
jsr skipframe
; No frame ready
lda #$00
- tax
+: tax
+ sec
rts
; Read bytes into buffer
: jsr adjustptr
:
-fixup08:lda rxtxreg
+fixup12:lda rxtxreg
sta (ptr),y
iny
-fixup09:lda rxtxreg+1
+fixup13:lda rxtxreg+1
sta (ptr),y
iny
bne :-
@@ -244,6 +267,7 @@ fixup09:lda rxtxreg+1
; Return frame length
lda len
ldx len+1
+ clc
rts
;---------------------------------------------------------------------
@@ -256,12 +280,12 @@ send:
; Transmit command
lda #$C9
ldx #$00
-fixup10:sta txcmd
-fixup11:stx txcmd+1
+fixup14:sta txcmd
+fixup15:stx txcmd+1
lda cnt
ldx cnt+1
-fixup12:sta txlen
-fixup13:stx txlen+1
+fixup16:sta txlen
+fixup17:stx txlen+1
; Adjust odd frame length
jsr adjustcnt
@@ -273,7 +297,7 @@ fixup13:stx txlen+1
; PACKETPP = $0138, PPDATA & $0100 ?
: lda #$38
jsr packetpp_a1
-fixup14:lda ppdata+1
+fixup18:lda ppdata+1
and #$01
bne :+
@@ -283,6 +307,7 @@ fixup14:lda ppdata+1
; And try again
dey
bne :-
+ sec
rts
; Send the frame
@@ -291,15 +316,16 @@ fixup14:lda ppdata+1
; Write bytes from buffer
: jsr adjustptr
: lda (ptr),y
-fixup15:sta rxtxreg
+fixup19:sta rxtxreg
iny
lda (ptr),y
-fixup16:sta rxtxreg+1
+fixup20:sta rxtxreg+1
iny
bne :-
inc ptr+1
dex
bpl :-
+ clc
rts
;---------------------------------------------------------------------
@@ -311,15 +337,16 @@ exit:
packetpp_a1:
ldx #$01
-fixup17:sta packetpp
-fixup18:stx packetpp+1
+packetpp_ax:
+fixup21:sta packetpp
+fixup22:stx packetpp+1
rts
;---------------------------------------------------------------------
ppdata_ax:
-fixup19:sta ppdata
-fixup20:stx ppdata+1
+fixup23:sta ppdata
+fixup24:stx ppdata+1
rts
;---------------------------------------------------------------------
@@ -328,9 +355,9 @@ skipframe:
; PACKETPP = $0102, PPDATA = PPDATA | $0040
lda #$02
jsr packetpp_a1
-fixup21:lda ppdata
+fixup25:lda ppdata
ora #$40
-fixup22:sta ppdata
+fixup26:sta ppdata
rts
;---------------------------------------------------------------------
diff --git a/cpu/6502/net/ethernet.c b/cpu/6502/net/ethernet.c
index c5eedc888..58c15e4d5 100644
--- a/cpu/6502/net/ethernet.c
+++ b/cpu/6502/net/ethernet.c
@@ -47,9 +47,13 @@ struct {
struct uip_eth_addr ethernet_address;
uint8_t *buffer;
uint16_t buffer_size;
- void __fastcall__ (* init)(uint16_t reg);
+ char jmp_init;
+ char __fastcall__ (* init)(uint16_t reg);
+ char jmp_poll;
uint16_t (* poll)(void);
+ char jmp_send;
void __fastcall__ (* send)(uint16_t len);
+ char jmp_exit;
void (* exit)(void);
} *module;
@@ -97,7 +101,10 @@ ethernet_init(struct ethernet_config *config)
module->buffer = uip_buf;
module->buffer_size = UIP_BUFSIZE;
- module->init(config->addr);
+ if(module->init(config->addr)) {
+ log_message(config->name, ": No hardware");
+ error_exit();
+ }
uip_setethaddr(module->ethernet_address);
}
diff --git a/cpu/6502/net/lan91c96.S b/cpu/6502/net/lan91c96.S
index 926e9c2c2..52a43f9f7 100644
--- a/cpu/6502/net/lan91c96.S
+++ b/cpu/6502/net/lan91c96.S
@@ -49,10 +49,10 @@ bufaddr:.res 2 ; Address
bufsize:.res 2 ; Size
; Jump table.
- .addr init
- .addr poll
- .addr send
- .addr exit
+ jmp init
+ jmp poll
+ jmp send
+ jmp exit
;---------------------------------------------------------------------
@@ -89,7 +89,7 @@ fixup: .byte fixup02-fixup01, fixup03-fixup02, fixup04-fixup03
.byte fixup29-fixup28, fixup30-fixup29, fixup31-fixup30
.byte fixup32-fixup31, fixup33-fixup32, fixup34-fixup33
.byte fixup35-fixup34, fixup36-fixup35, fixup37-fixup36
- .byte fixup38-fixup37
+ .byte fixup38-fixup37, fixup39-fixup38, fixup40-fixup39
fixups = * - fixup
@@ -195,51 +195,58 @@ fixup06:stx ethrcr+1
lda #$01 ; Bank 1
fixup07:sta ethbsr
-fixup08:lda ethcr+1
+ ; Check ISA mode base address register for reset values
+ lda #$18^67 ; I/O base $300 + ROM $CC000
+fixup08:eor ethbar
+fixup09:eor ethbar+1
+ beq :+
+ sec
+ rts
+
+:
+fixup10:lda ethcr+1
ora #%00010000 ; No wait (IOCHRDY)
-fixup09:sta ethcr+1
+fixup11:sta ethcr+1
lda #%00001001 ; Auto release
-fixup10:sta ethctr+1
+fixup12:sta ethctr+1
; Set MAC address
ldy #$00
: lda mac,y
-fixup11:sta ethiar,y
+fixup13:sta ethiar,y
iny
cpy #$06
bcc :-
; Set interrupt mask
lda #$02 ; Bank 2
-fixup12:sta ethbsr
+fixup14:sta ethbsr
lda #%00000000 ; No interrupts
-fixup13:sta ethmsk
+fixup15:sta ethmsk
+ tax
+ clc
rts
;---------------------------------------------------------------------
poll:
-fixup14:lda ethist
+fixup16:lda ethist
and #%00000001 ; RCV INT
- bne :+
-
- ; No packet available
- tax
- rts
+ beq :+
; Process the incoming packet
; ---------------------------
-: lda #$00
+ lda #$00
ldx #%11100000 ; RCV, AUTO INCR., READ
-fixup15:sta ethptr
-fixup16:stx ethptr+1
+fixup17:sta ethptr
+fixup18:stx ethptr+1
; Last word contains 'last data byte' and $60 or 'fill byte' and $40
-fixup17:lda ethdata ; Status word
-fixup18:lda ethdata ; Need high byte only
+fixup19:lda ethdata ; Status word
+fixup20:lda ethdata ; Need high byte only
; Move ODDFRM bit into carry:
; - Even packet length -> carry clear -> subtract 6 bytes
@@ -251,10 +258,10 @@ fixup18:lda ethdata ; Need high byte only
lsr
; The packet contains 3 extra words
-fixup19:lda ethdata ; Total number of bytes
+fixup21:lda ethdata ; Total number of bytes
sbc #$05 ; Actually 5 or 6 depending on carry
sta len
-fixup20:lda ethdata
+fixup22:lda ethdata
sbc #$00
sta len+1
@@ -263,22 +270,23 @@ fixup20:lda ethdata
cmp len
lda bufsize+1
sbc len+1
- bcs :+
+ bcs :++
; Yes, skip packet
; Remove and release RX packet from the FIFO
lda #%10000000
-fixup21:sta ethmmucr
+fixup23:sta ethmmucr
; No packet available
lda #$00
- tax
+: tax
+ sec
rts
; Read bytes into buffer
: jsr adjustptr
:
-fixup22:lda ethdata
+fixup24:lda ethdata
sta (ptr),y
iny
bne :-
@@ -288,11 +296,12 @@ fixup22:lda ethdata
; Remove and release RX packet from the FIFO
lda #%10000000
-fixup23:sta ethmmucr
+fixup25:sta ethmmucr
; Return packet length
lda len
ldx len+1
+ clc
rts
;---------------------------------------------------------------------
@@ -305,14 +314,14 @@ send:
; Allocate memory for TX
txa
ora #%00100000
-fixup24:sta ethmmucr
+fixup26:sta ethmmucr
; 8 retries
ldy #$08
; Wait for allocation ready
:
-fixup25:lda ethist
+fixup27:lda ethist
and #%00001000 ; ALLOC INT
bne :+
@@ -322,25 +331,26 @@ fixup25:lda ethist
; And try again
dey
bne :-
+ sec
rts
; Acknowledge interrupt, is it necessary ???
: lda #%00001000
-fixup26:sta ethack
+fixup28:sta ethack
; Set packet address
-fixup27:lda etharr
-fixup28:sta ethpnr
+fixup29:lda etharr
+fixup30:sta ethpnr
lda #$00
ldx #%01000000 ; AUTO INCR.
-fixup29:sta ethptr
-fixup30:stx ethptr+1
+fixup31:sta ethptr
+fixup32:stx ethptr+1
; Status written by CSMA
lda #$00
-fixup31:sta ethdata
-fixup32:sta ethdata
+fixup33:sta ethdata
+fixup34:sta ethdata
; Check packet length parity:
; - Even packet length -> carry set -> add 6 bytes
@@ -352,10 +362,10 @@ fixup32:sta ethdata
; The packet contains 3 extra words
lda len
adc #$05 ; Actually 5 or 6 depending on carry
-fixup33:sta ethdata
+fixup35:sta ethdata
lda len+1
adc #$00
-fixup34:sta ethdata
+fixup36:sta ethdata
; Send the packet
; ---------------
@@ -363,7 +373,7 @@ fixup34:sta ethdata
; Write bytes from buffer
jsr adjustptr
: lda (ptr),y
-fixup35:sta ethdata
+fixup37:sta ethdata
iny
bne :-
inc ptr+1
@@ -381,13 +391,14 @@ fixup35:sta ethdata
; No
: lda #$00
-fixup36:sta ethdata ; Fill byte
+fixup38:sta ethdata ; Fill byte
:
-fixup37:sta ethdata ; Control byte
+fixup39:sta ethdata ; Control byte
; Add packet to FIFO
lda #%11000000 ; ENQUEUE PACKET - transmit packet
-fixup38:sta ethmmucr
+fixup40:sta ethmmucr
+ clc
rts
;---------------------------------------------------------------------
diff --git a/cpu/6502/net/w5100.S b/cpu/6502/net/w5100.S
index c38b22459..f200a31fb 100644
--- a/cpu/6502/net/w5100.S
+++ b/cpu/6502/net/w5100.S
@@ -48,10 +48,10 @@ bufaddr:.res 2 ; Address
bufsize:.res 2 ; Size
; Jump table.
- .addr init
- .addr poll
- .addr send
- .addr exit
+ jmp init
+ jmp poll
+ jmp send
+ jmp exit
;---------------------------------------------------------------------
@@ -96,7 +96,8 @@ fixup: .byte fixup02-fixup01, fixup03-fixup02, fixup04-fixup03
.byte fixup17-fixup16, fixup18-fixup17, fixup19-fixup18
.byte fixup20-fixup19, fixup21-fixup20, fixup22-fixup21
.byte fixup23-fixup22, fixup24-fixup23, fixup25-fixup24
- .byte fixup26-fixup25
+ .byte fixup26-fixup25, fixup27-fixup26, fixup28-fixup27
+ .byte fixup29-fixup28, fixup30-fixup29
fixups = * - fixup
@@ -144,23 +145,40 @@ init:
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
+
; S/W Reset
: lda #$80
-fixup01:sta mode
+fixup05:sta mode
:
-fixup02:lda mode
+fixup06:lda mode
bmi :-
; Indirect Bus I/F mode, Address Auto-Increment, Ping Block
lda #$13
-fixup03:sta mode
+fixup07:sta mode
; Source Hardware Address Register: MAC Address
ldx #$00 ; Hibyte
ldy #$09 ; Lobyte
jsr set_addr
: lda mac,x
-fixup04:sta data
+fixup08:sta data
inx
cpx #$06
bcc :-
@@ -171,17 +189,20 @@ fixup04:sta data
ldy #$1A ; Lobyte
jsr set_addr
lda #$03
-fixup05:sta data
-fixup06:sta data
+fixup09:sta data
+fixup10:sta data
; Socket 0 Mode Register: MACRAW, MAC Filter
; Socket 0 Command Register: OPEN
ldy #$00
jsr set_addrsocket0
lda #$44
-fixup07:sta data
+fixup11:sta data
lda #$01
-fixup08:sta data
+fixup12:sta data
+ tya
+ tax
+ clc
rts
;---------------------------------------------------------------------
@@ -190,19 +211,20 @@ poll:
; Check for completion of previous command
; Socket 0 Command Register: = 0 ?
jsr set_addrcmdreg0
-fixup09:lda data
+fixup13: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
-fixup10:lda data ; Hibyte
-fixup11:ora data ; Lobyte
+fixup14:lda data ; Hibyte
+fixup15:ora data ; Lobyte
beq :--
; Process the incoming data
@@ -268,17 +290,18 @@ common: jsr set_addrsocket0
tax
lda reg+1
adc adv+1
-fixup12:sta data ; Hibyte
-fixup13:stx data ; Lobyte
+fixup16:sta data ; Hibyte
+fixup17:stx data ; Lobyte
; Set command register
tya ; Restore command
jsr set_addrcmdreg0
-fixup14:sta data
+fixup18:sta data
; Return data length (will be ignored for send)
lda len
ldx len+1
+ clc
rts
;---------------------------------------------------------------------
@@ -300,14 +323,14 @@ send:
; Wait for completion of previous command
; Socket 0 Command Register: = 0 ?
: jsr set_addrcmdreg0
-fixup15:lda data
+fixup19:lda data
bne :-
; Socket 0 TX Free Size Register: < length ?
: ldy #$20 ; Socket TX Free Size Register
jsr set_addrsocket0
-fixup16:lda data ; Hibyte
-fixup17:ldx data ; Lobyte
+fixup20:lda data ; Hibyte
+fixup21:ldx data ; Lobyte
cpx len
sbc len+1
bcc :-
@@ -337,16 +360,16 @@ exit:
;---------------------------------------------------------------------
set_addrphysical:
-fixup18:lda data ; Hibyte
-fixup19:ldy data ; Lobyte
+fixup22:lda data ; Hibyte
+fixup23:ldy data ; Lobyte
sty reg
sta reg+1
and #>$1FFF ; Socket Mask Address (hibyte)
ora bas ; Socket Base Address (hibyte)
tax
set_addr:
-fixup20:stx addr ; Hibyte
-fixup21:sty addr+1 ; Lobyte
+fixup24:stx addr ; Hibyte
+fixup25:sty addr+1 ; Lobyte
rts
set_addrcmdreg0:
@@ -361,7 +384,7 @@ set_addrbase:
beq set_addr ; Always
get_datacheckaddr:
-fixup22:lda data
+fixup26:lda data
iny ; Physical address shadow (lobyte)
bne :+
inx ; Physical address shadow (hibyte)
@@ -402,10 +425,10 @@ mov_data:
; R/W without address wraparound possible because
; highest R/W address > actual R/W address ?
; sec
-fixup23:sbc addr+1 ; Lobyte
+fixup27:sbc addr+1 ; Lobyte
tay
txa
-fixup24:sbc addr ; Hibyte
+fixup28:sbc addr ; Hibyte
tax
tya
bcs :+
@@ -466,7 +489,7 @@ rw_data:eor #$FF ; Two's complement part 1
; Read data
:
-fixup25:lda data
+fixup29:lda data
sta (ptr),y
iny
bne :-
@@ -477,7 +500,7 @@ fixup25:lda data
; Write data
: lda (ptr),y
-fixup26:sta data
+fixup30:sta data
iny
bne :-
inc ptr+1