updated LAN driver

This commit is contained in:
HenrykRichter
2019-03-20 09:02:11 +01:00
parent ec9088d70d
commit f97e75d972
20 changed files with 450 additions and 331 deletions
+12
View File
@@ -64,6 +64,18 @@ PRIORITY=PRI/K/N,BPS/K/N,MTU/K/N,FULLDUPLEX/S,FLOWCONTROL/S,TIMER/K/N,MULTICAST/
Changelog:
----------
2.2 - some more tuning to RX/TX scheduling
- added optional debug code to lowlevel routines
- removed some obsolete bus transfers
- uses DMACopyFromBuffer for IP-stacks supporting
this capability
- explicit 32 bit alignment for RX/TX to speed up
ZIII transfers
- added experimental support for MII interface to
poll and modify speed and duplex settings on the
fly
- miitool added (see README.miitool)
2.00 - improved RX speed for buffer wraparound cases
- some more safety checks for boards with unresponsive
ENC chips (explicit card bus clear before verification of
+8 -1
View File
@@ -18,7 +18,11 @@ combination. Please note that fixed parameters must be set at both
ends of the link. Otherwise the link will work slowly or not at all.
None of the settings this tool applies is permanent. Changed parameters
are only valid until a reboot of the NIC.
are only valid until the next reset of the NIC.
This utility is able to detect an active Ethernet interface in case that
the RoadShow TCP/IP stack is active. Otherwise, the device needs to be
passed as commandline option explicitly.
Examples for usage are given at the end of this text.
@@ -80,6 +84,9 @@ Valid Speed/Duplex combinations (not case sensitive):
Examples:
current status (detailed, autodetect)
miitool v
current status (detailed):
miitool DEV=enc624j6net.device v
-102
View File
@@ -1,102 +0,0 @@
VWiznet - A SANA-II driver for W5500 10/100 ethernet modules
Copyright (C) 2018-2019 Henryk Richter <henryk.richter@gmx.net>
This driver is supposed to support W5500 modules hooked up to the expansion
port of Vampire 500V2+ cards.
Installation:
-------------
Installation of the driver is straightforward.
Just copy vwiznet500ex.device from the bin subdirectory to devs:networks
and enable the interface in your favorite TCP/IP stack as usual. So far,
successful tests have been done with the free AmiTCP/IP 3.0b2, AmiTCP4.0-4.2,
Genesis, MiamiDX and RoadShow.
The minimum system requirement is the Gold 2.10 release of Apollo Core
for Vampire 500V2+.
Vampire500 Expansion port Hardware
-----------------------------------
Please see http://wiki.apollo-accelerators.com/doku.php/expansionport for
guidance on pinout of the expansion port.
The W5500 can be clocked way higher than the ENC28J60 that was used for
SDNet. As a consequence of clocks beyond 25 MHz, signal integrity is of
some concern. Therefore it is suggested to connect the module is as close
as possible to the expansion port and use an Ethernet expansion cable
in order to reach the edge of the computer case.
An adapter PCB is in the making. That PCB plugs directly into the Vampire
expansion port, connects readily available W5500 modules on the other
side and contains some components to keep signal integrity in a good shape.
Options
-------
Below you find the options accepted by the driver. Please note that no special
configuration is necessary for normal operation. What you find documented below
is available for tuning purposes.
The options template for the config files
ENVARC:SANA2/vwiznet500ex.config
is as follows:
PRIORITY=PRI/K/N,BPS/K/N,MTU/K/N,SPISPEED/K/N,TIMER/K/N,NOINTERRUPT/S
SPISPEED - SPI clock divider (1-10, default 1), controls maximum
clock of SPI bus. Actual I/O clock is Core_Clock/(3+SPISPEED).
PRIORITY - server task priority (default 1)
BPS - bit per seconds for statistics purposes
MTU - maximum transmission unit (default 1500)
NOINTERRUPT - disable hardware interrupt and use polling instead
(default: interrupt enabled)
TIMER - when disabling interrupt you also need to specify
a timer interval in microseconds
(default: 0, i.e. no timer)
example1 (useful for DSL via PPPoE,
higher priority for server task = more speed with AmiTCP
at the expense of multitasking friendliness):
echo "MTU=1492 SPISPEED=1 PRIORITY=6" >ENVARC:sana2/vwiznet500ex.config
Changelog:
----------
1.99 - re-enabled 32 Bit Buffer copies (unless Miami is active)
- default server task priority for AmiTCP=6 (otherwise 0)
- tuned RX/TX balancing to make RoadShow happy
- added Packet Filter hook processing (needs testing)
1.98 - preparations for V2 of the adapter PCB: hardware based reset
1.97 - added New style device commands
- implemented SANA-II Device Query Extension
1.96 - tuned defaults
1.95 - initial build, aligned with sdnet/v2expeth version
Copyrights / License:
---------------------
Copyright (C) 2018-2019 Henryk Richter <henryk.richter@gmx.net>, all rights reserved.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+41 -22
View File
@@ -25,11 +25,15 @@ compiler_vcc = 1
###############################################################################
# prefix for system includes (ASM)
#
# native AmigaOS compilation: set PREFX=GG: or PREFX=ADE:, depending on toolchain
###############################################################################
PREFX = c:/Users/Matze/Amiga/development/VBCC/
PREFX = /opt/amigaos-68k/
#PREFX = gg:
SYSINC = $(PREFX)NDK39/Include/include_i
#PREFX = c:/Users/Matze/Amiga/development/VBCC/
SYSINC = $(PREFX)os-include
#SYSINC = $(PREFX)NDK39/Include/include_i
###############################################################################
#
@@ -41,6 +45,7 @@ ifeq ($(compiler_vcc),1)
# VBCC (use explicit vlink line for LINK= if complaints about R_PC happen)
CCX = vc
LINK = vlink -bamigahunk -x -s -mrel -Cvbcc -Bstatic -nostdlib #-Rshort
LINKEXE = vlink -bamigahunk -x -s -mrel -Cvbcc -Bstatic
#LINK = $(CCX) -nostdlib
CFLAGS = -Os -+ -sc -c99 -cpu=$(CPU)
CFLAGS2 = -Os -+ -sc -c99 -cpu=$(CPU2)
@@ -50,6 +55,7 @@ else
# GCC
CCX = m68k-amigaos-gcc
LINK = $(CCX) -nostartfiles -s
LINKEXE = $(CCX) -s -noixemul
CFLAGS = -O3 -s -m$(CPU) -Wall -noixemul -mregparm=4 -fomit-frame-pointer -msoft-float -noixemul
CFLAGS2 = -O3 -s -m$(CPU2) -Wall -noixemul -mregparm=4 -fomit-frame-pointer -msoft-float -noixemul
@@ -77,29 +83,41 @@ IPATH =
###############################################################################
ifeq ($(compiler_vcc),1)
# skip quotes with VCC, the AmigaOS native version doesn't like them
DEFINES += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
DEFINES += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME="$(DEVICEID)"
DEFINES += -DDEVICEEXTRA=$(DEVICEEXTRA)
ASMDEFS += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
#DEFINES += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
#DEFINES += -DDEVICEDATE=$(DEVICEDATE)
#DEFINES += -DDEVICEEXTRA=$(DEVICEEXTRA)
DEFINES += -DDEVICENAME="$(DEVICEID)"
DEFINES += -DHAVE_VERSION_H=1
DEFINES += -DNEWSTYLE
#ASMDEFS += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
#ASMDEFS += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME=$(DEVICEID)
DEFINES2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
DEFINES2 += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME="$(DEVICEID2)"
DEFINES2 += -DDEVICEEXTRA=$(DEVICEEXTRA)
ASMDEFS2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
#DEFINES2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
#DEFINES2 += -DDEVICEDATE=$(DEVICEDATE)
#DEFINES2 += -DDEVICEEXTRA=$(DEVICEEXTRA)
DEFINES2 += -DDEVICENAME="$(DEVICEID2)"
DEFINES2 += -DHAVE_VERSION_H=1
DEFINES2 += -DNEWSTYLE
#ASMDEFS2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
else
DEFINES += -D"DEVICEVERSION=$(DEVICEVERSION)" -D"DEVICEREVISION=$(DEVICEREVISION)"
DEFINES += -D"DEVICEDATE=$(DEVICEDATE)" -D"DEVICENAME="$(DEVICEID)""
DEFINES += -D"DEVICEEXTRA=$(DEVICEEXTRA)"
ASMDEFS += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
#DEFINES += -D"DEVICEVERSION=$(DEVICEVERSION)" -D"DEVICEREVISION=$(DEVICEREVISION)"
#DEFINES += -D"DEVICEDATE=$(DEVICEDATE)"
#DEFINES += -D"DEVICEEXTRA=$(DEVICEEXTRA)"
DEFINES += -D"DEVICENAME="$(DEVICEID)""
DEFINES += -DHAVE_VERSION_H=1
DEFINES += -DNEWSTYLE
#ASMDEFS += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
#ASMDEFS += -DDEVICEDATE=$(DEVICEDATE) -DDEVICENAME=$(DEVICEID)
DEFINES2 += -D"DEVICEVERSION=$(DEVICEVERSION)" -D"DEVICEREVISION=$(DEVICEREVISION)"
DEFINES2 += -D"DEVICEDATE=$(DEVICEDATE)" -D"DEVICENAME="$(DEVICEID2)""
DEFINES2 += -D"DEVICEEXTRA=$(DEVICEEXTRA)"
ASMDEFS2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
#DEFINES2 += -D"DEVICEVERSION=$(DEVICEVERSION)" -D"DEVICEREVISION=$(DEVICEREVISION)"
#DEFINES2 += -D"DEVICEDATE=$(DEVICEDATE)" -D"DEVICENAME="$(DEVICEID2)""
#DEFINES2 += -D"DEVICEEXTRA=$(DEVICEEXTRA)"
DEFINES2 += -D"DEVICENAME="$(DEVICEID2)""
DEFINES2 += -DHAVE_VERSION_H=1
DEFINES2 += -DNEWSTYLE
#ASMDEFS2 += -DDEVICEVERSION=$(DEVICEVERSION) -DDEVICEREVISION=$(DEVICEREVISION)
endif
@@ -112,7 +130,8 @@ endif
ifeq ($(debug),1)
CFLAGS += -DDEBUG -g
CFLAGS2 += -DDEBUG -g
LINKLIBS = -L$(PREFX)targets/m68k-amigaos/lib -ldebug
LINKLIBS = -L$(PREFX)/lib -L$(PREFX)targets/m68k-amigaos/lib -ldebug
#LINKLIBS = -L$(PREFX)targets/m68k-amigaos/lib -ldebug
endif
###############################################################################
@@ -144,11 +163,11 @@ OBJECTS2 = $(patsubst %.o,%.2o,$(OBJECTS))
#
###############################################################################
all: $(DEVICEID) $(DEVICEID2)
all: $(DEVICEID) $(DEVICEID2) $(TESTTOOL) $(TESTTOOL2)
clean:
rm -f $(OBJECTS) $(OBJECTS2)
rm -f $(DEVICEID) $(DEVICEID2)
rm -f $(DEVICEID) $(DEVICEID2) $(EXTRACLEAN)
# not for cross compile :-)
install: $(DEVICEID) $(DEVICEID2)
Binary file not shown.
Binary file not shown.
+113 -107
View File
@@ -1,4 +1,3 @@
;APS00000000000000000000000000000000000000000000000000000000000000000000000000000000
; ------------------------------------------------------------------------------
; | Lowlevel Access to memory mapped ENC624J600 in PSP mode |
; | Henryk Richter <henryk.richter@gmx.net> |
@@ -20,14 +19,14 @@
; - _enc624j6l_RXReset -> won't recover from totally unresponsive chip (but exits gracefully)
;
; enable debugging code block (comment/uncomment, see below)
;DEBUG EQU 1
DEBUG EQU 1
GLOBALINT_BOARD EQU 1 ;if 1, then toggle board interrupt, else ENC624 INTIE
incdir src:baxnet/trunk/source/
;Temp:Amiga/src/Zorro-LAN-IDE.git/Driver/enc624j6net/
include "enc624j6net/registers.i"
include "enc624j6net/macros.i"
include "debug.i"
include "hw.i"
ifnd DEBUG
DEBUG EQU 0
@@ -41,7 +40,7 @@ _OPT_LONGRESET EQU 0 ;in testing, don't enable
;
; options for buffer memory configuration, please reserve some space for private variables
;
PSTART_INIT EQU $0BF0 ; 16 Bytes private storage for driver
PSTART_INIT EQU $0BF8 ; 8 Bytes private storage for driver
PSTOP_INIT EQU $0BFF ; (see below for definitions)
RXSTART_INIT EQU $0C00 ; start of RX buffer, room for 14 packets
@@ -57,10 +56,8 @@ MAX_FRAMELEN EQU 1518
;------------ driver private storage ------------------------------
PNextPacket EQU PSTART_INIT ;2 Bytes - private "next packet" pointer for RX
PNextTX EQU PSTART_INIT+2 ;2 Bytes - private "next packet" pointer for TX (init as 0)
PSigBit EQU PSTART_INIT+4 ;2 Bytes interrupt bit
PSigTask EQU PSTART_INIT+6 ;4 Bytes signaled task
PLinkChange EQU PSTART_INIT+10 ;2 Bytes Link Change (copy of PHYDPX,PHYLNK bits)
Punused EQU PSTART_INIT+12 ;
PLinkChange EQU PSTART_INIT+4 ;2 Bytes Link Change (copy of PHYDPX,PHYLNK bits)
Punused EQU PSTART_INIT+6 ;
;------------- TX: double buffering --------------------------------
PSwapTX EQU $600 ;swap between two TX buffers (one active, one activated after last TX done)
@@ -560,6 +557,8 @@ _enc624j6l_Init:
move.l a0,d0
beq .err
WRITEDEBUG Init_MSG,a0
READREG ESTAT,a0,d0
and #(ESTAT_CLKRDY|ESTAT_PHYRDY),d0
cmp #(ESTAT_CLKRDY|ESTAT_PHYRDY),d0
@@ -787,20 +786,13 @@ _enc624j6l_EnableInterrupt:
move.l a0,d1
beq.s .err
WRITEREG PSigBit,a0,d0 ;save signal bit
move.l a1,d0
WRITEREG PSigTask+2,a0,d0 ;lower two bytes
swap d0 ;
WRITEREG PSigTask,a0,d0 ;upper two bytes
; enable interrupt for incoming packet
moveq #-1,d0 ;magic trick: the board enables Interrupts
lea $4000(a0),a0
move.w d0,($4000,a0)
lea -$4000(a0),a0
move #EIE_PKTIE|EIE_PCFULIE|EIE_INTIE,d0
move #EIE_PKTIE|EIE_INTIE|EIE_PCFULIE,d0
SETREG EIE,a0,d0
moveq #1,d0
@@ -823,8 +815,20 @@ _enc624j6l_EnableInterrupt:
; Notes: assumes that init() was called before
;
_enc624j6l_EnableGlobalInterrupt:
move #EIE_PKTIE|EIE_PCFULIE|EIE_INTIE,d0 ; move #EIE_INTIE,d0
ifne GLOBALINT_BOARD
moveq #-1,d0 ;magic trick: the board enables Interrupts
lea $4000(a0),a0
move.w d0,($4000,a0)
lea -$4000(a0),a0
else ;GLOBALINT_BOARD
move #EIE_PKTIE|EIE_INTIE|EIE_PCFULIE,d0
SETREG EIE,a0,d0
endc ;GLOBALINT_BOARD
moveq #1,d0
.rts
rts
@@ -842,8 +846,21 @@ _enc624j6l_EnableGlobalInterrupt:
; Notes: assumes that init() was called before
;
_enc624j6l_DisableGlobalInterrupt:
ifne GLOBALINT_BOARD
moveq #0,d0 ;magic trick: the board enables Interrupts
lea $4000(a0),a0
move.w d0,($4000,a0)
lea -$4000(a0),a0
else ;GLOBALINT_BOARD
move #EIE_INTIE,d0
CLRREG EIE,a0,d0
endc ;GLOBALINT_BOARD
moveq #1,d0
.rts
rts
@@ -878,10 +895,6 @@ _enc624j6l_DisableInterrupt:
move #EIE_INTIE|EIE_PKTIE|EIE_LINKIE|EIE_AESIE|EIE_MODEXIE|EIE_HASHIE|EIE_PRDYIE|EIE_DMAIE|EIE_TXIE|EIE_TXABTIE|EIE_RXABTIE|EIE_PCFULIE,d0
CLRREG EIE,a0,d0
moveq #0,d0
WRITEREG PSigTask+2,a0,d0 ;lower two bytes
WRITEREG PSigTask,a0,d0 ;upper two bytes
moveq #1,d0
.err:
rts
@@ -905,35 +918,50 @@ _enc624j6l_DisableInterrupt:
; ULONG sigbit
;
_enc624j6l_IntServer_List:
move.l a6,-(sp)
move.l a1,d0 ;no pointer supplied ? -> return
beq.s .end
movem.l d1/A1/a6,-(sp)
beq.s .rts
move.l a1,a6
moveq #0,d1
move.l (A6)+,d0 ;read magic word
cmp.l #HW_MAGIC_WORD,D0 ; are we in the right structure?
bne.s .done
.boardloop:
move.l (A6)+,d0 ;next entry from list
move.l (a1)+,d0 ;next entry from list
beq.s .done ;
move.l d0,a1 ;current board
move.l d0,a0 ;current board
READREG EIR,A1,d0 ;get interrupt status reg
and #EIR_PKTIF|EIR_PCFULIF,D0
beq.s .boardloop ;no interrupt here
or.l d0,D1 ; save if at least one one board has interrupted
move #EIE_INTIE,D0 ;disable board interrupt until someone enables it again
CLRREG EIE,A1,d0
BRA.s .boardloop
READREG EIR,a0,d0 ;get interrupt status reg
and #EIR_PKTIF|EIR_PCFULIF|EIR_RXABTIF|EIR_PKTIF|EIR_TXABTIF,d0
or.l d0,d1
bra.s .boardloop
.done:
tst.w d1
beq.s .rts
; clear EIE_INTIE in all active boards directly from here
.intdis_loop:
move.l (a6)+,d0
beq.s .boardsdone
move.l d0,a1
ifne GLOBALINT_BOARD
moveq #0,d0 ;magic trick: the board enables Interrupts
lea $4000(a1),a1
move.w d0,($4000,a1)
else ;GLOBALINT_BOARD
move #EIE_INTIE,D0 ;disable board interrupt until someone enables it again
CLRREG EIE,A1,d0
endc ;GLOBALINT_BOARD
bra.s .intdis_loop
.boardsdone:
;faster: get from extended Driver board list instead from ZII/ZIII card
ifne 1
move.l (a6)+,d0 ;SigTask
beq.s .rts
@@ -941,33 +969,16 @@ _enc624j6l_IntServer_List:
move.l (a6)+,d1 ;SigBit
move.l d0,a1 ;SigTask
move.l (a6)+,a6 ;ExecBase
move.l (a6)+,a6 ;ExecBase (from FastRAM)
;move.l 4.w,a6
moveq #0,d0
bset d1,d0
else
READREG PSigTask,a0,d0 ;upper two bytes
swap d0 ;
READREG PSigTask+2,a0,d0 ;lower two bytes
tst.l d0 ; no task ?
beq.s .rts
move.l d0,a1 ; signaled task
moveq #0,d0
READREG PSigBit,a0,d1 ;get signal bit
bset d1,d0 ;signal mask
move.l 4.w,a6
endc
jsr _LVOSignal(a6)
.rts
movem.l (sp)+,D1/A1/A6
.end
move.l (sp)+,a6
moveq #0,d0 ;set Z flag
rts
@@ -1071,7 +1082,11 @@ _enc624j6l_CheckLinkChange:
;
ifne DEBUG
RXReset_MSG: dc.b "RXReset Head %04lx Tail %04lx NextPacket %04lx ReadPTR %04lx Bytes %04lx",10,0
RXReset_MSG: dc.b "RXReset Head %04lx Tail %04lx NextPacket %04lx NextReadPTR %04lx Bytes(maybe) %04lx ESTAT %04lx",13,10,0
Init_MSG: dc.b "ENC624j6net init (debug build) board address %lx",13,10,0
TXWait_MSG: dc.b "TransmitFrame: waiting",13,10,0
TXAbort_MSG: dc.b "TransmitFrame: abort",13,10,0
cnop 0,4
endc
_enc624j6l_RXReset:
@@ -1084,6 +1099,8 @@ _enc624j6l_RXReset:
moveq #0,d1
moveq #0,d2
moveq #0,d3
moveq #0,d7
READREG ESTAT,a0,d7
READREG ERXHEAD,A0,d0
READREG ERXTAIL,A0,d1
READREG PNextPacket,a0,d2
@@ -1100,10 +1117,7 @@ _enc624j6l_RXReset:
rol.w #8,d4 ;swap pointer to Big Endian
endc
WRITEDEBUG RXReset_MSG,d0,d1,d2,d3,d4
WRITEDEBUG RXReset_MSG,d0,d1,d2,d3,d4,d7
movem.l (sp)+,d2-d7
endc
@@ -1202,8 +1216,10 @@ _enc624j6l_RecvFrame: ;
beq .rts ;nothing in buffer, return sheer emptiness
;at least one frame in buffer
ifne DEBUG
READREG ERXHEAD,A0,d4
READREG ERXTAIL,A0,d5
endc
;----------- check next packet pointer and verify expected state -----------
READREG PNextPacket,a0,d7 ;get user read pointer from private space
@@ -1215,15 +1231,6 @@ _enc624j6l_RecvFrame: ;
rol.w #8,d0 ;swap pointer to Big Endian
endc
; btst #0,d0
; beq.s .nozerobit
; nop
;.nozerobit
; btst #0,d7
; beq.s .nozerobit2
; nop
;.nozerobit2
;verify next packet pointer, re-initialize recv if this is invalid
cmp #RXSTOP_INIT,d0 ;bad pointer (<0 or >end of memory)
bhi.w .recv_err
@@ -1238,55 +1245,40 @@ _enc624j6l_RecvFrame: ;
add.w d0,d1 ;next pkt + unwrap distance
.ptrcheck:
sub.w d7,d1 ;length of pkt
cmp #MAX_FRAMELEN+2+6,d1 ;must be smaller than max framelen + ptr + status vector
cmp #MAX_FRAMELEN+2+6+2,d1 ;must be smaller than max framelen + ptr + status vector + alignment
bhi .recv_err ;-> reinit recv (am I paranoid ? -> try ENC28J60, then you know why...)
;debug: collect packet positions
;move.l recvptr,a2
;move d0,(a2)+
;move.l a2,recvptr
;addq.l #1,recvcount
;cmp.l #65536,recvcount
;bgt .recv_err
WRITEREG PNextPacket,a0,d0 ;write pointer for next packet
;------------------ check receive status vector -----------------------------
addq.w #2,d7 ;increment pointer
WRAPINDEX d7 ;wrap D7 if beyond buffer
;lea (a0,d7.w),a2 ;read ptr for first control word
;READREG 0,a2,d0 ;last control word = length (byte count)
READSRAM a0,d7,d0 ;move (a0,d7.w),d0
ifeq _OPT_BUFFER_SWAP
rol.w #8,d0 ;swap pointer to Big Endian
endc
and.w #$f800,d0 ;verify (should be all zeros in upper 9 bits)
ifne 0
READSRAM a0,d7,d2 ;move (a0,d7.w),d0
ifeq _OPT_BUFFER_SWAP
rol.w #8,d2 ;swap pointer to Big Endian
endc
and.w #$f800,d2 ;verify (should be all zeros in upper 9 bits)
bne .recv_err ;receive buffer is wrong -> re-initialize
endc
addq.w #4,d7 ;increment pointer
WRAPINDEX d7 ;wrap D7 if beyond buffer
WRITEREG PNextPacket,a0,d0 ;write pointer for next packet
ifne 0
;lea (a0,d7.w),a2 ;new read pointer for length
;READREG 0,a2,d0 ;last control word = length (byte count)
READSRAM a0,d7,d0 ;move (a0,d7.w),d0
READSRAM a0,d7,d2 ;move (a0,d7.w),d0
ifeq _OPT_BUFFER_SWAP
rol.w #8,d0 ;swap pointer to Big Endian
endc
rol.w #8,d2 ;swap pointer to Big Endian
endc ;_OPT_BUFFER_SWAP
endc ;0
ifne 1
;D1 is the distance to the next frame = stored length + recv vevtor
sub #6+2,d1 ;STATUS VECTOR, Pointer
subq #6+2,d1 ;STATUS VECTOR, Pointer
move d1,d0 ;
else
cmp #2,d0
blt .recv_err ;can't be: SRC MAC 6 DST MAC 6 LEN/TYPE 2 CRC 4 (discounting variable data)
cmp #MAX_FRAMELEN,d0
bgt .recv_err
endc
subq #4,d0 ;subtract CRC length
addq.w #2,d7 ;increment pointer (skip status vector length field)
@@ -1365,6 +1357,10 @@ _enc624j6l_RecvFrame: ;
bra.s .end_read
.nooptrecv:
;DEBUG ONLY
;bra.s .emergency_slow
;DEBUG ONLY
ifeq _OPT_BUFFER_SWAP ;1
;
;wraparound aware loop for big endian buffer
@@ -1462,7 +1458,13 @@ _enc624j6l_RecvFrame: ;
rts
.err: moveq #-1,d0 ;receive error
bra.s .rts
.recv_err:
moveq #0,d0
READREG ESTAT,a0,d2 ;number of pending frames
move.b d2,d0 ;clear out count (ESTAT_PKTCNT7...ESTAT_PKTCNT0)
beq.s .rts ;nothing in buffer, return sheer emptiness
;serious problem: we need to re-initialize the recv buffer here
bsr _enc624j6l_RXReset
@@ -1613,18 +1615,22 @@ _enc624j6l_TransmitFrame:
.copydone
;---------------- wait on last frame ----------------------------------
move #200,d3
move #600,d3 ;
.txwait:
READREG ECON1,a0,d1
and.w #ECON1_TXRTS,d1
beq.s .txrdy
;100 MBit/s frame time is max. 0.12 ms (without inter-frame spacing)
;wait 20 us via CIA
moveq #20,d0
;WRITEDEBUG TXWait_MSG
;wait 5 us via CIA
moveq #5,d0
bsr _enc624j6l_UMinDelay
dbf d3,.txwait ;approx. 4ms max. wait
WRITEDEBUG TXAbort_MSG
;hmpf. abort last transmission
move #ECON1_TXRTS,d1 ;
CLRREG ECON1,a0,d1 ;
+2 -4
View File
@@ -460,9 +460,7 @@ void myhw_ControlInterrupts( DEVBASEP )
ObtainSemaphore( &hwd->hwd_Sem ); /* redundant here: server is a single task -> but it looks good :-) */
hwd->hwd_act_boards[0] = HW_MAGIC_WORD;
flag = 1;
flag = 0;
for( i=0 ; i < db->db_NBoards ; i++ )
{
if( db->db_Units[i].duh_online )
@@ -476,7 +474,7 @@ void myhw_ControlInterrupts( DEVBASEP )
hwd->hwd_act_boards[flag+2] = (APTR)hwd->hwd_IntSig; /* append sigbit */
hwd->hwd_act_boards[flag+3] = (APTR)db->db_SysBase; /* append ExecBase *((APTR*)0x4); */
if( flag>1 ) /* determine on/off switch */
if( flag ) /* determine on/off switch */
{
/* at least 1 board is online */
if( hwd->hwd_Interrupt.is_Data )
+4 -3
View File
@@ -1,6 +1,7 @@
incdir include:
ifnd _LVOSupervisor
include exec/exec_lib.i
include lvo/exec_lib.i
;include exec/exec_lib.i
endc
include exec/execbase.i
@@ -18,7 +19,7 @@ _LVORawMayGetChar equ -$1fe
;A0 = format
;A1 = arguments
_KPrintF:
ifd DEBUG
; ifd DEBUG
movem.l d0-d2/a0-a3/a6,-(sp)
@@ -37,7 +38,7 @@ _KPrintF:
jsr _LVORawPutChar(a6) ; move.b d0,(a3)+
movem.l (sp)+,d0/d1/a0/a1/a6
endc ;DEBUG
; endc ;DEBUG
rts
+201 -69
View File
@@ -4,7 +4,6 @@
/** SANA-II extension for access to Ethernet PHY registers over MII interface **/
/** **/
/** Copyright (c) 2019, Henryk Richter, Timm S. Müller **/
/** All rights reserved. **/
/** **/
/** Redistribution and use in source and binary forms, with or without **/
/** modification, are permitted provided that the following conditions are met: **/
@@ -16,9 +15,6 @@
/** 3. All advertising materials mentioning features or use of this software **/
/** must display the following acknowledgement: **/
/** This product includes software developed by Henryk Richter. **/
/** 4. Neither the name of the Henryk Richter 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 Henryk Richter ''AS IS'' AND ANY **/
/** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED **/
@@ -32,15 +28,22 @@
/** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **/
/** **/
/*******************************************************************************************/
/** Acknowledgements: **/
/** text and definitions in "media" table and "miitool.h" file originate from mii-tool.c **/
/** written/copyright 1997-2000 by Donald Becker **/
/*******************************************************************************************/
/*
Notes:
- make sure you have an up-to-date devices/sana2devqueryext.h
- make sure you have devices/newstyle.h
- compilation
sc miitool.c link
sc miitool.c link INCLUDEDIR=sc:netinclude
gcc miitool.c -Igg:netinclude -o miitool
- if you don`t have the Roadshow SDK installed, just comment "RSHOW" out to build
without auto-detection code
*/
#define RSHOW
#include <proto/exec.h>
#include <proto/dos.h>
@@ -49,8 +52,17 @@
#include <devices/sana2.h>
#include <devices/sana2devqueryext.h>
#include "miitool.h"
#ifdef RSHOW
#include <libraries/bsdsocket.h>
#include <proto/bsdsocket.h>
#endif
#ifdef __GNUC__
struct UtilityBase *UtilityBase;
static USHORT Utility_MY = 0;
#endif
#define OPT_TEMPLATE "DEVICE=DEV/K,UNIT/K/N,VERBOSE=V/S,FORCEMEDIA/K,ADVERTISE/K,RENEG=RESTART/S,RESET/S,VERYVERBOSE=VV/S"
const char opt_template[] = OPT_TEMPLATE;
struct progopts {
@@ -70,12 +82,17 @@ struct prgdata {
struct Device *sana2dev;
UBYTE devvalid;
struct progopts opts;
BYTE *auto_devname; /* device name, if auto-detected */
};
void end_prog( struct prgdata *prg )
{
if( prg->auto_devname )
FreeVec( prg->auto_devname );
if( prg->sana2devio )
{
if( prg->devvalid )
@@ -84,6 +101,16 @@ void end_prog( struct prgdata *prg )
}
if( prg->sana2devport )
DeleteMsgPort( prg->sana2devport );
#ifdef __GNUC__
if( (UtilityBase) && (Utility_MY) )
{
CloseLibrary( (struct Library*)UtilityBase );
Utility_MY = 0;
UtilityBase = NULL;
}
#endif /* __GNUC__ */
}
/*
@@ -105,6 +132,13 @@ LONG start_prog( struct prgdata *prg )
if( !prg->sana2devio )
goto err;
#ifdef __GNUC__
if( !UtilityBase )
{
UtilityBase = (struct UtilityBase*)OpenLibrary("utility.library",37);
Utility_MY = 1;
}
#endif /* __GNUC__ */
return 1;
err:
end_prog( prg );
@@ -189,36 +223,37 @@ const struct {
BYTE *name;
UWORD namelen;
UWORD value;
} media[] = {
/* The order through 100baseT4 matches bits in the BMSR */
} mediatypes[] = {
/* these are kept in this order for the dump loop decision about best mode */
{ "10baseT-HD", 10,MII_AN_10BASET_HD },
{ "10baseT-FD", 10,MII_AN_10BASET_FD },
{ "100baseTx-HD", 12,MII_AN_100BASETX_HD },
{ "100baseTx-FD", 12,MII_AN_100BASETX_FD },
{ "100baseT4", 9,MII_AN_100BASET4 },
/* generic mode names where only the speed matters */
{ "100baseTx", 9,MII_AN_100BASETX_FD | MII_AN_100BASETX_HD },
{ "10baseT", 7,MII_AN_10BASET_FD | MII_AN_10BASET_HD },
{ "100bTx", 6,MII_AN_100BASETX_FD | MII_AN_100BASETX_HD },
{ "10bT", 4,MII_AN_10BASET_FD | MII_AN_10BASET_HD },
};
#define NMEDIA (sizeof(media)/sizeof(media[0]))
#define NMEDIA (sizeof(mediatypes)/sizeof(mediatypes[0]))
void dump_mii_media( USHORT par, BOOL bestonly )
void dump_mii_media( USHORT parms, BOOL bestonly )
{
LONG i;
par >>= 5; /* get upper bits */
for( i=4 ; i >= 0 ; i-- )
for( i=9 ; i >= 5 ; i-- )
{
if( par & (1<<i) )
if( parms & (1<<i) )
{
Printf(" ");
Printf("%s",(ULONG)media[i].name);
Printf(" %s",(ULONG)mediatypes[i-5].name);
if( bestonly )
break;
}
}
if( par & (1<<5) )
if( parms & (1<<10) )
Printf(" flow-control");
}
@@ -234,13 +269,13 @@ LONG parse_speedduplex( BYTE *parameters )
while( *s != 0 )
{
for( i=0 ; i < NMEDIA ; i++ )
if( Strnicmp( media[i].name, s, media[i].namelen ) == 0 )
if( Strnicmp( mediatypes[i].name, s, mediatypes[i].namelen ) == 0 )
break;
if( i==NMEDIA )
goto err;
s += media[i].namelen;
res |= media[i].value;
s += mediatypes[i].namelen;
res |= mediatypes[i].value;
/* skip " " and/or "," */
while( *s != 0 )
@@ -254,26 +289,26 @@ LONG parse_speedduplex( BYTE *parameters )
return res;
err:
Printf("Invalid media specification %s\n",parameters);
Printf("Invalid media specification %s\n",(ULONG)parameters);
Printf("Valid Arguments:\n");
for( i=0 ; i < NMEDIA ; i++ )
Printf("%s\n",media[i].name);
Printf("%s\n",(ULONG)mediatypes[i].name);
return -1;
}
/*
note: this code assumes that "mii" has the register contents in natural
note: this code assumes that "mii" has the register contents in network
byte ordering. Also, the registers themselves shall be consecutive
in memory.
*/
int dump_mii( struct S2DevQueryMIIParam *mii, LONG length, LONG verbose )
{
USHORT bmcr,bmsr,advert,curlink;
USHORT bmcr,bmsr,selfad,curlink;
LONG i;
bmcr = mii[MII_BMCR].Content;
bmsr = mii[MII_BMSR].Content;
advert = mii[MII_ANAR].Content;
selfad = mii[MII_ANAR].Content;
curlink = mii[MII_ANLPAR].Content;
if( bmcr == 0xffff )
@@ -286,12 +321,12 @@ int dump_mii( struct S2DevQueryMIIParam *mii, LONG length, LONG verbose )
{
if( bmsr & MII_BMSR_AN_COMPLETE)
{
if( advert & curlink )
if( selfad & curlink )
{
if( curlink & MII_AN_ACK )
/* if( curlink & MII_AN_ACK ) */
Printf("negotiated ");
else Printf("no autonegotiation,");
dump_mii_media( advert & curlink, 1 );
/* else Printf("no autonegotiation,"); */
dump_mii_media( selfad & curlink, 1 );
Printf(", ");
}
else
@@ -308,8 +343,8 @@ int dump_mii( struct S2DevQueryMIIParam *mii, LONG length, LONG verbose )
else
{
Printf("%s Mbit, %s duplex, ",
(bmcr & MII_BMCR_100MBIT) ? "100" : "10",
(bmcr & MII_BMCR_DUPLEX) ? "full" : "half" );
(bmcr & MII_BMCR_100MBIT) ? (ULONG)"100" : (ULONG)"10",
(bmcr & MII_BMCR_DUPLEX) ? (ULONG)"full" : (ULONG)"half" );
}
if( bmsr & MII_BMSR_LINK_VALID )
Printf("link ok");
@@ -353,8 +388,8 @@ int dump_mii( struct S2DevQueryMIIParam *mii, LONG length, LONG verbose )
Printf("autonegotiation enabled\n");
else
Printf("%s Mbit, %s duplex\n",
(bmcr & MII_BMCR_100MBIT) ? "100" : "10",
(bmcr & MII_BMCR_DUPLEX) ? "full" : "half");
(bmcr & MII_BMCR_100MBIT) ? (ULONG)"100" : (ULONG)"10",
(bmcr & MII_BMCR_DUPLEX) ? (ULONG)"full" : (ULONG)"half");
Printf(" basic status: ");
if( bmsr & MII_BMSR_AN_COMPLETE )
Printf("autonegotiation complete, ");
@@ -366,7 +401,7 @@ int dump_mii( struct S2DevQueryMIIParam *mii, LONG length, LONG verbose )
Printf("\n capabilities:");
dump_mii_media( bmsr >> 6, 0 );
Printf("\n advertising: ");
dump_mii_media( advert, 0 );
dump_mii_media( selfad, 0 );
if( curlink & MII_AN_ABILITY_MASK )
{
Printf("\n link partner:");
@@ -438,6 +473,111 @@ LONG write_mii( struct prgdata *prg, struct S2DevQueryMIIParam *mii, LONG num )
return parm_mii.Actual;
}
#ifdef RSHOW
/* return string length without closing 0 */
LONG myStrLen( BYTE *str )
{
LONG ret = 0;
if( str )
{
while( *str++ )
ret++;
}
return ret;
}
/* copy string, append 0 */
void myStrNCpy( BYTE *dst, BYTE*src, LONG bytes )
{
if( !dst )
return;
if( src )
{
while( (bytes--) && (*src != 0) )
{
*dst++ = *src++;
}
}
*dst = 0;
}
/* find active interface and its device in RoadShow (optional) */
/* "which" index of Ethernet adapter 0,1,2,... */
/* "unit" is the output unit */
BYTE *find_active_interface(LONG which, LONG *unit )
{
struct Library *SocketBase;
BYTE *ret = NULL;
struct List * interface_list = NULL;
struct Node *n;
BYTE *dev = NULL;
LONG hw = -1;
SocketBase = OpenLibrary("bsdsocket.library",4);
if( !SocketBase )
{
Printf("Cannot open bsdsocket.library version 4 for device auto-detection\n");
return NULL;
}
do
{
LONG have_iface = 0;
if( !(SocketBaseTags(SBTM_GETREF(SBTC_HAVE_INTERFACE_API), &have_iface, TAG_DONE) == 0)
||(!have_iface) )
{
Printf("RoadShow-style interface API not available in IP stack\n");
break;
}
interface_list = ObtainInterfaceList();
if( !interface_list )
{
break;
}
for( n=interface_list->lh_Head ; n->ln_Succ != NULL ; n=n->ln_Succ )
{
/* Printf("Interface %s\n",n->ln_Name); */
/* find Ethernet interface */
if(!QueryInterfaceTags( n->ln_Name, IFQ_HardwareType, &hw,
IFQ_DeviceName, &dev,
IFQ_DeviceUnit, unit ) )
continue;
/* Printf("device %s hwtype %ld\n",dev,hw); */
if( hw == S2WireType_Ethernet )
break;
}
if( hw == S2WireType_Ethernet )
{
if( dev )
{
ret = AllocVec( myStrLen( dev ), 0 );
if( ret )
myStrNCpy( ret, dev, myStrLen(dev) );
}
}
}
while(0);
if( interface_list )
ReleaseInterfaceList(interface_list);
CloseLibrary(SocketBase);
return ret;
}
#endif
/* 8 basic registers, we poll 16 out of curiosity */
#define MII_REGNUM 16
/* two spare registers for write mode */
@@ -468,17 +608,34 @@ int main(int argc, char **argv)
return res;
}
unit = (prg->opts.unit) ? *prg->opts.unit : 0;
if( !prg->opts.devname )
{
#ifdef RSHOW
LONG _unit;
prg->auto_devname = find_active_interface( 0, &_unit );
if( prg->auto_devname )
{
unit = _unit;
name = prg->auto_devname;
}
else
{
Printf("cannot auto-determine device, please use DEVICE=... as argument\n");
end_prog(prg);
return res;
}
#else
name = "enc624j6net.device";
Printf("TODO: auto-detect, now trying default %s\n",name);
Printf("device auto-detect not compiled in, now trying default %s\n",name);
#endif
/* end_prog(prg);
return res; */
}
else
name = prg->opts.devname;
unit = (prg->opts.unit) ? *prg->opts.unit : 0;
if( prg->opts.vverbose )
prg->opts.verbose = 2;
else
@@ -524,7 +681,7 @@ int main(int argc, char **argv)
parm_productname.Data = productname;
parm_productname.Length = sizeof(productname);
parm_productname.Actual = 0;
#if 1
tags[i=0].ti_Tag = S2_DevQueryExtVendorName;
tags[i++].ti_Data = (ULONG) &parm_vendorname;
tags[i ].ti_Tag = S2_DevQueryExtProductName;
@@ -542,55 +699,28 @@ int main(int argc, char **argv)
parm_mii.Actual = query_mii( prg, mii, 0, 15 );
if( parm_mii.Actual )
{
/* read BMSR twice */
/* read BMSR a second time */
query_mii( prg, mii+MII_BMSR, MII_BMSR, MII_BMSR );
res = RETURN_OK;
}
else
res = RETURN_WARN;
#else
/* MII specific */
parm_mii.Data = (APTR)mii;
parm_mii.Length = sizeof(mii);
parm_mii.Actual = 0;
for( i=0 ; i < 16 ; i++ ) /* MII standard register set: 8 */
{
mii[i].ID = i; /* mii[i].Content = 0; */
}
mii[16].ID = MII_BMSR; /* read BMSR twice */
tags[i=0].ti_Tag = S2_DevQueryExtVendorName;
tags[i++].ti_Data = (ULONG) &parm_vendorname;
tags[i ].ti_Tag = S2_DevQueryExtProductName;
tags[i++].ti_Data = (ULONG) &parm_productname;
tags[i ].ti_Tag = S2_DevQueryExtGetMII;
tags[i++].ti_Data = (ULONG) &parm_mii;
tags[i ].ti_Tag = TAG_DONE;
prg->sana2devio->ios2_Req.io_Command = S2_DEVICEQUERYEXT;
prg->sana2devio->ios2_Data = tags;
prg->sana2devio->ios2_DataLength = sizeof tags;
if( DoIO((struct IORequest *) prg->sana2devio ) != 0 )
Printf("Sana2DeviceQueryExtension for MII access not present\n");
res = RETURN_WARN;
else res = RETURN_OK;
mii[MII_BMSR].Content = mii[16].Content; /* read BMSR twice */
#endif
}
}
Printf("Device: %s\n",name);
Printf("Device: %s\n",(ULONG)name);
/* general info */
if( parm_vendorname.Actual != 0 )
{
vendorname[parm_vendorname.Actual-1] = 0;
Printf("Vendor: %s\n",vendorname);
Printf("Vendor: %s\n",(ULONG)vendorname);
}
if( parm_productname.Actual != 0 )
{
productname[parm_productname.Actual-1] = 0;
Printf("Product: %s\n",productname);
Printf("Product: %s\n",(ULONG)productname);
}
/* after query, see what we've got */
@@ -603,6 +733,7 @@ int main(int argc, char **argv)
}
else
{
/* command or query ? */
if( !(prg->opts.renegotiate) && !(prg->opts.reset)
&& !(prg->opts.advertise) && !(prg->opts.force)
)
@@ -659,3 +790,4 @@ int main(int argc, char **argv)
end_prog(prg);
return res;
}
+45
View File
@@ -66,6 +66,51 @@ struct S2DevQueryExtParam
/* Current physical link speed, see definitions below: */
#define S2_DevQueryExtLinkSpeed (S2_DevQueryExtTagBase + 4)
/* proposal added by Henryk Richter: access to MII */
/* MII is the standardized ethernet interface to the
PHY registers. It allows to read and modify autonegotiation
settings and status, as well as manual reconfiguration of
link parameters. In order to ease the burden on the
SANA-II driver, this interface is transparent in the sense
that no processing of MII registers is necessary.
Please note that MII read/write is slow. Use with discretion.
The format of the Data APTR is per entry as follows:
UWORD ID
UWORD Content
S2_DevQueryExtGetMII
Please pass a writable Data array of Length=2*NumIDs to the call and
initialize the IDs you are interested in. The driver will initialize
the Content of the IDs it knows about. Should a requested ID be
unsupported by the driver or underlying chipset, the driver will
overwrite the respective IDs with S2_DEVQUERYEXT_MII_INVALID and
clear the associated Content field.
In case of fatal error, the "Actual" field of S2DevQueryExtParam
will be 0. Otherwise, the last successfully updated location + 2
will be returned.
S2_DevQueryExtSetMII
Please pass a Data array of Length=2*NumIDs to the call and initialize
the IDs to write along with their content. The driver will write the
MII registers corresponding with the IDs in the given order.
In case of fatal error, the "Actual" field of S2DevQueryExtParam
will be 0. Otherwise, the last successfully updated location + 2
will be returned.
*/
#define S2_DevQueryExtGetMII (S2_DevQueryExtTagBase + 0x20)
#define S2_DevQueryExtSetMII (S2_DevQueryExtTagBase + 0x21)
struct S2DevQueryMIIParam
{
UWORD ID;
UWORD Content;
};
#define S2_DEVQUERYEXT_MII_INVALID 0xfe
#define S2_DEVQUERYEXT_LINK_UNDEFINED 0xffffffff
#define S2_DEVQUERYEXT_LINK_DOWN 0
#define S2_DEVQUERYEXT_LINK_UP 1
+2 -1
View File
@@ -37,7 +37,7 @@ static LONG server_queryext( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq );
/* tunables: number of one-call read and write requests */
/* this limits the number of processed write requests per run when enabled */
#define ONE_WRITE_REQ 2
#define ONE_WRITE_REQ 1
/* this limits the number of processed read requests per run when enabled */
#define ONE_READ_REQ 2
@@ -1071,6 +1071,7 @@ VOID SAVEDS ServerTask(void)
{
if( !action ) /* queues quiet ? -> sleep */
{
Disable();
i=0;BOARDLOOP( ( ; i < db->db_NBoards ; i++ ) )
{ /* housekeeping -> check for link change on idle, re-enable interrupts etc. */
hw_check_link_change(db,i);
+1 -1
View File
@@ -127,7 +127,7 @@ CFLAGS = $(CFLAGS) INCLUDEDIR="" INCLUDEDIR=$(SUBDIR) $(DEFINES)
# ASM based alternative to deviceheader.o would be romtag.o
OBJECTS = deviceheader.o$(TYPE) deviceinit.o$(TYPE) device.o$(TYPE) \
server.o$(TYPE) $(SUBDIR)/hw.o$(TYPE)
server.o$(TYPE) $(SUBDIR)/hw.o$(TYPE) kprintf.o$(TYPE)
OBJECTS = $(OBJECTS) $(ASMOBJECTS)
+2 -2
View File
@@ -9,9 +9,9 @@
#define _INC_VERSION_H
#define DEVICEVERSION 2
#define DEVICEREVISION 1
#define DEVICEREVISION 2
#define DEVICEEXTRA
/* #define DEVICEEXTRA Beta */
#define DEVICEDATE 21.02.2019
#define DEVICEDATE 10.03.2019
#endif