├── module_ethercat
├── module_build_info
└── src
│ ├── ethercat.xc
│ ├── pduhandler.h
│ ├── ethercat.h
│ ├── frame.h
│ ├── frameAssembly.S
│ ├── frame.xc
│ └── pduhandler.xc
├── .gitignore
├── doc
├── summary.rst
├── photo-4-slices.jpg
├── index.rst
├── api.rst
├── Makefile
├── usage.rst
├── design-notes.rst
└── threads.svg
├── testbench
├── Makefile
└── src
│ └── stimulus.c
├── app_ethercat_slice
├── src
│ ├── waitFor.S
│ └── main.xc
└── Makefile
├── app_ethercat_singlecore
├── src
│ ├── waitFor.S
│ └── main.xc
└── Makefile
├── app_ethercat_test
├── Makefile
└── src
│ ├── waitFor.S
│ └── main.xc
├── app_master_harness
├── Makefile
└── src
│ └── ping.xc
├── visualiseTrace.sh
├── README.rst
├── LICENSE.txt
├── Makefile
├── .project
└── .cproject
/module_ethercat/module_build_info:
--------------------------------------------------------------------------------
1 | MODULE_XCC_FLAGS = $(XCC_FLAGS) -O3 -g
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | */.build*/*
2 | */bin/*
3 | *.o
4 | *.xe
5 | *.vcd
6 | *.xi
7 | *.i
8 | *.a
9 |
--------------------------------------------------------------------------------
/doc/summary.rst:
--------------------------------------------------------------------------------
1 | Ethercat
2 | ========
3 |
4 | module_ethercat
5 | ---------------
6 |
7 |
--------------------------------------------------------------------------------
/doc/photo-4-slices.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xcore/sc_ethercat/HEAD/doc/photo-4-slices.jpg
--------------------------------------------------------------------------------
/doc/index.rst:
--------------------------------------------------------------------------------
1 | Ethercat
2 | --------
3 |
4 | .. toctree::
5 |
6 | summary
7 | design-notes
8 | usage
9 | api
10 |
--------------------------------------------------------------------------------
/testbench/Makefile:
--------------------------------------------------------------------------------
1 | test: bin/tester
2 | bin/tester "$(TFLAG) ../app_ethercat_test/bin/XK-1/app_ethercat_test.xe"
3 |
4 | bin/tester: src/stimulus.c
5 | if [ ! -d bin ]; then mkdir bin; fi
6 | cc -o bin/tester -std=c99 -m32 -I $(XMOS_TOOL_PATH)/include src/stimulus.c $(XMOS_TOOL_PATH)/lib/libxsidevice.so
7 |
--------------------------------------------------------------------------------
/app_ethercat_slice/src/waitFor.S:
--------------------------------------------------------------------------------
1 | .section .dp.bss,"awd",@nobits
2 |
3 | .align 4
4 | .globl destinationsCore1
5 | .globl destinationsCore1_
6 | .globl destinationsCore0
7 | .globl destinationsCore0_
8 | destinationsCore0:
9 | destinationsCore0_:
10 | .word 0,0,0
11 | destinationsCore1:
12 | destinationsCore1_:
13 | .word 0,0,0
14 |
--------------------------------------------------------------------------------
/app_ethercat_singlecore/src/waitFor.S:
--------------------------------------------------------------------------------
1 | .section .dp.bss,"awd",@nobits
2 |
3 | .align 4
4 | .globl destinationsCore1
5 | .globl destinationsCore1_
6 | .globl destinationsCore0
7 | .globl destinationsCore0_
8 | destinationsCore0:
9 | destinationsCore0_:
10 | .word 0,0,0
11 | destinationsCore1:
12 | destinationsCore1_:
13 | .word 0,0,0
14 |
--------------------------------------------------------------------------------
/doc/api.rst:
--------------------------------------------------------------------------------
1 | API
2 | ===
3 |
4 | Internal
5 | --------
6 |
7 | This section contains internal documentation - that is the bits that make
8 | up the ethercat controller.
9 |
10 | .. doxygenstruct:: mii_ethercat_ports
11 |
12 | .. doxygenfunction:: ethercat_port_init
13 | .. doxygenfunction:: rxProcessS
14 | .. doxygenfunction:: txProcess
15 |
16 | .. doxygenfunction:: frameProcess
17 |
--------------------------------------------------------------------------------
/app_ethercat_test/Makefile:
--------------------------------------------------------------------------------
1 | TARGET = XC-3
2 | APP_NAME =
3 | XCC_FLAGS = -O2 -g
4 | USED_MODULES = module_ethercat module_ethernet_smi
5 |
6 | #=============================================================================
7 | # The following part of the Makefile includes the common build infrastructure
8 | # for compiling XMOS applications. You should not need to edit below here.
9 |
10 | XMOS_MAKE_PATH ?= ../..
11 | include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
12 |
--------------------------------------------------------------------------------
/app_master_harness/Makefile:
--------------------------------------------------------------------------------
1 | TARGET = XC-2
2 | APP_NAME =
3 | XCC_FLAGS = -g -O2 -fsubword-select
4 | USED_MODULES = module_mii_singlethread module_ethernet_smi
5 |
6 | #=============================================================================
7 | # The following part of the Makefile includes the common build infrastructure
8 | # for compiling XMOS applications. You should not need to edit below here.
9 |
10 | XMOS_MAKE_PATH ?= ../..
11 | include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
12 |
--------------------------------------------------------------------------------
/app_ethercat_slice/Makefile:
--------------------------------------------------------------------------------
1 | TARGET = xp-skc-l2-single
2 | APP_NAME =
3 | XCC_FLAGS = -O2 -g -DSMI_MDC_BIT=1 -DSMI_MDIO_BIT=0
4 | USED_MODULES = module_ethercat module_ethernet_smi module_slicekit_xn
5 |
6 | #=============================================================================
7 | # The following part of the Makefile includes the common build infrastructure
8 | # for compiling XMOS applications. You should not need to edit below here.
9 |
10 | XMOS_MAKE_PATH ?= ../..
11 | include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
12 |
--------------------------------------------------------------------------------
/app_ethercat_singlecore/Makefile:
--------------------------------------------------------------------------------
1 | TARGET = xp-skc-l2-single
2 | APP_NAME =
3 | XCC_FLAGS = -O2 -g -DSMI_MDC_BIT=1 -DSMI_MDIO_BIT=0
4 | USED_MODULES = module_ethercat module_ethernet_smi module_slicekit_xn
5 |
6 | #=============================================================================
7 | # The following part of the Makefile includes the common build infrastructure
8 | # for compiling XMOS applications. You should not need to edit below here.
9 |
10 | XMOS_MAKE_PATH ?= ../..
11 | include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
12 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | SPHINX_PROJECT_NAME=Ethercat
2 | VERSION=0v1
3 | DOXYGEN_DIRS=../../sc_ethercat/module_ethercat
4 | SOURCE_INCLUDE_DIRS=../../sc_ethercat
5 | XDOC_DIR ?= ../../xdoc
6 | include $(XDOC_DIR)/Makefile.inc
7 |
8 | all: html pdf
9 | @if [ ! -d ../../sc_ethercat_gh_pages ] ; then echo '**** no gh_pages checked out ****'; exit 0; else cp -r _build/html/* ../../sc_ethercat_gh_pages/; cp -r _build/html/.doctrees ../../sc_ethercat_gh_pages/; echo 'HTML files copied to sc_ethercat_gh_pages'; echo 'Now go to sc_ethercat_gh_pages, commit, and push to publish the documentation'; fi
10 |
--------------------------------------------------------------------------------
/module_ethercat/src/ethercat.xc:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 | #include
7 | #include "ethercat.h"
8 |
9 | void ethercat_port_init(mii_ethercat_ports &m) {
10 | configure_clock_src(m.clk_mii_rx, m.p_mii_rxclk);
11 | configure_clock_src(m.clk_mii_tx, m.p_mii_txclk);
12 |
13 | set_clock_fall_delay(m.clk_mii_tx, 7); // NEEDED?
14 |
15 | configure_in_port_strobed_slave(m.p_mii_rxd, m.p_mii_rxdv, m.clk_mii_rx);
16 | configure_out_port_strobed_master(m.p_mii_txd, m.p_mii_txen, m.clk_mii_tx, 0);
17 |
18 | start_clock(m.clk_mii_rx);
19 | start_clock(m.clk_mii_tx);
20 | }
21 |
--------------------------------------------------------------------------------
/doc/usage.rst:
--------------------------------------------------------------------------------
1 | Usage
2 | -----
3 |
4 | The app_ethercat_test application should be run on any number of XC-3 nodes
5 | (to be replaced with Ethernet-slice when available) conencted to each
6 | other.
7 |
8 | * The left conncetor on the XC-3 is the main connector, the right
9 | connector can be used for chaining.
10 |
11 | * The Ethernet connected to slice 0-0 is the main connector, the other four
12 | can be used for building a chain (or a tree!)
13 |
14 | * An ethercat master needs to be inserted in the chain, connected to the
15 | first Ethercat slave. The master is in app_master_harness and is designed
16 | to run on an XC-2 (to be replaced by an slice too). The master sends an
17 | Ethercat packet every second, and prints it out no return, including the
18 | round-trip-time in 10 ns ticks.
19 |
--------------------------------------------------------------------------------
/module_ethercat/src/pduhandler.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 | /** Function that processes all frames. Frames are streamed in over fromRx
7 | * and streamed out over toTx. The data streams are opened with control
8 | * token 3 and terminated with two control tokens. One control token to
9 | * signal the CRC status (15: CRC error, 0: CRC good), and an END token.
10 | *
11 | * \param fromRx stream into the process, comes from rxProcessS()
12 | *
13 | * \param toTx stream into the process, goes to txProcess()
14 | *
15 | * \param destination channel end where to send to.
16 | *
17 | * \param memory array of words that contains the Ethercat memory.
18 | */
19 | void frameProcess(streaming chanend fromRx, streaming chanend toTx,
20 | int &destination, short memory[]);
21 |
--------------------------------------------------------------------------------
/app_ethercat_test/src/waitFor.S:
--------------------------------------------------------------------------------
1 | .globl waitFor
2 | .globl waitFor.nstackwords
3 | .linkset waitFor.nstackwords, 0
4 | .globl waitFor.chanends
5 | .linkset waitFor.chanends, 0
6 | .globl waitFor.timers
7 | .linkset waitFor.timers, 0
8 |
9 | .text
10 | .align 4
11 | waitFor:
12 | ldw r11, r0[0]
13 | bf r11, waitFor
14 | retsp 0
15 |
16 | .globl assignDestination
17 | .globl assignDestination.nstackwords
18 | .linkset assignDestination.nstackwords, 0
19 | .globl assignDestination.chanends
20 | .linkset assignDestination.chanends, 0
21 | .globl assignDestination.timers
22 | .linkset assignDestination.timers, 0
23 |
24 | .text
25 | .align 4
26 | assignDestination:
27 | stw r1, r0[0]
28 | retsp 0
29 |
30 |
31 | .section .dp.bss,"awd",@nobits
32 | .globl destinationIdentifiers
33 | .globl destinationIdentifiers_
34 | .globl destinations
35 | .globl destinations_
36 | destinationIdentifiers:
37 | destinationIdentifiers_:
38 | .word 0,0,0,0,0
39 | destinations:
40 | destinations_:
41 | .word 0,0,0,0,0
42 |
--------------------------------------------------------------------------------
/visualiseTrace.sh:
--------------------------------------------------------------------------------
1 | make TFLAG=-t test | awk -F@ '
2 | {
3 | if ($3 > 46900) print $0
4 | }
5 | ' > OUTN
6 |
7 | for i in 0 1 2
8 | do
9 | fgrep "]@$i" < OUTN | sed -e 's/^.*stdcore.0.//' | grep -v -e '-P-.* out' | grep -v -e '-P-.* in' | fgrep -v 'Event caus' | sed 's/[^:]*: //' | awk -F@ '
10 | BEGIN {
11 | last = 46959;
12 | this = '$i';
13 | if (this == 1) OUTCNT = -5
14 | if (this == 0) nextt = 2;
15 | if (this == 1) nextt = 3;
16 | if (this == 2) nextt = 1;
17 | }
18 | /^in/{
19 | last++;
20 | while($2 > last) printf("@%d\n", last++);
21 | print "Q" this "." (++INCNT) " " $0
22 | next;
23 | }
24 | /^out/{
25 | last++;
26 | while($2 > last) printf("@%d\n", last++);
27 | print "Q" nextt "." (++OUTCNT) " " $0
28 | next;
29 | }
30 | {
31 | last++;
32 | while($2 > last) printf("@%d\n", last++);
33 | print $0
34 | next;
35 | }
36 | END {
37 | while(last < 50100) printf("@%d\n", last++);
38 | }
39 | ' > OUT$i
40 | done
41 | join -t@ -1 2 -2 2 OUT0 OUT2 | join -t@ -1 1 -2 2 - OUT1 | tr '@' ' ' | expand -6,56,106,156
42 | rm OUT0 OUT1 OUT2 OUTN
43 |
--------------------------------------------------------------------------------
/module_ethercat/src/ethercat.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 | /** Structure containing all the ports of an MII PHY.
7 | */
8 | typedef struct mii_ethercat_ports {
9 | clock clk_mii_rx; /**< RX Clock Block **/
10 | clock clk_mii_tx; /**< TX Clock Block **/
11 |
12 | port p_mii_rxclk; /**< MII RX clock wire */
13 | in buffered port:8 p_mii_rxd; /**< MII RX data wire */
14 | in port p_mii_rxdv; /**< MII RX data valid wire */
15 |
16 | port p_mii_txclk; /**< MII TX clock wire */
17 | out buffered port:8 p_mii_txd; /**< MII TX data wire */
18 | out port p_mii_txen; /**< MII TX enable wire */
19 | } mii_ethercat_ports;
20 |
21 | /** Function that initialises the ports and clockblocks that control the
22 | * PHY. This needs to be called once for each PHY.
23 | *
24 | * \param m port structure.
25 | */
26 | void ethercat_port_init(mii_ethercat_ports &m);
27 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | Ethercat
2 | ........
3 |
4 | :Stable release: unreleased
5 |
6 | :Status: idea
7 |
8 | :Maintainer: https://github.com/henkmuller
9 |
10 | :Description: Feasibility study for EtherCAT
11 |
12 |
13 | Key Features
14 | ============
15 |
16 | * Ethercat test-harness to run on XC-2
17 |
18 | * Ethercat slave to run on XC-3
19 |
20 | * Low latency MII Rx and Tx
21 |
22 | * Rudimentary EtherCAT protocol handler
23 |
24 | * Current latency of 800ns, but memory access has not been implemented yet
25 | (PHY latency adds 400 ns). Return path latency approximately 640 ns
26 | (preamble) + 400 ns (PHY) + 160 ns (processing)
27 |
28 | To Do
29 | =====
30 |
31 | * Mailbox protocol
32 | * Network variable protocol
33 | * Memory interface.
34 |
35 | Firmware Overview
36 | =================
37 |
38 | The module and applicatons in this repo are a feasibility study on coding
39 | an EtherCAT slave on an XS1 device. The target is either an L2 or a G4,
40 | depending on whether fast threads are required (> 100 MIPS requires an L2)
41 | and on whether a fast switch is required (the G4 switch is very low
42 | latency).
43 |
44 | Known Issues
45 | ============
46 |
47 | * app_ethercat_test won't build (and is deprecated)
48 |
49 | Required Repositories
50 | =====================
51 |
52 | * hw_slicekit_system git\@github.com:xcore/hw_slicekit_system.git (XN file)
53 | * sc_ethernet git\@github.com:xcore/sc_ethernet.git (SMI module)
54 | * xcommon git\@github.com:xcore/xcommon.git (build system)
55 | * xdoc git\@github.com:xcore/xdoc.git (documentation)
56 |
57 | Support
58 | =======
59 |
60 |
61 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Software License Agreement
2 |
3 | Copyright (c) 2011, XMOS Ltd, All rights reserved.
4 |
5 | The copyright holders hereby grant to any person obtaining a copy of this software (the "Software") and/or its associated
6 | documentation files (the Documentation), the perpetual, irrevocable (except in the case of breach of this license) no-cost,
7 | royalty free, sublicensable rights to use, copy, modify, merge, publish, display, publicly perform, distribute, and/or
8 | sell copies of the Software and the Documentation, together or separately, and to permit persons to whom the Software and/or
9 | Documentation is furnished to do so, subject to the following conditions:
10 |
11 | . Redistributions of the Software in source code must retain the above copyright notice, this list of conditions and the
12 | following disclaimers.
13 |
14 | . Redistributions of the Software in binary form must reproduce the above copyright notice, this list of conditions and
15 | the following disclaimers in the documentation and/or other materials provided with the distribution.
16 |
17 | . Redistributions of the Documentation must retain the above copyright notice, this list of conditions and the following
18 | disclaimers.
19 |
20 | Neither the name of XMOS, nor the names of its contributors may be used to endorse or promote products derived from this
21 | Software or the Documentation without specific prior written permission of the copyright holder.
22 |
23 | THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR DOCUMENTATION OR THE USE OF OR OTHER
27 | DEALINGS WITH THE SOFTWARE OR DOCUMENTATION.
28 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # This Makefile acts as a composite builder for all the elements
2 | # of this repository.
3 |
4 | # It has target patterns for all, clean and test for sub-directories of the
5 | # form dir.target e.g. calling:
6 | #
7 | # xmake app_uart_demo.all
8 | #
9 | # will execute 'xmake all' in the app_uart_demo sub-directory.
10 | #
11 | # In addition the following targets are defined:
12 | #
13 | # all:
14 | #
15 | # This target will build all the applications listed in the BUILD_SUBDIRS
16 | # variable.
17 | #
18 | # plugins:
19 | #
20 | # This target will build all the plugins listed in the PLUGIN_SUBDIRS
21 | # variable
22 | #
23 | # clean:
24 | #
25 | # This target will clean all the applications listed in the BUILD_SUBDIRS
26 | # variable.
27 | #
28 | # clean_plugins:
29 | #
30 | # This target will clean all the plugins listed in the PLUGIN_SUBDIRS
31 | # variable.
32 | #
33 | # test:
34 | #
35 | # This target will make the test make target in all the directories
36 | # listed in TEST_SUBDIRS.
37 | #
38 |
39 |
40 | # This variable should contain a space separated list of all
41 | # the directories containing buildable applications (usually
42 | # prefixed with the app_ prefix)
43 | BUILD_SUBDIRS = app_ethercat_test
44 |
45 | # This variable should contain a space separated list of all
46 | # the directories containing buildable plugins (usually
47 | # prefixed with the plugin_ prefix)
48 | PLUGIN_SUBDIRS =
49 |
50 | # This variable should contain a space separated list of all
51 | # the directories containing applications with a 'test' make target
52 | TEST_SUBDIRS = testbench
53 |
54 | # Provided that the above variables are set you shouldn't need to modify
55 | # the targets below here.
56 |
57 | %.all:
58 | cd $* && xmake all
59 |
60 | %.clean:
61 | cd $* && xmake clean
62 |
63 | %.test:
64 | cd $* && xmake test
65 |
66 | all: $(foreach x, $(BUILD_SUBDIRS), $x.all)
67 | plugins: $(foreach x, $(PLUGIN_SUBDIRS), $x.all)
68 | clean: $(foreach x, $(BUILD_SUBDIRS), $x.clean)
69 | clean_plugins: $(foreach x, $(PLUGIN_SUBDIRS), $x.clean)
70 | test: $(foreach x, $(TEST_SUBDIRS), $x.test)
71 |
--------------------------------------------------------------------------------
/module_ethercat/src/frame.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 |
7 | /** Function that transmits data on an mii port. This function reads bytes
8 | * from an input channel, and outputs them one byte at a time. Data should
9 | * arrive fast enough to prevent a gap in the packet.
10 | *
11 | * The first token is a control token: a zero control token indicates that
12 | * the transmitter should append a CRC; a non-zero control token indicates
13 | * that a valid CRC is included at the end of the message. After the
14 | * initial control token, a stream of data bytes are expected on the
15 | * channel, terminated by a control token. The terminating token is either
16 | * 0 or 0xF depending on whether the CRC on the incoming packet was valid
17 | * or not. If the TX function was asked to add a valid CRC, *and* the
18 | * incoming CRC was deemed invalid, then it will knacker the outgoing CRC
19 | * too. Just to be consistent. Finally a '1' control token is read closing
20 | * the stream.
21 | *
22 | * \param txData port on which data is transmitted,
23 | * must be byte buffered.
24 | *
25 | * \param fromProtocol channel on which data arrives
26 | */
27 | void txProcess(buffered out port:8 txData,
28 | streaming chanend fromProtocol);
29 |
30 |
31 |
32 | /** Function that receives data on the master port. Only frames arriving on
33 | * this port are interpreted. This function reads byte from the input port
34 | * (guarded by the datavalid port), and outputs them on the channel. The
35 | * data stream is opened with control token 3 (indicating that a valid CRC
36 | * will eb transmitted at the end of the stream) and terminated with two
37 | * control tokens. One control token to signal the CRC status (15: CRC
38 | * error, 0: CRC good), and an END token.
39 | *
40 | * \param dataValid port that signals whether rxData contains
41 | * valid data.
42 | *
43 | * \param rxData port on which data arrives, must be byte buffered
44 | *
45 | * \param toProtocol channel end on which packet is transmitted
46 | *
47 | * \param destinationChannel channelend to use as destination - can be
48 | * modified on the fly
49 | */
50 | void rxProcessS(in port dataValid,
51 | buffered in port:8 rxData,
52 | streaming chanend toProtocol,
53 | int &destinationChannel);
54 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | sc_ethercat
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
10 | clean,full,incremental,
11 |
12 |
13 | ?name?
14 |
15 |
16 |
17 | org.eclipse.cdt.make.core.append_environment
18 | true
19 |
20 |
21 | org.eclipse.cdt.make.core.autoBuildTarget
22 | all
23 |
24 |
25 | org.eclipse.cdt.make.core.buildArguments
26 | -f Makefile
27 |
28 |
29 | org.eclipse.cdt.make.core.buildCommand
30 | xmake
31 |
32 |
33 | org.eclipse.cdt.make.core.buildLocation
34 | ${workspace_loc:/sc_ethercat}
35 |
36 |
37 | org.eclipse.cdt.make.core.cleanBuildTarget
38 | clean
39 |
40 |
41 | org.eclipse.cdt.make.core.contents
42 | org.eclipse.cdt.make.core.activeConfigSettings
43 |
44 |
45 | org.eclipse.cdt.make.core.enableAutoBuild
46 | false
47 |
48 |
49 | org.eclipse.cdt.make.core.enableCleanBuild
50 | true
51 |
52 |
53 | org.eclipse.cdt.make.core.enableFullBuild
54 | true
55 |
56 |
57 | org.eclipse.cdt.make.core.fullBuildTarget
58 | all
59 |
60 |
61 | org.eclipse.cdt.make.core.stopOnError
62 | true
63 |
64 |
65 | org.eclipse.cdt.make.core.useDefaultBuildCmd
66 | false
67 |
68 |
69 |
70 |
71 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
72 |
73 |
74 |
75 |
76 |
77 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
78 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
79 | org.eclipse.cdt.core.cnature
80 |
81 |
82 |
--------------------------------------------------------------------------------
/module_ethercat/src/frameAssembly.S:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | .globl rxProcessS
4 | .globl rxProcessS.nstackwords
5 | .linkset rxProcessS.nstackwords, 0
6 | .globl rxProcessS.chanends
7 | .linkset rxProcessS.chanends, 0
8 | .globl rxProcessS.timers
9 | .linkset rxProcessS.timers, 0
10 |
11 | // r0: dataValid
12 | // r1: rxData
13 | // r2: toProtocol
14 | // r3: &destinationChanend
15 | // r4: poly
16 | // r5: CRC
17 | // r6: 0xFFFFFFFF (correct CRC)
18 | // r7: Table with two control tokens
19 | // r11: temp
20 |
21 | .section .cp.const4 ,"acM", @progbits, 4
22 | .align 4
23 | polynomial:
24 | .word 0xEDB88320
25 | initialCRC:
26 | .word 0x9226F562
27 | controlTokenTable:
28 | .byte 0x0F, 0, 0, 0
29 |
30 | .text
31 | .align 4
32 | rxProcessS:
33 | getd r11, res[r2] // Initialise default destination
34 | stw r11, r3[0] // To current destination
35 |
36 | ldw r4, cp[polynomial] // r4 is constant - loaded once.
37 |
38 | ldap r11, dataValidVector // Set up dataValid resource
39 | setv res[r0], r11 // Point vector to entry point
40 | ldc r11, 0 // Set condition data to 0
41 | setd res[r0], r11 // Set condition itself to
42 | setc res[r0], XS1_SETC_COND_EQ // EQ: when pinseq(0)
43 |
44 | ldap r11, rxdVector // Set up data port resource
45 | setv res[r1], r11 // Point vector to entry point
46 | ldc r11, 0xD // Set condition data to 0xD
47 | setd res[r1], r11 // Set condition delayed to inside loop
48 |
49 | ldaw r11, cp[controlTokenTable] // Set r7 to point to array with two control
50 | or r7, r11, r11
51 | mkmsk r6, 32 // tokens, and set r6 to contain correct CRC.
52 |
53 | loop:
54 | clre
55 | ldw r5, cp[initialCRC] // Initialise the CRC to magic pattern
56 | setc res[r1], XS1_SETC_COND_EQ // Set condition to test on pinseq(0xD)
57 | in r11, res[r1] // Wait for the 0xD to arrive.
58 | ldw r11, r3[0] // Load the direction for this packet
59 | setd res[r2], r11 // Set packet to go there.
60 | outct res[r2], 3 // Send packet start
61 | eeu res[r0] // Enable events on both resources
62 | eeu res[r1] // And wait for byte on first one.
63 |
64 | rxdVector:
65 | in r11, res[r1] // Read byte from port
66 | outt res[r2], r11 // Send it to destination (protocol or port)
67 | crc8 r5, r11, r11, r4 // Incorporate into CRC
68 | waiteu // Wait for next byte or datavalid.
69 |
70 | dataValidVector:
71 | in r11, res[r0] // Data valid has disappeared, read it.
72 | eq r5, r5, r6 // Test if CRC is 0xFFFFFFFF, use result
73 | ld8u r5, r7[r5] // to read appropriate control-token
74 | outct res[r2], r5 // And send control token out.
75 | outct res[r2], 1 // And terminate stream.
76 | bu loop
77 |
--------------------------------------------------------------------------------
/module_ethercat/src/frame.xc:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | extern int rx0, rx1;
12 |
13 | void rx0Process(in port rxActive, buffered in port:8 rxPort, streaming chanend toProtocol) {
14 | const register unsigned poly = 0xEDB88320;
15 | int cnt = 0;
16 | while (1) {
17 | int clockCounter, running = 1, bits;
18 | unsigned crc = 0x9226F562;
19 | rxPort when pinseq(0xD) :> void;
20 | soutct(toProtocol, 3);
21 | while(running) {
22 | char inputWord;
23 | select {
24 | case rxPort :> inputWord:
25 | toProtocol <: inputWord;
26 | crc8shr(crc, inputWord, poly);
27 | break;
28 | case rxActive when pinseq(0) :> void:
29 | soutct(toProtocol, ~crc ? 0xF : 0);
30 | running = 0;
31 | break;
32 | }
33 | }
34 | soutct(toProtocol, 1);
35 | asm("add %0, %1, 1" : "=r"(cnt) : "r" (cnt));
36 | }
37 | }
38 |
39 | void rxNProcess(in port rxActive, buffered in port:8 rxPort, streaming chanend toProtocol) {
40 | const register unsigned poly = 0xEDB88320;
41 | int cnt = 0;
42 | while (1) {
43 | int clockCounter, running = 1, bits, txChannelEnd;
44 | unsigned crc = 0x9226F562;
45 | rxPort when pinseq(0xD) :> void;
46 | // asm("ldw %0, dp[rx1]" : "=r" (txChannelEnd));
47 | // asm("setd res[%0],%1" :: "r" (toProtocol), "r" (txChannelEnd));
48 | soutct(toProtocol, 3);
49 | while(running) {
50 | char inputWord;
51 | select {
52 | case rxPort :> inputWord:
53 | toProtocol <: inputWord;
54 | crc8shr(crc, inputWord, poly);
55 | break;
56 | case rxActive when pinseq(0) :> void:
57 | soutct(toProtocol, ~crc ? 0xF : 0);
58 | running = 0;
59 | break;
60 | }
61 | }
62 | soutct(toProtocol, 1);
63 | asm("add %0, %1, 1" : "=r"(cnt) : "r" (cnt));
64 | }
65 | }
66 |
67 | void txProcess(buffered out port:8 txPort, streaming chanend fromProtocol) {
68 | register const unsigned poly = 0xEDB88320;
69 | int cnt = 0;
70 | while(1) {
71 | int clockCounter;
72 | unsigned int bytesLeft, outputWord;
73 | unsigned char outputChar;
74 | unsigned crc = 0x9226F562, incomingCrc;
75 | int keepExistingCRC;
76 | keepExistingCRC = sinct(fromProtocol);
77 | txPort <: 0x55;
78 | #pragma loop unroll
79 | for(int i = 0; i < 6; i++) {
80 | txPort <: 0x55;
81 | }
82 | fromProtocol :> outputChar;
83 | crc8shr(crc, outputChar, poly);
84 | txPort <: 0xD5;
85 | while(!stestct(fromProtocol)) {
86 | txPort <: outputChar;
87 | fromProtocol :> outputChar;
88 | crc8shr(crc, outputChar, poly);
89 | }
90 | txPort <: outputChar;
91 | if (keepExistingCRC) {
92 | sinct(fromProtocol);
93 | } else {
94 | crc32(crc, keepExistingCRC, poly);
95 | crc = ~crc;
96 | txPort <: >> crc;
97 | txPort <: >> crc;
98 | incomingCrc = sinct(fromProtocol);
99 | txPort <: >> crc;
100 | crc ^= incomingCrc<<6;
101 | txPort <: >> crc;
102 | }
103 | schkct(fromProtocol, 1);
104 | asm("add %0, %1, 1" : "=r"(cnt) : "r" (cnt));
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/testbench/src/stimulus.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 | #include "xsidevice.h"
7 | #include
8 | #include
9 |
10 | void *xsim = 0;
11 |
12 | unsigned char packet[] = {
13 | 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xB5,
14 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
15 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
16 | 0x88, 0xA4, // Ethercat frame type
17 |
18 | 0x38, 0x10, // 11 bits length, 4 bit protocol (0x1)
19 |
20 | 0x01, // PDU frame
21 |
22 | 0x01, // Command: Auto Increment Physical Read (first PDU, length 28)
23 | 0x5A, // IDX: master index
24 | 0x00, 0x00, // ADP: auto increment address
25 | 0x01, 0x01, // ADO: physical memory address
26 | 0x10, 0x80, // Length: 16 bytes, not circulated, another PDU to follow
27 | 0x00, 0x00, // IRQ
28 | 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // DATA
29 | 0x00, 0x00, // WKC: working counter.
30 |
31 | 0x02, // Command: Auto Increment Physical Write (second PDU, length 28)
32 | 0x57, // IDX: master index
33 | 0xFF, 0x01, // ADP: auto increment address
34 | 0x30, 0x40, // ADO: physical memory address
35 | 0x10, 0x00, // Length: 16 bytes, not circulated, last PDU
36 | 0x00, 0x00, // IRQ
37 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // DATA
38 | 0x00, 0x00, // WKC: working counter.
39 |
40 | 0x00, 0x01, 0x02, 0x03, // Ethernet CRC
41 | };
42 |
43 | int main(int argc, char **argv) {
44 | int time = 0, clock = 0, cnt = 0, even = 0, oldready = 0, startTime = 0;
45 | XsiStatus status = xsi_create(&xsim, argv[1]);
46 | assert(status == XSI_STATUS_OK);
47 | while (status != XSI_STATUS_DONE && time < 1000000) {
48 | time++;
49 | if(time % 20 == 3) {
50 | clock = !clock;
51 | xsi_drive_port_pins(xsim, "stdcore[0]", "XS1_PORT_1A", 1, clock);
52 | if (clock == 1) {
53 | if (time > 100000) {
54 | if (cnt < sizeof(packet)) {
55 | if (cnt == 0 && !even) {
56 | startTime = time;
57 | }
58 | xsi_drive_port_pins(xsim, "stdcore[0]", "XS1_PORT_1B", 1, 1);
59 | xsi_drive_port_pins(xsim, "stdcore[0]", "XS1_PORT_4A", 0xF,
60 | even ? packet[cnt] >> 4 : packet[cnt]);
61 | if (even) {
62 | cnt++;
63 | }
64 | even = !even;
65 | } else {
66 | xsi_drive_port_pins(xsim, "stdcore[0]", "XS1_PORT_1B", 1, 0);
67 | }
68 | }
69 | }
70 | }
71 | if(time % 20 == 4) {
72 | xsi_drive_port_pins(xsim, "stdcore[0]", "XS1_PORT_1C", 1, clock);
73 | if (clock == 0) {
74 | unsigned ready;
75 | xsi_sample_port_pins(xsim, "stdcore[0]", "XS1_PORT_1D", 1, &ready);
76 | if (ready) {
77 | unsigned nibble;
78 | if (!oldready) {
79 | printf("%d ns delay <", time - startTime);
80 | oldready = 1;
81 | }
82 | xsi_sample_port_pins(xsim, "stdcore[0]", "XS1_PORT_4B", 0xF, &nibble);
83 | printf("%01x", nibble);
84 | } else {
85 | if (oldready) {
86 | printf(">\n", time);
87 | oldready = 0;
88 | }
89 | }
90 | }
91 | }
92 | if(time % 5 == 0 || time % 3 == 0) {
93 | status = xsi_clock(xsim);
94 | assert(status == XSI_STATUS_OK || status == XSI_STATUS_DONE );
95 | }
96 | }
97 | status = xsi_terminate(xsim);
98 | return 0;
99 | }
100 |
--------------------------------------------------------------------------------
/doc/design-notes.rst:
--------------------------------------------------------------------------------
1 | Ethercat Design Notes
2 | =====================
3 |
4 | The prototype environment to develop Ethercat is shown below. It comprises
5 | a single L2 motherboard, with 4 ethernet "slices".The bottom left port is
6 | port 0, port 1, 2, and 3 are anticlockwise from there. The XN file included
7 | models that board with all four slices, but missing ports are automatically
8 | skipped.
9 |
10 | .. figure:: photo-4-slices.*
11 | :width: 50%
12 |
13 | Photo of prototype ethercat system with 4 ports.
14 |
15 | Philosophy
16 | ----------
17 |
18 | Ethercat requires a short latency between incoming packet and outgoing
19 | packet. The key to meeting this latency is to use a different design method
20 | then usual for input and output.
21 |
22 | Traditionally one would use 32 bit buffered ports to transport data. A port
23 | with this level of buffering creates a 31-bit latency between a bit
24 | arriving and a bit being processed; or 310 ns. Switching to 8 bit ports
25 | creates 70ns latency instead.
26 |
27 | A second design criterion is that ports that are switched off should be
28 | bypassed. In our design we are achieving this by rerouting channel ends.
29 | The end of a channel always points to the first active transmit port. This
30 | method enables us to add no latency when skipping ports that are not in
31 | use.
32 |
33 | An Ethercat system with N ports requires the following threads:
34 |
35 | #. Data Rx (N)
36 | #. Data Tx (N).
37 | #. Frame processing thread (1)
38 | #. Topology controller (1)
39 |
40 | Data Rx and Tx
41 | --------------
42 |
43 | Each port has a data receive and transmit thread. The receive thread reads
44 | data of the MII port and outputs it over a streaming channel. The transmit
45 | thread reads data from a streaming channel and outputs this onto the MII
46 | ports. The protocol over the channel comprises unidirectional messages from
47 | Rx to Tx that are always delivered as a whole:
48 |
49 | #. A control token, either CT(3) that means *original CRC attached* or CT(0)
50 | that means *no CRC in this stream, please compute one*.
51 |
52 | #. A stream of data bytes comprising the Ethernet frame, including the CRC
53 | if it started with CT(3).
54 |
55 | #. A control token, either CT(0) that means *original CRC was valid* or
56 | CT(15) that means *original CRC was not valid*
57 |
58 | #. An END control token. This closes the channel, enabling it to be
59 | redirected if required.
60 |
61 | The RX process will always set the destination of its output channel prior
62 | to transmitting a packet. That means that a whole packet is either
63 | transmitted to the current channel end, or a different one (if the topology
64 | changed). The RX process will always output a 3 token (CRC attached), and
65 | end with 0/15 as appropriate.
66 |
67 | The TX process will store the start token, and compute a CRC on the data on
68 | the fly, but, if it gets to the final token it takes one of three
69 | decisions:
70 |
71 | #. The start token was CT(3): we have just outputted the original CRC, and
72 | hence we discard our CRC and stop transmitting; packet complete.
73 |
74 | #. The start token was CT(0) and the end token was CT(0): compute the final
75 | CRC, and transmit it.
76 |
77 | #. The start token was CT(0) and the end token was not CT(0): compute the
78 | final CRC, xor it with the final token (invalidating the CRC), and
79 | transmit the invalid CRC. This guarantees that an invalid CRC on input
80 | results in an invalid CRC on output.
81 |
82 |
83 | Frame processing
84 | ----------------
85 |
86 | Frame processing inputs and outputs the packet with the same channel
87 | protocol, but it replaces the initial '3' control token with a '0', and
88 | discards the last 4 btyes of the stream; discarding the CRC, and requesting
89 | the transmitter to compute a new one. This enables the frame processor to
90 | modify the data and implement mailboxes, reads, and writes.
91 |
92 |
93 | Toplogy controller
94 | ------------------
95 |
96 |
97 | The topology controller inspects, using SMI and INT_N wires, whether the
98 | PHYs are connected to other PHYs. Given the current configuration, it
99 | computes the first connected port for each port, and sets up the
100 | destination for each Rx process. Rx process 0 is always destined to the
101 | frame processor, but the FrameProcessor, Rx1, Rx2, and Rx3, communicate with
102 | whatever Tx is next. Fully populated they would transmit to Tx1, Tx2, Tx3,
103 | and Tx0; but if, say, nothing is plugged into port 2, then they would
104 | communicate with Tx1, Tx3, Null, and Tx0.
105 |
106 | This is arranged through an array in some shared memory - the words contain
107 | destination addresses, are written byt he topology controller, and are read
108 | by the Rx/FrameController threads.
109 |
--------------------------------------------------------------------------------
/app_master_harness/src/ping.xc:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "smi.h"
14 | #include "miiClient.h"
15 | #include "miiDriver.h"
16 |
17 | #define ETH_CORE 2
18 |
19 | on stdcore[ETH_CORE]: port led0 = PORT_LED_2_0;
20 | on stdcore[ETH_CORE]: port led1 = PORT_LED_2_1;
21 |
22 | on stdcore[ETH_CORE]: mii_interface_t mii =
23 | {
24 | XS1_CLKBLK_1,
25 | XS1_CLKBLK_2,
26 |
27 | PORT_ETH_RXCLK,
28 | PORT_ETH_RXER,
29 | PORT_ETH_RXD,
30 | PORT_ETH_RXDV,
31 |
32 | PORT_ETH_TXCLK,
33 | PORT_ETH_TXEN,
34 | PORT_ETH_TXD,
35 |
36 | XS1_PORT_8A,
37 | };
38 |
39 | #ifdef PORT_ETH_RST_N
40 | on stdcore[ETH_CORE]: out port p_mii_resetn = PORT_ETH_RST_N;
41 | on stdcore[ETH_CORE]: smi_interface_t smi = { 0, PORT_ETH_MDIO, PORT_ETH_MDC };
42 | #else
43 | on stdcore[ETH_CORE]: smi_interface_t smi = { 0, PORT_ETH_RST_N_MDIO, PORT_ETH_MDC };
44 | #endif
45 |
46 | on stdcore[ETH_CORE]: clock clk_smi = XS1_CLKBLK_5;
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | unsigned char packet[] = {
55 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
56 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
57 | 0x88, 0xA4, // Ethercat frame type
58 |
59 | 0x38, 0x10, // 11 bits length, 4 bit protocol (0x1)
60 |
61 | 0x01, // PDU frame
62 |
63 | 0x01, // Command: Auto Increment Physical Read (first PDU, length 28)
64 | 0x5A, // IDX: master index
65 | 0x00, 0x00, // ADP: auto increment address
66 | 0x01, 0x01, // ADO: physical memory address
67 | 0x10, 0x80, // Length: 16 bytes, not circulated, another PDU to follow
68 | 0x00, 0x00, // IRQ
69 | 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
70 | 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // DATA
71 | 0x00, 0x00, // WKC: working counter.
72 |
73 | 0x02, // Command: Auto Increment Physical Write (second PDU, length 28)
74 | 0x57, // IDX: master index
75 | 0xFF, 0x01, // ADP: auto increment address
76 | 0x30, 0x40, // ADO: physical memory address
77 | 0x10, 0x00, // Length: 16 bytes, not circulated, last PDU
78 | 0x00, 0x00, // IRQ
79 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
80 | 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // DATA
81 | 0x00, 0x00, // WKC: working counter.
82 |
83 | 1,2,3,4,5,6,7,8// PADDING FOR TX.
84 | };
85 |
86 |
87 | static int led0Status = ~0;
88 | static int led1Status = ~0;
89 |
90 | #define NAV 100
91 |
92 | void handlePacket(int a, int nBytes, int rxTime, int txTime) {
93 | static int av[NAV];
94 | static int avc = 0;
95 | static int avsum;
96 | static int avwrapped = 0;
97 | int diff = rxTime - txTime;
98 | int avg;
99 | led0Status = ~led0Status;
100 | led0 <: led0Status;
101 | avsum -= av[avc];
102 | av[avc] = diff;
103 | avsum += diff;
104 | avc ++;
105 | if (avc == NAV) {
106 | avc = 0;
107 | avwrapped = 1;
108 | }
109 | avg = avsum * 1000 / (avwrapped?NAV:avc);
110 | printf("txTime %10u, rxTime %10u diff %d ns Av %d.%02d ns \n", txTime, rxTime, diff * 10, avg / 100, avg % 100);
111 | #if 0
112 | for(int i = 0; i < nBytes; i++) {
113 | int v;
114 | asm("ld8u %0, %1[%2]" : "=r" (v) : "r" (a), "r" (i));
115 | printf(" %02x", v);
116 | if (v != packet[i]) {
117 | printf(" (%02x)", packet[i]);
118 | } else {
119 | printf(" ");
120 | }
121 | if ((i & 0x7) == 0x7) {
122 | printf("\n");
123 | }
124 | }
125 | printf("\n");
126 | #endif
127 | }
128 |
129 | void generateEthercat(chanend cIn, chanend cOut, chanend cNotifications) {
130 | int b[3200];
131 | struct miiData miiData;
132 | timer t;
133 | int timeout;
134 | int transmitTime;
135 |
136 | led0 <: led0Status;
137 | led1 <: led1Status;
138 |
139 | miiBufferInit(miiData, cIn, cNotifications, b, 3200);
140 | miiOutInit(cOut);
141 |
142 | t:> timeout;
143 | timeout += 200000000;
144 | while (1) {
145 | select {
146 | case miiNotified(miiData, cNotifications);
147 | case t when timerafter(timeout) :> void:
148 | timeout += 100000000;
149 | transmitTime = miiOutPacket(cOut, (packet, int[]), 0, sizeof(packet)-8);
150 | miiOutPacketDone(cOut);
151 | led1Status = ~led1Status;
152 | led1 <: led1Status;
153 | break;
154 | }
155 | while(1) {
156 | int nBytes, a, timeStamp;
157 | {a,nBytes,timeStamp} = miiGetInBuffer(miiData);
158 | if (a == 0) {
159 | break;
160 | }
161 | handlePacket(a, nBytes, timeStamp, transmitTime);
162 | miiFreeInBuffer(miiData, a);
163 | }
164 | miiRestartBuffer(miiData);
165 | }
166 | }
167 |
168 | void ethernetLayer(void) {
169 | chan cIn, cOut;
170 | chan notifications;
171 | miiInitialise(smi.p_smi_mdio, mii);
172 | smi_port_init(clk_smi, smi);
173 | eth_phy_config(1, smi);
174 | par {
175 | miiDriver(mii, cIn, cOut);
176 | generateEthercat(cIn, cOut, notifications);
177 | }
178 | }
179 |
180 | int main() {
181 | par {
182 | on stdcore[ETH_CORE]: ethernetLayer();
183 | }
184 | return 0;
185 | }
186 |
--------------------------------------------------------------------------------
/app_ethercat_test/src/main.xc:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "pduhandler.h"
11 | #include "smi.h"
12 |
13 | #define NUMBER_DYNAMIC_CHANNELS 5
14 |
15 | extern int destinationIdentifiers[NUMBER_DYNAMIC_CHANNELS];
16 | extern int destinationIdentifiers_[NUMBER_DYNAMIC_CHANNELS];
17 | extern int destinations[NUMBER_DYNAMIC_CHANNELS];
18 | extern int destinations_[NUMBER_DYNAMIC_CHANNELS];
19 |
20 | extern void waitFor(int &x);
21 |
22 | /** This structure is subtly different from the normal mii_interface_t
23 | * in that it is 8 bit buffered rather than 32 bit buffered. No need
24 | * for a facke port either.
25 | */
26 | typedef struct mii_interface_t {
27 | clock clk_mii_rx; /**< MII RX Clock Block **/
28 | clock clk_mii_tx; /**< MII TX Clock Block **/
29 |
30 | in port p_mii_rxclk; /**< MII RX clock wire */
31 | in port p_mii_rxer; /**< MII RX error wire */
32 | in buffered port:8 p_mii_rxd; /**< MII RX data wire */
33 | in port p_mii_rxdv; /**< MII RX data valid wire */
34 |
35 | in port p_mii_txclk; /**< MII TX clock wire */
36 | out port p_mii_txen; /**< MII TX enable wire */
37 | out buffered port:8 p_mii_txd; /**< MII TX data wire */
38 | } mii_interface_t;
39 |
40 |
41 | on stdcore[2]: mii_interface_t mii0 = {
42 | XS1_CLKBLK_1, XS1_CLKBLK_2,
43 | PORT_ETH_RXCLK_0, PORT_ETH_RXER_0, PORT_ETH_RXD_0, PORT_ETH_RXDV_0,
44 | PORT_ETH_TXCLK_0, PORT_ETH_TXEN_0, PORT_ETH_TXD_0,
45 | };
46 |
47 | on stdcore[2]: mii_interface_t mii1 = {
48 | XS1_CLKBLK_3, XS1_CLKBLK_4,
49 | PORT_ETH_RXCLK_1, PORT_ETH_RXER_1, PORT_ETH_RXD_1, PORT_ETH_RXDV_1,
50 | PORT_ETH_TXCLK_1, PORT_ETH_TXEN_1, PORT_ETH_TXD_1,
51 | };
52 |
53 | on stdcore[2]: out port p_mii_resetn = PORT_ETH_RST_N;
54 | on stdcore[2]: smi_interface_t smi0 = { 0x1f, PORT_ETH_MDIO_0, PORT_ETH_MDC_0 };
55 | on stdcore[2]: smi_interface_t smi1 = { 0x1f, PORT_ETH_MDIO_1, PORT_ETH_MDC_1 };
56 |
57 | on stdcore[2]: clock clk_smi = XS1_CLKBLK_5;
58 |
59 | void mii_port_init(mii_interface_t &m) {
60 | configure_clock_src(m.clk_mii_rx, m.p_mii_rxclk);
61 | configure_clock_src(m.clk_mii_tx, m.p_mii_txclk);
62 |
63 | set_clock_fall_delay(m.clk_mii_tx, 7); // NEEDED?
64 |
65 | configure_in_port_strobed_slave(m.p_mii_rxd, m.p_mii_rxdv, m.clk_mii_rx);
66 | configure_out_port_strobed_master(m.p_mii_txd, m.p_mii_txen, m.clk_mii_tx, 0);
67 |
68 | start_clock(m.clk_mii_rx);
69 | start_clock(m.clk_mii_tx);
70 | }
71 |
72 | #define RESET_TIMER_DELAY 50000
73 |
74 | void phy_reset(out port p_mii_resetn, timer tmr) {
75 | unsigned int resetTime;
76 |
77 | p_mii_resetn <: 0;
78 | tmr :> resetTime;
79 | resetTime += RESET_TIMER_DELAY;
80 | tmr when timerafter(resetTime) :> void;
81 |
82 | p_mii_resetn <: ~0;
83 | tmr :> resetTime;
84 | resetTime += RESET_TIMER_DELAY;
85 | tmr when timerafter(resetTime) :> void;
86 | }
87 |
88 | void linkConnectionChecker(smi_interface_t &smi0, smi_interface_t &smi1) {
89 | timer t;
90 | int u, w0, w1;
91 | int forwarding;
92 | for(int i = 0; i < 3; i++) {
93 | waitFor(destinationIdentifiers_[i]);
94 | destinations_[i] = destinationIdentifiers_[i];
95 | }
96 | forwarding = 0;
97 | t :> u;
98 | while(1) {
99 | u += 150000000;
100 | t when timerafter(u) :> void;
101 | w0 = smiCheckLinkState(smi0);
102 | w1 = smiCheckLinkState(smi1);
103 | // printintln(20000 + w0 * 100 + w1);
104 | if (w1) {
105 | if (!forwarding) {
106 | forwarding = 1;
107 | destinations_[0] = destinationIdentifiers[1];
108 | destinations_[1] = destinationIdentifiers[0];
109 | printstr("Forwarding enabled\n");
110 | }
111 | } else {
112 | if (forwarding) {
113 | forwarding = 0;
114 | destinations_[0] = destinationIdentifiers[0];
115 | destinations_[1] = destinationIdentifiers[0];
116 | printstr("Forwarding disabled\n");
117 | }
118 | }
119 | }
120 | }
121 |
122 |
123 | void ethernetCore() {
124 | streaming chan rx0ToProto, protoToTx1, rx1ToTx0;
125 | timer t;
126 |
127 | phy_reset(p_mii_resetn, t);
128 | mii_port_init(mii0);
129 | mii_port_init(mii1);
130 | printstr("Inited\n");
131 | configure_clock_ref (clk_smi, 10);
132 | configure_out_port_no_ready(smi0.p_smi_mdc, clk_smi, 1);
133 | configure_out_port_no_ready(smi1.p_smi_mdc, clk_smi, 1);
134 | start_clock (clk_smi);
135 |
136 | eth_phy_config(1, smi0);
137 | eth_phy_config(1, smi1);
138 |
139 | printhexln(eth_phy_id(smi0));
140 | printhexln(eth_phy_id(smi1));
141 |
142 | par {
143 | #if 0
144 | rx0Process(mii0.p_mii_rxdv, mii0.p_mii_rxd, rx0ToProto);
145 | frameProcess(rx0ToProto, protoToTx1, txFrame);
146 | txProcess(mii1.p_mii_txd, protoToTx1, tx1);
147 | rxNProcess(mii1.p_mii_rxdv, mii1.p_mii_rxd, rx1ToTx0);
148 | txProcess(mii0.p_mii_txd, rx1ToTx0, tx0);
149 | #else
150 | {
151 | waitFor(destinations[2]);
152 | rxProcessS(mii0.p_mii_rxdv, mii0.p_mii_rxd, rx0ToProto, destinations[2]);
153 | }
154 | {
155 | waitFor(destinations[0]);
156 | frameProcess(rx0ToProto, protoToTx1, destinationIdentifiers[2], destinations[0]);
157 | }
158 | txProcess(mii1.p_mii_txd, protoToTx1, destinationIdentifiers[1]);
159 | {
160 | waitFor(destinations[1]);
161 | rxProcessS(mii1.p_mii_rxdv, mii1.p_mii_rxd, rx1ToTx0, destinations[1]);
162 | }
163 | txProcess(mii0.p_mii_txd, rx1ToTx0, destinationIdentifiers[0]);
164 | #endif
165 | linkConnectionChecker(smi0, smi1);
166 | }
167 | }
168 |
169 | int main(void) {
170 | par {
171 | on stdcore[2]: ethernetCore();
172 | }
173 | return 0;
174 | }
175 |
--------------------------------------------------------------------------------
/app_ethercat_slice/src/main.xc:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011, XMOS Ltd, All rights reserved
2 | // This software is freely distributable under a derivative of the
3 | // University of Illinois/NCSA Open Source License posted in
4 | // LICENSE.txt and at
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "ethercat.h"
11 | #include "pduhandler.h"
12 | #include "smi.h"
13 |
14 | #define ETHCORE 0
15 |
16 | #define NUMBER_DYNAMIC_CHANNELS 2
17 |
18 | extern int destinationsCore0[NUMBER_DYNAMIC_CHANNELS];
19 | extern int destinationsCore0_[NUMBER_DYNAMIC_CHANNELS];
20 | extern int destinationsCore1[NUMBER_DYNAMIC_CHANNELS];
21 | extern int destinationsCore1_[NUMBER_DYNAMIC_CHANNELS];
22 |
23 | extern void waitFor(int &x);
24 |
25 | on stdcore[0]: out port disableFlash = PORT_SPI_DISABLE;
26 |
27 | on stdcore[0]: mii_ethercat_ports mii0 = {
28 | XS1_CLKBLK_3, XS1_CLKBLK_4,
29 | PORT_ETH_RXCLK_0, PORT_ETH_RXD_0, PORT_ETH_RXDV_0,
30 | PORT_ETH_TXCLK_0, PORT_ETH_TXD_0, PORT_ETH_TXEN_0,
31 | };
32 |
33 | on stdcore[0]: mii_ethercat_ports mii1 = {
34 | XS1_CLKBLK_1, XS1_CLKBLK_2,
35 | PORT_ETH_RXCLK_1, PORT_ETH_RXD_1, PORT_ETH_RXDV_1,
36 | PORT_ETH_TXCLK_1, PORT_ETH_TXD_1, PORT_ETH_TXEN_1,
37 | };
38 |
39 | on stdcore[1]: mii_ethercat_ports mii2 = {
40 | XS1_CLKBLK_3, XS1_CLKBLK_4,
41 | PORT_ETH_RXCLK_2, PORT_ETH_RXD_2, PORT_ETH_RXDV_2,
42 | PORT_ETH_TXCLK_2, PORT_ETH_TXD_2, PORT_ETH_TXEN_2,
43 | };
44 |
45 | on stdcore[1]: mii_ethercat_ports mii3 = {
46 | XS1_CLKBLK_1, XS1_CLKBLK_2,
47 | PORT_ETH_RXCLK_3, PORT_ETH_RXD_3, PORT_ETH_RXDV_3,
48 | PORT_ETH_TXCLK_3, PORT_ETH_TXD_3, PORT_ETH_TXEN_3,
49 | };
50 |
51 | on stdcore[0]: smi_interface_t smi0 = { 0x80000000,
52 | PORT_ETH_MDIOFAKE_0,
53 | PORT_ETH_MDIOC_0 };
54 | on stdcore[0]: smi_interface_t smi1 = { 0,
55 | PORT_ETH_MDIO_1,
56 | PORT_ETH_MDC_1 };
57 | on stdcore[1]: smi_interface_t smi2 = { 0x80000000,
58 | PORT_ETH_MDIOFAKE_2,
59 | PORT_ETH_MDIOC_2 };
60 | on stdcore[1]: smi_interface_t smi3 = { 0,
61 | PORT_ETH_MDIO_3,
62 | PORT_ETH_MDC_3 };
63 |
64 | on stdcore[0]: clock clk_smi0 = XS1_CLKBLK_5;
65 | on stdcore[1]: clock clk_smi2 = XS1_CLKBLK_5;
66 |
67 | int phyPresentAndUp(smi_interface_t &smi) {
68 | int basicStatus = smi_reg(smi, 1, 0, 1);
69 | return (basicStatus & 0x12) == 0 && (basicStatus & 4) == 4;
70 | }
71 |
72 | #define NUMBER_PORTS 4
73 |
74 | void connectionHandler(chanend from0, chanend from1) {
75 | int portIsConnected[NUMBER_PORTS];
76 | int portIdentifiers[NUMBER_PORTS];
77 | int destinations[NUMBER_PORTS];
78 |
79 | for(int i = 0; i < NUMBER_PORTS; i++) {
80 | portIsConnected[i] = 1;
81 | }
82 |
83 | from0 :> portIdentifiers[0];
84 | from0 :> portIdentifiers[1];
85 | from1 :> portIdentifiers[2];
86 | from1 :> portIdentifiers[3];
87 |
88 | while(1) {
89 | from0 :> portIsConnected[0];
90 | from0 :> portIsConnected[1];
91 | from1 :> portIsConnected[2];
92 | from1 :> portIsConnected[3];
93 | portIsConnected[0] = 1; // Assume connected. Better be.
94 |
95 | for(int i = 0; i < NUMBER_PORTS; i++) {
96 | if (!portIsConnected[i]) {
97 | destinations[i] = portIdentifiers[i] | 0xff00; // null chan
98 | continue;
99 | }
100 | for(int j = i+1; j < NUMBER_PORTS+1; j++) {
101 | int portNr;
102 | if (j == NUMBER_PORTS) {
103 | portNr = 0;
104 | } else {
105 | portNr = j;
106 | }
107 | if (portIsConnected[portNr]) {
108 | destinations[i] = portIdentifiers[portNr];
109 | break;
110 | }
111 | }
112 | }
113 | from0 <: destinations[0];
114 | from0 <: destinations[1];
115 | from1 <: destinations[2];
116 | from1 <: destinations[3];
117 | }
118 | }
119 |
120 | void linkConnectionChecker(smi_interface_t &smi0, smi_interface_t &smi1,
121 | chanend toMaster,
122 | int destinations_[2],
123 | chanend init0, chanend init1) {
124 | timer t;
125 | int u, w0, w1, dest;
126 |
127 | init0 :> dest;
128 | toMaster <: dest;
129 | init1 :> dest;
130 | toMaster <: dest;
131 |
132 | t :> u;
133 |
134 | while(1) {
135 | u += 150000000;
136 | t when timerafter(u) :> void;
137 | w0 = phyPresentAndUp(smi0);
138 | w1 = phyPresentAndUp(smi1);
139 | toMaster <: w0;
140 | toMaster <: w1;
141 | toMaster :> destinations_[0];
142 | toMaster :> destinations_[1];
143 | }
144 | }
145 |
146 | void publishDestination(chanend init, streaming chanend dest) {
147 | int i;
148 | asm("add %0, %1, 0" : "=r" (i) : "r" (dest));
149 | init <: i;
150 | }
151 |
152 | void ethernetCore(mii_ethercat_ports &mii0, mii_ethercat_ports &mii1,
153 | smi_interface_t &smi0, smi_interface_t &smi1,
154 | clock clk_smi, out port ?disableFlash,
155 | chanend toMaster,
156 | int destinations[2], int destinations_[2],
157 | int isProcessingNode) {
158 | streaming chan protoToTx1, rx1ToTx0;
159 | timer tmr;
160 | int resetTime;
161 | chan init0, init1;
162 | int tempDestination;
163 | short memory[100];
164 |
165 | if (!isnull(disableFlash)) {
166 | disableFlash <: 0;
167 | }
168 |
169 | tmr :> resetTime;
170 | resetTime += 50000000;
171 | tmr when timerafter(resetTime) :> void;
172 |
173 | ethercat_port_init(mii0);
174 | ethercat_port_init(mii1);
175 | configure_clock_ref (clk_smi, 10);
176 | configure_out_port_no_ready(smi0.p_smi_mdc, clk_smi, 1);
177 | configure_out_port_no_ready(smi1.p_smi_mdc, clk_smi, 1<
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "ethercat.h"
11 | #include "pduhandler.h"
12 | #include "smi.h"
13 |
14 | #define ETHCORE 0
15 |
16 | #define NUMBER_DYNAMIC_CHANNELS 2
17 |
18 | extern int destinationsCore0[NUMBER_DYNAMIC_CHANNELS];
19 | extern int destinationsCore0_[NUMBER_DYNAMIC_CHANNELS];
20 | extern int destinationsCore1[NUMBER_DYNAMIC_CHANNELS];
21 | extern int destinationsCore1_[NUMBER_DYNAMIC_CHANNELS];
22 |
23 | extern void waitFor(int &x);
24 |
25 | on stdcore[0]: out port disableFlash = PORT_SPI_DISABLE;
26 |
27 | on stdcore[1]: mii_ethercat_ports mii0 = {
28 | XS1_CLKBLK_3, XS1_CLKBLK_4,
29 | PORT_ETH_RXCLK_0, PORT_ETH_RXD_0, PORT_ETH_RXDV_0,
30 | PORT_ETH_TXCLK_0, PORT_ETH_TXD_0, PORT_ETH_TXEN_0,
31 | };
32 |
33 | on stdcore[1]: mii_ethercat_ports mii1 = {
34 | XS1_CLKBLK_1, XS1_CLKBLK_2,
35 | PORT_ETH_RXCLK_1, PORT_ETH_RXD_1, PORT_ETH_RXDV_1,
36 | PORT_ETH_TXCLK_1, PORT_ETH_TXD_1, PORT_ETH_TXEN_1,
37 | };
38 |
39 | on stdcore[0]: mii_ethercat_ports mii2 = {
40 | XS1_CLKBLK_3, XS1_CLKBLK_4,
41 | PORT_ETH_RXCLK_2, PORT_ETH_RXD_2, PORT_ETH_RXDV_2,
42 | PORT_ETH_TXCLK_2, PORT_ETH_TXD_2, PORT_ETH_TXEN_2,
43 | };
44 |
45 | on stdcore[0]: mii_ethercat_ports mii3 = {
46 | XS1_CLKBLK_1, XS1_CLKBLK_2,
47 | PORT_ETH_RXCLK_3, PORT_ETH_RXD_3, PORT_ETH_RXDV_3,
48 | PORT_ETH_TXCLK_3, PORT_ETH_TXD_3, PORT_ETH_TXEN_3,
49 | };
50 |
51 | on stdcore[1]: smi_interface_t smi0 = { 0x80000000,
52 | PORT_ETH_MDIOFAKE_0,
53 | PORT_ETH_MDIOC_0 };
54 | on stdcore[1]: smi_interface_t smi1 = { 0,
55 | PORT_ETH_MDIO_1,
56 | PORT_ETH_MDC_1 };
57 | on stdcore[0]: smi_interface_t smi2 = { 0x80000000,
58 | PORT_ETH_MDIOFAKE_2,
59 | PORT_ETH_MDIOC_2 };
60 | on stdcore[0]: smi_interface_t smi3 = { 0,
61 | PORT_ETH_MDIO_3,
62 | PORT_ETH_MDC_3 };
63 |
64 | on stdcore[1]: clock clk_smi0 = XS1_CLKBLK_5;
65 | on stdcore[0]: clock clk_smi2 = XS1_CLKBLK_5;
66 |
67 | int phyPresentAndUp(smi_interface_t &smi) {
68 | int basicStatus = smi_reg(smi, 1, 0, 1);
69 | return (basicStatus & 0x12) == 0 && (basicStatus & 4) == 4;
70 | }
71 |
72 | #define NUMBER_PORTS 4
73 |
74 | void connectionHandler(chanend from0, chanend from1) {
75 | int portIsConnected[NUMBER_PORTS];
76 | int portIdentifiers[NUMBER_PORTS];
77 | int destinations[NUMBER_PORTS];
78 |
79 | for(int i = 0; i < NUMBER_PORTS; i++) {
80 | portIsConnected[i] = 1;
81 | }
82 |
83 | from0 :> portIdentifiers[0];
84 | from0 :> portIdentifiers[1];
85 | from1 :> portIdentifiers[2];
86 | from1 :> portIdentifiers[3];
87 |
88 | while(1) {
89 | from0 :> portIsConnected[0];
90 | from0 :> portIsConnected[1];
91 | from1 :> portIsConnected[2];
92 | from1 :> portIsConnected[3];
93 | portIsConnected[0] = 1; // Assume connected. Better be.
94 |
95 | for(int i = 0; i < NUMBER_PORTS; i++) {
96 | if (!portIsConnected[i]) {
97 | destinations[i] = portIdentifiers[i] | 0xff00; // null chan
98 | continue;
99 | }
100 | for(int j = i+1; j < NUMBER_PORTS+1; j++) {
101 | int portNr;
102 | if (j == NUMBER_PORTS) {
103 | portNr = 0;
104 | } else {
105 | portNr = j;
106 | }
107 | if (portIsConnected[portNr]) {
108 | destinations[i] = portIdentifiers[portNr];
109 | break;
110 | }
111 | }
112 | }
113 | from0 <: destinations[0];
114 | from0 <: destinations[1];
115 | from1 <: destinations[2];
116 | from1 <: destinations[3];
117 | }
118 | }
119 |
120 | void linkConnectionChecker(smi_interface_t &smi0, smi_interface_t &smi1,
121 | chanend toMaster,
122 | int destinations_[2],
123 | chanend init0, chanend init1) {
124 | timer t;
125 | int u, w0, w1, dest;
126 |
127 | init0 :> dest;
128 | toMaster <: dest;
129 | init1 :> dest;
130 | toMaster <: dest;
131 |
132 | t :> u;
133 |
134 | while(1) {
135 | u += 150000000;
136 | t when timerafter(u) :> void;
137 | w0 = phyPresentAndUp(smi0);
138 | w1 = phyPresentAndUp(smi1);
139 | toMaster <: w0;
140 | toMaster <: w1;
141 | toMaster :> destinations_[0];
142 | toMaster :> destinations_[1];
143 | }
144 | }
145 |
146 | void publishDestination(chanend init, streaming chanend dest) {
147 | int i;
148 | asm("add %0, %1, 0" : "=r" (i) : "r" (dest));
149 | init <: i;
150 | }
151 |
152 |
153 |
154 |
155 | void ethernetCore(mii_ethercat_ports &mii0, mii_ethercat_ports &mii1,
156 | smi_interface_t &smi0, smi_interface_t &smi1,
157 | clock clk_smi, out port ?disableFlash,
158 | chanend toMaster,
159 | int destinations[2], int destinations_[2],
160 | int isProcessingNode) {
161 | short memory[4096];
162 | streaming chan protoToTx1, rx1ToTx0;
163 | timer tmr;
164 | int resetTime;
165 | chan init0, init1;
166 | int tempDestination;
167 |
168 | memory[0x502/2] = 0;
169 |
170 | if (!isnull(disableFlash)) {
171 | disableFlash <: 0;
172 | }
173 |
174 | tmr :> resetTime;
175 | resetTime += 50000000;
176 | tmr when timerafter(resetTime) :> void;
177 |
178 | ethercat_port_init(mii0);
179 | ethercat_port_init(mii1);
180 | configure_clock_ref (clk_smi, 10);
181 | configure_out_port_no_ready(smi0.p_smi_mdc, clk_smi, 1);
182 | configure_out_port_no_ready(smi1.p_smi_mdc, clk_smi, 1<
5 |
6 | #include
7 | #include
8 | #include
9 | #include "pduhandler.h"
10 |
11 | extern int rx0, rx1;
12 |
13 | #define MEM_LENGTH 8192
14 |
15 |
16 | void passthrough(streaming chanend fromRx, streaming chanend toTx) {
17 | unsigned char byte;
18 | while (!stestct(fromRx)) {
19 | fromRx :> byte; toTx <: byte;
20 | }
21 | soutct(toTx, sinct(fromRx));
22 | soutct(toTx, 1);
23 | schkct(fromRx, 1);
24 | }
25 |
26 | static inline unsigned char passByte(streaming chanend fromRx, streaming chanend toTx) {
27 | unsigned char byte;
28 | fromRx :> byte; toTx <: byte;
29 | return byte;
30 | }
31 |
32 | static inline int pass16(streaming chanend fromRx, streaming chanend toTx) {
33 | unsigned char byteH, byteL;
34 | fromRx :> byteL; toTx <: byteL; // ADO, Physical address
35 | fromRx :> byteH; toTx <: byteH; // ADO
36 | return byteL | (byteH << 8);
37 | }
38 |
39 | static inline int pass32(streaming chanend fromRx, streaming chanend toTx) {
40 | unsigned char byteH, byteL;
41 | int a;
42 | fromRx :> byteL; toTx <: byteL;
43 | fromRx :> byteH; toTx <: byteH;
44 | a = byteL | (byteH << 8);
45 | fromRx :> byteH; toTx <: byteH;
46 | a |= byteH << 16;
47 | fromRx :> byteH; toTx <: byteH;
48 | return a | byteH << 24;
49 | }
50 |
51 | static inline int passADPinc(streaming chanend fromRx, streaming chanend toTx) {
52 | unsigned char byteH, byteL, byteH_, byteL_;
53 | fromRx :> byteL; // Auto Inc address
54 | byteL_ = byteL + 1;
55 | toTx <: byteL_;
56 | fromRx :> byteH; // Auto Inc address
57 | if (byteL_ == 0) {
58 | byteH_ = byteH + 1;
59 | }
60 | toTx <: byteH_;
61 | return (byteL | byteH) == 0;
62 | }
63 |
64 | static inline int passADO(streaming chanend fromRx, streaming chanend toTx) {
65 | return pass16(fromRx, toTx);
66 | }
67 |
68 | static inline int passADR(streaming chanend fromRx, streaming chanend toTx) {
69 | return pass32(fromRx, toTx);
70 | }
71 |
72 | static inline int passADP(streaming chanend fromRx, streaming chanend toTx) {
73 | return pass16(fromRx, toTx);
74 | }
75 |
76 | static inline int passTotalLength(streaming chanend fromRx, streaming chanend toTx) {
77 | return pass16(fromRx, toTx);
78 | }
79 |
80 | static inline int passLEN(streaming chanend fromRx, streaming chanend toTx, int &morePDUs) {
81 | unsigned char byteH, byteL;
82 | fromRx :> byteL; toTx <: byteL; // LEN
83 | fromRx :> byteH; toTx <: byteH; // LEN
84 | morePDUs = byteH >> 7;
85 | return byteL | (byteH & 0x7 << 8);
86 | }
87 |
88 | static inline void passIRQ(streaming chanend fromRx, streaming chanend toTx) {
89 | passByte(fromRx, toTx);
90 | passByte(fromRx, toTx);
91 | }
92 |
93 | static inline void passWKCinc(streaming chanend fromRx, streaming chanend toTx) {
94 | unsigned char byteH, byteL, byteH_, byteL_;
95 | fromRx :> byteL;
96 | byteL_ = byteL + 1;
97 | toTx <: byteL_;
98 | fromRx :> byteH;
99 | if (byteL_ == 0) {
100 | byteH_ = byteH + 1;
101 | }
102 | toTx <: byteH_;
103 | }
104 |
105 | static inline void passWKC(streaming chanend fromRx, streaming chanend toTx) {
106 | passByte(fromRx, toTx);
107 | passByte(fromRx, toTx);
108 | }
109 |
110 |
111 | #pragma unsafe arrays
112 | void frameProcess(streaming chanend fromRx, streaming chanend toTx, int &destination, short memoryWord[]) {
113 | int handled = 0;
114 | unsigned char byte, ot2 = 0;
115 | unsigned total;
116 | int cnt = 0;
117 | int morePDUs, operate, address, length, station;
118 | int defaultDest;
119 |
120 | asm("getd %0,res[%1]" : "=r" (defaultDest) : "r" (toTx));
121 | destination = defaultDest;
122 |
123 | while (1) {
124 | morePDUs = 1;
125 | schkct(fromRx, 3);
126 | asm("setd res[%0],%1" :: "r" (toTx), "r" (destination));
127 | soutct(toTx, 0); // Recompute CRC.
128 | #pragma loop unroll
129 | for(int i = 0; i < 12; i++) {
130 | fromRx :> byte; toTx <: byte;
131 | }
132 | fromRx :> byte; toTx <: byte;
133 | if (byte != 0x88) {
134 | // printf("Got <%02x> not 0x88\n", byte);
135 | passthrough(fromRx, toTx); continue;
136 | }
137 | fromRx :> byte; toTx <: byte;
138 | if (byte != 0xA4) {
139 | // printf("Got <%02x> not 0xA4\n", byte);
140 | passthrough(fromRx, toTx); continue;
141 | }
142 | total = passTotalLength(fromRx, toTx);
143 | byte = total >> 12;
144 | total &= 0xfff;
145 | // ot = total;
146 | // fromRx :> byte; toTx <: byte; // frame type
147 | if (total < 44) {
148 | total = 44;
149 | }
150 | switch(byte) {
151 | case 1: // PDU frame
152 | do {
153 | fromRx :> byte; toTx <: byte; // Command
154 | switch(byte) {
155 | case 0x01: // APRD
156 | passByte(fromRx, toTx); // IDX
157 | operate = passADPinc(fromRx, toTx); // ADP
158 | address = passADO(fromRx, toTx); // ADO
159 | length = passLEN(fromRx, toTx, morePDUs); // ADO
160 | passIRQ(fromRx, toTx);
161 | total -= length + 12;
162 | if (operate) {
163 | for(int i = 0; i < length; i++) {
164 | fromRx :> byte;
165 | toTx <: (memoryWord, unsigned char[])[address++];
166 | }
167 | passWKCinc(fromRx, toTx);
168 | } else {
169 | for(int i = 0; i < length; i++) {
170 | passByte(fromRx, toTx);
171 | }
172 | passWKC(fromRx, toTx);
173 | }
174 | break;
175 | case 0x02: // APWR
176 | passByte(fromRx, toTx); // IDX
177 | operate = passADPinc(fromRx, toTx); // ADP
178 | address = passADO(fromRx, toTx); // ADO
179 | length = passLEN(fromRx, toTx, morePDUs); // ADO
180 | passIRQ(fromRx, toTx);
181 | ot2 = total;
182 | total -= length + 12;
183 | if (operate) {
184 | for(int i = 0; i < length; i++) {
185 | (memoryWord, unsigned char[])[address++] = passByte(fromRx, toTx);
186 | }
187 | passWKCinc(fromRx, toTx);
188 | } else {
189 | for(int i = 0; i < length; i++) {
190 | passByte(fromRx, toTx);
191 | }
192 | passWKC(fromRx, toTx);
193 | }
194 | break;
195 | case 0x04: // FPRD
196 | passByte(fromRx, toTx); // IDX
197 | station = passADP(fromRx, toTx); // ADP
198 | operate = station == memoryWord[0x0010/2];
199 | address = passADO(fromRx, toTx); // ADO
200 | operate |= station == memoryWord[0x0012/2];
201 | length = passLEN(fromRx, toTx, morePDUs);
202 | passIRQ(fromRx, toTx);
203 | total -= length + 12;
204 | if (operate) {
205 | for(int i = 0; i < length; i++) {
206 | fromRx :> byte;
207 | toTx <: (memoryWord, unsigned char[])[address++];
208 | }
209 | passWKCinc(fromRx, toTx);
210 | } else {
211 | printf("Station %04x Word %04x\n", station, memoryWord[0x0010/2]);
212 | for(int i = 0; i < length; i++) {
213 | passByte(fromRx, toTx);
214 | }
215 | passWKC(fromRx, toTx);
216 | }
217 | break;
218 | case 0x05: // FPWR
219 | passByte(fromRx, toTx); // IDX
220 | station = passADP(fromRx, toTx); // ADP
221 | operate = station == memoryWord[0x0010/2];
222 | address = passADO(fromRx, toTx); // ADO
223 | operate |= station == memoryWord[0x0012/2];
224 | length = passLEN(fromRx, toTx, morePDUs);
225 | passIRQ(fromRx, toTx);
226 | total -= length + 12;
227 | if (operate) {
228 | for(int i = 0; i < length; i++) {
229 | (memoryWord, unsigned char[])[address++] = passByte(fromRx, toTx);
230 | }
231 | passWKCinc(fromRx, toTx);
232 | } else {
233 | for(int i = 0; i < length; i++) {
234 | passByte(fromRx, toTx);
235 | }
236 | passWKC(fromRx, toTx);
237 | }
238 | break;
239 | case 0x07: // BRD
240 | passByte(fromRx, toTx); // IDX
241 | passADPinc(fromRx, toTx); // ADP
242 | address = passADO(fromRx, toTx); // ADO
243 | length = passLEN(fromRx, toTx, morePDUs);
244 | operate = address+length < MEM_LENGTH;
245 | passIRQ(fromRx, toTx);
246 | total -= length + 12;
247 | if (operate) {
248 | for(int i = 0; i < length; i++) {
249 | fromRx :> byte;
250 | toTx <: (unsigned char) (byte | (memoryWord, unsigned char[])[address++]);
251 | }
252 | passWKCinc(fromRx, toTx);
253 | } else {
254 | for(int i = 0; i < length; i++) {
255 | passByte(fromRx, toTx);
256 | }
257 | passWKC(fromRx, toTx);
258 | }
259 | break;
260 | case 0x08: // BWR
261 | passByte(fromRx, toTx); // IDX
262 | passADPinc(fromRx, toTx); // ADP
263 | address = passADO(fromRx, toTx); // ADO
264 | length = passLEN(fromRx, toTx, morePDUs); // ADO
265 | operate = address+length < MEM_LENGTH;
266 | passIRQ(fromRx, toTx);
267 | total -= length + 12;
268 | if (operate) {
269 | #pragma unsafe arrays
270 | for(int i = 0; i < length; i++) {
271 | (memoryWord, unsigned char[])[address++] = passByte(fromRx, toTx);
272 | }
273 | passWKCinc(fromRx, toTx);
274 | } else {
275 | for(int i = 0; i < length; i++) {
276 | passByte(fromRx, toTx);
277 | }
278 | passWKC(fromRx, toTx);
279 | }
280 | break;
281 | case 0x0A: // LRD
282 | passByte(fromRx, toTx); // IDX
283 | address = passADR(fromRx, toTx); // ADO
284 | length = passLEN(fromRx, toTx, morePDUs);
285 | operate = 1; /* TO BE DECIDED */
286 | passIRQ(fromRx, toTx);
287 | total -= length + 12;
288 | if (operate) {
289 | for(int i = 0; i < length; i++) {
290 | fromRx :> byte;
291 | toTx <: (memoryWord, unsigned char[])[address++];
292 | }
293 | passWKCinc(fromRx, toTx);
294 | } else {
295 | for(int i = 0; i < length; i++) {
296 | passByte(fromRx, toTx);
297 | }
298 | passWKC(fromRx, toTx);
299 | }
300 | break;
301 | case 0x0B: // LWR
302 | break;
303 | default:
304 | printf("Did not see a known command but %02x\n", byte);
305 | passthrough(fromRx, toTx);
306 | break;
307 | }
308 | } while (morePDUs);
309 | break;
310 | default:
311 | printf("Did not see a PDU frame but %02x\n", byte);
312 | passthrough(fromRx, toTx);
313 | break;
314 | }
315 | for(int i = 0; i < total; i++) { // transmit any trailer, but not the CRC.
316 | passByte(fromRx, toTx);
317 | }
318 | fromRx :> int _; // gobble up CRC.
319 | soutct(toTx, sinct(fromRx));
320 | soutct(toTx, 1);
321 | schkct(fromRx, 1);
322 | asm("add %0, %1, 1" : "=r"(cnt) : "r" (cnt));
323 | asm("add %0, %1, 1" : "=r"(cnt) : "r" (total));
324 | asm("add %0, %1, 1" : "=r"(cnt) : "r" (address));
325 | asm("add %0, %1, 1" : "=r"(handled) : "r" (handled));
326 | }
327 | }
328 |
--------------------------------------------------------------------------------
/.cproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
47 |
61 |
62 |
63 |
64 |
78 |
92 |
93 |
94 |
95 |
96 |
114 |
132 |
133 |
134 |
135 |
136 |
150 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 | xmake
270 | -f .makefile
271 | all
272 | true
273 | false
274 | true
275 |
276 |
277 | xmake
278 | -f Makefile
279 | app_uart_test.all
280 | true
281 | true
282 | true
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
--------------------------------------------------------------------------------
/doc/threads.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
601 |
--------------------------------------------------------------------------------