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