aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/microblaze/lib
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/microblaze/lib')
-rw-r--r--firmware/microblaze/lib/.gitignore40
-rw-r--r--firmware/microblaze/lib/Makefile.am88
-rw-r--r--firmware/microblaze/lib/_exit.c27
-rw-r--r--firmware/microblaze/lib/abort.c32
-rw-r--r--firmware/microblaze/lib/ad9510.c42
-rw-r--r--firmware/microblaze/lib/ad9510.h30
-rw-r--r--firmware/microblaze/lib/arp_cache.c90
-rw-r--r--firmware/microblaze/lib/arp_cache.h33
-rw-r--r--firmware/microblaze/lib/banal.c49
-rw-r--r--firmware/microblaze/lib/banal.h93
-rw-r--r--firmware/microblaze/lib/bsm12.c319
-rw-r--r--firmware/microblaze/lib/bsm12.h83
-rw-r--r--firmware/microblaze/lib/buffer_pool.c72
-rw-r--r--firmware/microblaze/lib/buffer_pool.h75
-rw-r--r--firmware/microblaze/lib/clocks.c239
-rw-r--r--firmware/microblaze/lib/clocks.h95
-rw-r--r--firmware/microblaze/lib/dbsm.c297
-rw-r--r--firmware/microblaze/lib/dbsm.h90
-rw-r--r--firmware/microblaze/lib/eeprom.c69
-rw-r--r--firmware/microblaze/lib/eth_mac.c127
-rw-r--r--firmware/microblaze/lib/eth_mac.h32
-rw-r--r--firmware/microblaze/lib/eth_mac_regs.h62
-rw-r--r--firmware/microblaze/lib/eth_phy.h219
-rw-r--r--firmware/microblaze/lib/ethernet.c390
-rw-r--r--firmware/microblaze/lib/ethernet.h93
-rw-r--r--firmware/microblaze/lib/ethertype.h27
-rw-r--r--firmware/microblaze/lib/exit.c28
-rw-r--r--firmware/microblaze/lib/hal_io.c323
-rw-r--r--firmware/microblaze/lib/hal_io.h166
-rw-r--r--firmware/microblaze/lib/hal_uart.c77
-rw-r--r--firmware/microblaze/lib/hal_uart.h68
-rw-r--r--firmware/microblaze/lib/i2c.c127
-rw-r--r--firmware/microblaze/lib/i2c.h39
-rw-r--r--firmware/microblaze/lib/if_arp.h153
-rw-r--r--firmware/microblaze/lib/mdelay.c73
-rw-r--r--firmware/microblaze/lib/mdelay.h29
-rw-r--r--firmware/microblaze/lib/memcpy_wa.c42
-rw-r--r--firmware/microblaze/lib/memcpy_wa.h32
-rw-r--r--firmware/microblaze/lib/memory_map.h796
-rw-r--r--firmware/microblaze/lib/memset_wa.c45
-rw-r--r--firmware/microblaze/lib/memset_wa.h27
-rw-r--r--firmware/microblaze/lib/net_common.c449
-rw-r--r--firmware/microblaze/lib/net_common.h50
-rw-r--r--firmware/microblaze/lib/nonstdio.c80
-rw-r--r--firmware/microblaze/lib/nonstdio.h46
-rw-r--r--firmware/microblaze/lib/pic.c94
-rw-r--r--firmware/microblaze/lib/pic.h35
-rw-r--r--firmware/microblaze/lib/print_buffer.c36
-rw-r--r--firmware/microblaze/lib/print_fxpt.c83
-rw-r--r--firmware/microblaze/lib/print_mac_addr.c30
-rw-r--r--firmware/microblaze/lib/print_rmon_regs.c44
-rw-r--r--firmware/microblaze/lib/print_rmon_regs.h24
-rw-r--r--firmware/microblaze/lib/printf.c134
-rw-r--r--firmware/microblaze/lib/printf.c.smaller134
-rw-r--r--firmware/microblaze/lib/sd.c197
-rw-r--r--firmware/microblaze/lib/sd.h122
-rw-r--r--firmware/microblaze/lib/spi.c61
-rw-r--r--firmware/microblaze/lib/spi.h52
-rw-r--r--firmware/microblaze/lib/stdint.h34
-rw-r--r--firmware/microblaze/lib/stdio.h38
-rw-r--r--firmware/microblaze/lib/u2_init.c107
-rw-r--r--firmware/microblaze/lib/u2_init.h31
-rw-r--r--firmware/microblaze/lib/usrp2_bytesex.h66
-rw-r--r--firmware/microblaze/lib/wb16550.h98
64 files changed, 6883 insertions, 0 deletions
diff --git a/firmware/microblaze/lib/.gitignore b/firmware/microblaze/lib/.gitignore
new file mode 100644
index 000000000..5d838bf6c
--- /dev/null
+++ b/firmware/microblaze/lib/.gitignore
@@ -0,0 +1,40 @@
+*~
+/*-stamp
+/*.a
+/*.bin
+/*.dump
+/*.log
+/*.rom
+/.deps
+/Makefile
+/Makefile.in
+/aclocal.m4
+/autom4te.cache
+/blink_leds
+/blink_leds2
+/build
+/compile
+/config.h
+/config.h.in
+/config.log
+/config.status
+/configure
+/depcomp
+/eth_test
+/gen_eth_packets
+/ibs_rx_test
+/ibs_tx_test
+/install-sh
+/libtool
+/ltmain.sh
+/missing
+/py-compile
+/rcv_eth_packets
+/run_tests.sh
+/stamp-h1
+/test1
+/test_phy_comm
+/timer_test
+/buf_ram_test
+/buf_ram_zero
+/hello
diff --git a/firmware/microblaze/lib/Makefile.am b/firmware/microblaze/lib/Makefile.am
new file mode 100644
index 000000000..783895850
--- /dev/null
+++ b/firmware/microblaze/lib/Makefile.am
@@ -0,0 +1,88 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+# Copyright 2007 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+include $(top_srcdir)/Makefile.common
+
+noinst_LIBRARIES = \
+ libu2fw.a
+
+libu2fw_a_SOURCES = \
+ abort.c \
+ ad9510.c \
+ bsm12.c \
+ buffer_pool.c \
+ clocks.c \
+ dbsm.c \
+ eeprom.c \
+ ethernet.c \
+ eth_mac.c \
+ _exit.c \
+ exit.c \
+ hal_io.c \
+ hal_uart.c \
+ i2c.c \
+ mdelay.c \
+ memcpy_wa.c \
+ memset_wa.c \
+ nonstdio.c \
+ pic.c \
+ print_mac_addr.c \
+ print_rmon_regs.c \
+ print_fxpt.c \
+ print_buffer.c \
+ printf.c \
+ sd.c \
+ spi.c \
+ u2_init.c \
+ net_common.c \
+ arp_cache.c \
+ banal.c
+
+noinst_HEADERS = \
+ ad9510.h \
+ bsm12.h \
+ buffer_pool.h \
+ clocks.h \
+ dbsm.h \
+ eth_mac.h \
+ eth_mac_regs.h \
+ eth_phy.h \
+ ethernet.h \
+ hal_io.h \
+ hal_uart.h \
+ i2c.h \
+ mdelay.h \
+ memcpy_wa.h \
+ memory_map.h \
+ memset_wa.h \
+ nonstdio.h \
+ pic.h \
+ print_rmon_regs.h \
+ sd.h \
+ spi.h \
+ stdint.h \
+ stdio.h \
+ u2_init.h \
+ usrp2_bytesex.h \
+ wb16550.h \
+ net_common.h \
+ if_arp.h \
+ arp_cache.h \
+ banal.h \
+ ethertype.h
diff --git a/firmware/microblaze/lib/_exit.c b/firmware/microblaze/lib/_exit.c
new file mode 100644
index 000000000..9b40ab2ee
--- /dev/null
+++ b/firmware/microblaze/lib/_exit.c
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Stub so we can compile using 3.4 based mb-gcc
+ */
+void
+_exit(int status)
+{
+ while (1)
+ ;
+}
diff --git a/firmware/microblaze/lib/abort.c b/firmware/microblaze/lib/abort.c
new file mode 100644
index 000000000..d1d709392
--- /dev/null
+++ b/firmware/microblaze/lib/abort.c
@@ -0,0 +1,32 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <nonstdio.h>
+
+extern void _exit(int status);
+
+void
+abort(void)
+{
+ putstr("\n\nabort\n");
+ // FIXME loop blinking leds
+ _exit(-1);
+}
diff --git a/firmware/microblaze/lib/ad9510.c b/firmware/microblaze/lib/ad9510.c
new file mode 100644
index 000000000..4d3acb65d
--- /dev/null
+++ b/firmware/microblaze/lib/ad9510.c
@@ -0,0 +1,42 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ad9510.h"
+#include "spi.h"
+#include <memory_map.h>
+
+#define RD (1 << 15)
+#define WR (0 << 15)
+
+void
+ad9510_write_reg(int regno, uint8_t value)
+{
+ uint32_t inst = WR | (regno & 0xff);
+ uint32_t v = (inst << 8) | (value & 0xff);
+ spi_transact(SPI_TXONLY, SPI_SS_AD9510, v, 24, SPIF_PUSH_FALL);
+}
+
+int
+ad9510_read_reg(int regno)
+{
+ uint32_t inst = RD | (regno & 0xff);
+ uint32_t v = (inst << 8) | 0;
+ uint32_t r = spi_transact(SPI_TXRX, SPI_SS_AD9510, v, 24,
+ SPIF_PUSH_FALL | SPIF_LATCH_FALL);
+ return r & 0xff;
+}
diff --git a/firmware/microblaze/lib/ad9510.h b/firmware/microblaze/lib/ad9510.h
new file mode 100644
index 000000000..a395e5223
--- /dev/null
+++ b/firmware/microblaze/lib/ad9510.h
@@ -0,0 +1,30 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_AD9510_H
+#define INCLUDED_AD9510_H
+
+#include <stdint.h>
+
+/*
+ * Analog Device AD9510 1.2 GHz Clock Distribution IC w/ PLL
+ */
+
+void ad9510_write_reg(int regno, uint8_t value);
+int ad9510_read_reg(int regno);
+
+#endif /* INCLUDED_AD9510_H */
diff --git a/firmware/microblaze/lib/arp_cache.c b/firmware/microblaze/lib/arp_cache.c
new file mode 100644
index 000000000..9c586fa6b
--- /dev/null
+++ b/firmware/microblaze/lib/arp_cache.c
@@ -0,0 +1,90 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "arp_cache.h"
+#include <stddef.h>
+
+typedef struct {
+ struct ip_addr ip;
+ eth_mac_addr_t mac;
+} arp_cache_t;
+
+#define NENTRIES 8 // power-of-2
+
+static size_t nentries;
+static size_t victim;
+static arp_cache_t cache[NENTRIES];
+
+void
+arp_cache_init(void)
+{
+ nentries = 0;
+ victim = 0;
+}
+
+// returns non-negative index if found, else -1
+static int
+arp_cache_lookup(const struct ip_addr *ip)
+{
+ int i;
+ for (i = 0; i < nentries; i++)
+ if (cache[i].ip.addr == ip->addr)
+ return i;
+
+ return -1;
+}
+
+static int
+arp_cache_alloc(void)
+{
+ if (nentries < NENTRIES)
+ return nentries++;
+
+ int i = victim;
+ victim = (victim + 1) % NENTRIES;
+ return i;
+}
+
+void
+arp_cache_update(const struct ip_addr *ip,
+ const eth_mac_addr_t *mac)
+{
+ int i = arp_cache_lookup(ip);
+ if (i < 0){
+ i = arp_cache_alloc();
+ cache[i].ip = *ip;
+ cache[i].mac = *mac;
+ }
+ else {
+ cache[i].mac = *mac;
+ }
+}
+
+bool
+arp_cache_lookup_mac(const struct ip_addr *ip,
+ eth_mac_addr_t *mac)
+{
+ int i = arp_cache_lookup(ip);
+ if (i < 0)
+ return false;
+
+ *mac = cache[i].mac;
+ return true;
+}
diff --git a/firmware/microblaze/lib/arp_cache.h b/firmware/microblaze/lib/arp_cache.h
new file mode 100644
index 000000000..8e84a1f94
--- /dev/null
+++ b/firmware/microblaze/lib/arp_cache.h
@@ -0,0 +1,33 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_ARP_CACHE_H
+#define INCLUDED_ARP_CACHE_H
+
+#include <lwip/ip_addr.h>
+#include <net/eth_mac_addr.h>
+#include <stdbool.h>
+
+void arp_cache_init(void);
+
+void arp_cache_update(const struct ip_addr *ip,
+ const eth_mac_addr_t *mac);
+
+bool arp_cache_lookup_mac(const struct ip_addr *ip,
+ eth_mac_addr_t *mac);
+
+#endif /* INCLUDED_ARP_CACHE_H */
diff --git a/firmware/microblaze/lib/banal.c b/firmware/microblaze/lib/banal.c
new file mode 100644
index 000000000..23f5f3b8a
--- /dev/null
+++ b/firmware/microblaze/lib/banal.c
@@ -0,0 +1,49 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <banal.h>
+
+uint32_t
+get_uint32(const unsigned char *s)
+{
+ return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+}
+
+uint64_t
+get_uint64(const unsigned char *s)
+{
+ return (((uint64_t)get_uint32(s)) << 32) | get_uint32(s+4);
+}
+
+uint32_t
+divide_uint64(uint64_t dividend, uint32_t divisor)
+{
+ uint32_t result = 0;
+ uint64_t dividend_ = 0;
+ for(int i = 31; i >= 0; i--){
+ //approximate the divisor with the ith result bit set
+ uint64_t tmp = dividend_;
+ tmp += (uint64_t)divisor << i;
+ //set the ith result bit if the approximation is less
+ if (tmp <= dividend){
+ dividend_ = tmp;
+ result |= 1 << i;
+ }
+ }
+ return result;
+}
diff --git a/firmware/microblaze/lib/banal.h b/firmware/microblaze/lib/banal.h
new file mode 100644
index 000000000..6d9420602
--- /dev/null
+++ b/firmware/microblaze/lib/banal.h
@@ -0,0 +1,93 @@
+/* -*- c -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_BANAL_H
+#define INCLUDED_BANAL_H
+
+#include <stdint.h>
+#include <lwip/ip_addr.h>
+
+/*
+ * 1's complement sum for IP and UDP headers
+ *
+ * init chksum to zero to start.
+ */
+static inline unsigned int
+CHKSUM(unsigned int x, unsigned int *chksum)
+{
+ *chksum += x;
+ *chksum = (*chksum & 0xffff) + (*chksum>>16);
+ *chksum = (*chksum & 0xffff) + (*chksum>>16);
+ return x;
+}
+
+unsigned int
+chksum_buffer(unsigned short *buf, int nshorts, unsigned int initial_chksum);
+
+//-------------- unsigned get_int 8, 16, 32, 64 --------------//
+
+static inline uint8_t
+get_uint8(const unsigned char *s)
+{
+ return s[0];
+}
+
+static inline uint16_t
+get_uint16(const unsigned char *s)
+{
+ return (s[0] << 8) | s[1];
+}
+
+uint32_t
+get_uint32(const unsigned char *s);
+
+uint64_t
+get_uint64(const unsigned char *s);
+
+//--------------- signed get_int 8, 16, 32, 64 --------------//
+
+static inline int8_t
+get_int8(const unsigned char *s)
+{
+ return get_uint8(s);
+}
+
+static inline int16_t
+get_int16(const unsigned char *s)
+{
+ return get_uint16(s);
+}
+
+static inline int32_t
+get_int32(const unsigned char *s)
+{
+ return get_uint32(s);
+}
+
+static inline int64_t
+get_int64(const unsigned char *s)
+{
+ return get_uint64(s);
+}
+
+void
+print_ip(struct ip_addr ip);
+
+uint32_t
+divide_uint64(uint64_t dividend, uint32_t divisor);
+
+#endif /* INCLUDED_BANAL_H */
diff --git a/firmware/microblaze/lib/bsm12.c b/firmware/microblaze/lib/bsm12.c
new file mode 100644
index 000000000..3f17fe42d
--- /dev/null
+++ b/firmware/microblaze/lib/bsm12.c
@@ -0,0 +1,319 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * buffer state machine: 1 input to two outputs
+ *
+ * Typically used to read packets from the ethernet and then after inspecting,
+ * handle the packet in firmware or pass it on to 1 of the 2 buffer destinations.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "bsm12.h"
+#include "memory_map.h"
+#include "buffer_pool.h"
+#include <stdbool.h>
+#include "nonstdio.h"
+#include <stdlib.h>
+
+typedef enum {
+ BS_EMPTY,
+ BS_FILLING,
+ BS_FULL,
+ BS_EMPTYING,
+} buffer_state_t;
+
+static buffer_state_t buffer_state[NBUFFERS];
+static uint32_t last_send_ctrl[NBUFFERS];
+static int8_t buffer_target[NBUFFERS]; // -1, 0 or 1.
+static uint8_t buffer_dst[NBUFFERS]; // 0 or 1. Valid only when BF_EMPTYING
+
+#define ST_IDLE (-1)
+
+void
+bsm12_init(bsm12_t *sm, int buf0,
+ const buf_cmd_args_t *recv,
+ const buf_cmd_args_t *send0,
+ const buf_cmd_args_t *send1,
+ bsm12_inspector_t inspect)
+{
+ if (buf0 & 0x3) // precondition: buf0 % 4 == 0
+ abort();
+
+ sm->buf0 = buf0;
+ sm->running = false;
+ sm->recv_args = *recv;
+ sm->send_args[0] = *send0;
+ sm->send_args[1] = *send1;
+
+ sm->rx_state = ST_IDLE;
+ sm->tx_state[0] = ST_IDLE;
+ sm->tx_state[1] = ST_IDLE;
+
+ sm->inspect = inspect;
+
+ sm->bps_error = BPS_ERROR(buf0 + 0) | BPS_ERROR(buf0 + 1) | BPS_ERROR(buf0 + 2);
+ sm->bps_done = BPS_DONE(buf0 + 0) | BPS_DONE(buf0 + 1) | BPS_DONE(buf0 + 2);
+ sm->bps_error_or_done = sm->bps_error | sm->bps_done;
+
+ // How much to adjust the last_line register.
+ // It's 1 for everything but the ethernet.
+ sm->last_line_adj = recv->port == PORT_ETH ? 3 : 1;
+
+ buffer_state[sm->buf0 + 0] = BS_EMPTY;
+ buffer_state[sm->buf0 + 1] = BS_EMPTY;
+ buffer_state[sm->buf0 + 2] = BS_EMPTY;
+
+ buffer_target[sm->buf0 + 0] = -1;
+ buffer_target[sm->buf0 + 1] = -1;
+ buffer_target[sm->buf0 + 2] = -1;
+
+ for (int i = 0; i < NBUFFERS; i++)
+ sm->next_buf[i] = buf0;
+
+ sm->next_buf[buf0 + 0] = buf0 + 1;
+ sm->next_buf[buf0 + 1] = buf0 + 2;
+ sm->next_buf[buf0 + 2] = buf0 + 0;
+
+ for (int i = 0; i < 3; i++){
+ sm->precomputed_receive_to_buf_ctrl_word[i] =
+ (BPC_READ
+ | BPC_BUFFER(sm->buf0 + i)
+ | BPC_PORT(sm->recv_args.port)
+ | BPC_STEP(1)
+ | BPC_FIRST_LINE(sm->recv_args.first_line)
+ | BPC_LAST_LINE(sm->recv_args.last_line));
+
+ for (int j = 0; j < 2; j++){
+ sm->precomputed_send_from_buf_ctrl_word[i][j] =
+ (BPC_WRITE
+ | BPC_BUFFER(sm->buf0 + i)
+ | BPC_PORT(sm->send_args[j].port)
+ | BPC_STEP(1)
+ | BPC_FIRST_LINE(sm->send_args[j].first_line)
+ | BPC_LAST_LINE(0)); // last line filled in at runtime
+ }
+ }
+}
+
+static inline void
+bsm12_receive_to_buf(bsm12_t *sm, int bufno)
+{
+ buffer_pool_ctrl->ctrl = sm->precomputed_receive_to_buf_ctrl_word[bufno & 0x3];
+}
+
+static inline void
+bsm12_send_from_buf(bsm12_t *sm, int bufno, int dst_idx)
+{
+ dst_idx &= 0x1;
+
+ uint32_t t =
+ (sm->precomputed_send_from_buf_ctrl_word[bufno & 0x3][dst_idx]
+ | BPC_LAST_LINE(buffer_pool_status->last_line[bufno] - sm->last_line_adj));
+
+ buffer_pool_ctrl->ctrl = t;
+ last_send_ctrl[bufno] = t;
+ buffer_dst[bufno] = dst_idx;
+}
+
+static inline void
+bsm12_resend_from_buf(bsm12_t *sm, int bufno)
+{
+ buffer_pool_ctrl->ctrl = last_send_ctrl[bufno];
+}
+
+void
+bsm12_start(bsm12_t *sm)
+{
+ sm->running = true;
+
+ buffer_state[sm->buf0 + 0] = BS_EMPTY;
+ buffer_state[sm->buf0 + 1] = BS_EMPTY;
+ buffer_state[sm->buf0 + 2] = BS_EMPTY;
+
+ buffer_target[sm->buf0 + 0] = -1;
+ buffer_target[sm->buf0 + 1] = -1;
+ buffer_target[sm->buf0 + 2] = -1;
+
+ bp_clear_buf(sm->buf0 + 0);
+ bp_clear_buf(sm->buf0 + 1);
+ bp_clear_buf(sm->buf0 + 2);
+
+ sm->rx_state = 0;
+ sm->tx_state[0] = ST_IDLE;
+ sm->tx_state[1] = ST_IDLE;
+ bsm12_receive_to_buf(sm, sm->buf0);
+ buffer_state[sm->buf0] = BS_FILLING;
+}
+
+void
+bsm12_stop(bsm12_t *sm)
+{
+ sm->running = false;
+ bp_clear_buf(sm->buf0 + 0);
+ bp_clear_buf(sm->buf0 + 1);
+ bp_clear_buf(sm->buf0 + 2);
+ buffer_state[sm->buf0 + 0] = BS_EMPTY;
+ buffer_state[sm->buf0 + 1] = BS_EMPTY;
+ buffer_state[sm->buf0 + 2] = BS_EMPTY;
+}
+
+static void bsm12_process_helper(bsm12_t *sm, int buf_this);
+static void bsm12_error_helper(bsm12_t *sm, int buf_this);
+
+void
+bsm12_process_status(bsm12_t *sm, uint32_t status)
+{
+ // anything for us?
+ if ((status & sm->bps_error_or_done) == 0 || !sm->running)
+ return;
+
+ if (status & sm->bps_error){
+ // Most likely an ethernet Rx error. We just restart the transfer.
+ if (status & (BPS_ERROR(sm->buf0 + 0)))
+ bsm12_error_helper(sm, sm->buf0 + 0);
+
+ if (status & (BPS_ERROR(sm->buf0 + 1)))
+ bsm12_error_helper(sm, sm->buf0 + 1);
+
+ if (status & (BPS_ERROR(sm->buf0 + 2)))
+ bsm12_error_helper(sm, sm->buf0 + 2);
+ }
+
+ if (status & BPS_DONE(sm->buf0 + 0))
+ bsm12_process_helper(sm, sm->buf0 + 0);
+
+ if (status & BPS_DONE(sm->buf0 + 1))
+ bsm12_process_helper(sm, sm->buf0 + 1);
+
+ if (status & BPS_DONE(sm->buf0 + 2))
+ bsm12_process_helper(sm, sm->buf0 + 2);
+}
+
+ static void
+bsm12_process_helper(bsm12_t *sm, int buf_this)
+{
+ bp_clear_buf(buf_this);
+
+ if (buffer_state[buf_this] == BS_FILLING){
+
+ buffer_state[buf_this] = BS_FULL;
+ buffer_target[buf_this] = -1;
+
+ //
+ // where does this packet go?
+ //
+ int dst = sm->inspect(sm, buf_this);
+ if (dst == -1){
+ //
+ // f/w handled the packet; refill the buffer
+ //
+ bsm12_receive_to_buf(sm, buf_this);
+ buffer_state[buf_this] = BS_FILLING;
+ buffer_target[buf_this] = -1;
+ sm->rx_state = buf_this & 0x3;
+ }
+ else { // goes to dst 0 or 1
+ //
+ // If the next buffer is empty, start a receive on it
+ //
+ int t = sm->next_buf[buf_this];
+ if (buffer_state[t] == BS_EMPTY){
+ bsm12_receive_to_buf(sm, t);
+ buffer_state[t] = BS_FILLING;
+ buffer_target[t] = -1;
+ sm->rx_state = t & 0x3;
+ }
+ else
+ sm->rx_state = ST_IDLE;
+
+ //
+ // If the destination is idle, start the xfer, othewise remember it
+ //
+ if (sm->tx_state[dst] == ST_IDLE){
+ bsm12_send_from_buf(sm, buf_this, dst);
+ sm->tx_state[dst] = buf_this & 0x3;
+ buffer_state[buf_this] = BS_EMPTYING;
+ buffer_target[buf_this] = -1;
+ }
+ else {
+ buffer_target[buf_this] = dst;
+ }
+ }
+ }
+
+ else { // BS_EMPTYING
+
+ buffer_state[buf_this] = BS_EMPTY;
+ buffer_target[buf_this] = -1;
+
+ if (sm->rx_state == ST_IDLE){ // fire off another receive
+ sm->rx_state = buf_this & 0x3;
+ bsm12_receive_to_buf(sm, buf_this);
+ buffer_state[buf_this] = BS_FILLING;
+ buffer_target[buf_this] = -1;
+ }
+
+ int dst = buffer_dst[buf_this]; // the dst we were emptying into
+ // is the next buffer full and for us?
+ int t = sm->next_buf[buf_this];
+ if (buffer_target[t] == dst){ // yes,
+ bsm12_send_from_buf(sm, t, dst); // send it
+ buffer_state[t] = BS_EMPTYING;
+ buffer_target[t] = -1;
+ sm->tx_state[dst] = t & 0x3;
+ }
+ // how about the one after that?
+ else if (buffer_target[t=sm->next_buf[t]] == dst){ // yes,
+ bsm12_send_from_buf(sm, t, dst); // send it
+ buffer_state[t] = BS_EMPTYING;
+ buffer_target[t] = -1;
+ sm->tx_state[dst] = t & 0x3;
+ }
+ else {
+ sm->tx_state[dst] = ST_IDLE;
+ }
+ }
+}
+
+static void
+bsm12_error_helper(bsm12_t *sm, int buf_this)
+{
+ bp_clear_buf(buf_this); // clears ERROR flag
+
+ if (buffer_state[buf_this] == BS_FILLING){
+ bsm12_receive_to_buf(sm, buf_this); // restart the xfer
+ }
+ else { // buffer was emptying
+ bsm12_resend_from_buf(sm, buf_this); // restart the xfer
+ }
+}
+
+
+void
+bsm12_handle_tx_underrun(bsm12_t *sm)
+{
+}
+
+void
+bsm12_handle_rx_overrun(bsm12_t *sm)
+{
+}
diff --git a/firmware/microblaze/lib/bsm12.h b/firmware/microblaze/lib/bsm12.h
new file mode 100644
index 000000000..b8e576b79
--- /dev/null
+++ b/firmware/microblaze/lib/bsm12.h
@@ -0,0 +1,83 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_BSM12_H
+#define INCLUDED_BSM12_H
+
+#include "dbsm.h"
+#include "memory_map.h"
+
+/*!
+ * buffer state machine: 1 input to two outputs
+ *
+ * Typically used to read packets from the ethernet and then after inspecting,
+ * handle the packet in firmware or pass it on to 1 of the 2 buffer destinations.
+ */
+
+struct _bsm12;
+typedef struct _bsm12 bsm12_t;
+
+/*!
+ * Pointer to function that does packet inspection.
+ *
+ * \param sm the state machine
+ * \param buf_this the index of the buffer to inspect and/or pass on
+ *
+ * Returns -1, 0 or 1. If it returns -1, it means that the s/w
+ * handled that packet, and that it should NOT be passed on to one of
+ * the buffer endpoints. 0 indicates the first endpoint, 1 the second endpoint.
+ */
+typedef int (*bsm12_inspector_t)(bsm12_t *sm, int buf_this);
+
+
+/*!
+ * buffer state machine: 1 input to two outputs
+ */
+struct _bsm12
+{
+ uint8_t buf0; // This machine uses buf0, buf0+1 and buf0+2. buf0 % 4 == 0.
+ uint8_t running;
+ int8_t rx_state; // -1, 0, 1, 2 which buffer we're receiving into
+ int8_t tx_state[2]; // -1, 0, 1, 2 which buffer we're sending from
+ buf_cmd_args_t recv_args;
+ buf_cmd_args_t send_args[2];
+ bsm12_inspector_t inspect;
+ int last_line_adj;
+ uint32_t bps_error;
+ uint32_t bps_done;
+ uint32_t bps_error_or_done;
+ uint8_t next_buf[NBUFFERS];
+ uint32_t precomputed_receive_to_buf_ctrl_word[3];
+ uint32_t precomputed_send_from_buf_ctrl_word[4][2]; // really only 3, not 4
+ // (easier addr comp)
+};
+
+void bsm12_init(bsm12_t *sm, int buf0,
+ const buf_cmd_args_t *recv,
+ const buf_cmd_args_t *send0,
+ const buf_cmd_args_t *send1,
+ bsm12_inspector_t inspect);
+
+void bsm12_start(bsm12_t *sm);
+void bsm12_stop(bsm12_t *sm);
+void bsm12_process_status(bsm12_t *sm, uint32_t status);
+void bsm12_handle_tx_underrun(bsm12_t *sm);
+void bsm12_handle_rx_overrun(bsm12_t *sm);
+
+
+#endif /* INCLUDED_BSM12_H */
diff --git a/firmware/microblaze/lib/buffer_pool.c b/firmware/microblaze/lib/buffer_pool.c
new file mode 100644
index 000000000..77e7c5213
--- /dev/null
+++ b/firmware/microblaze/lib/buffer_pool.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "memory_map.h"
+#include "buffer_pool.h"
+#include "hal_io.h"
+
+void
+bp_init(void)
+{
+ int i;
+ bp_disable_port(PORT_SERDES);
+ bp_disable_port(PORT_DSP);
+ bp_disable_port(PORT_ETH);
+ bp_disable_port(PORT_RAM);
+
+ for (i = 0; i < NBUFFERS; i++)
+ bp_clear_buf(i);
+}
+
+#ifndef INLINE_BUFFER_POOL
+
+void
+bp_clear_buf(int bufnum)
+{
+ buffer_pool_ctrl->ctrl = BPC_BUFFER(bufnum) | BPC_PORT_NIL | BPC_CLR;
+}
+
+void
+bp_disable_port(int portnum)
+{
+ // disable buffer connections to this port
+ buffer_pool_ctrl->ctrl = BPC_BUFFER_NIL | BPC_PORT(portnum);
+}
+
+void
+bp_receive_to_buf(int bufnum, int port, int step, int fl, int ll)
+{
+ buffer_pool_ctrl->ctrl = (BPC_READ
+ | BPC_BUFFER(bufnum)
+ | BPC_PORT(port)
+ | BPC_STEP(step)
+ | BPC_FIRST_LINE(fl)
+ | BPC_LAST_LINE(ll));
+}
+
+void
+bp_send_from_buf(int bufnum, int port, int step, int fl, int ll)
+{
+ buffer_pool_ctrl->ctrl = (BPC_WRITE
+ | BPC_BUFFER(bufnum)
+ | BPC_PORT(port)
+ | BPC_STEP(step)
+ | BPC_FIRST_LINE(fl)
+ | BPC_LAST_LINE(ll));
+}
+
+#endif
diff --git a/firmware/microblaze/lib/buffer_pool.h b/firmware/microblaze/lib/buffer_pool.h
new file mode 100644
index 000000000..145b20f8d
--- /dev/null
+++ b/firmware/microblaze/lib/buffer_pool.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_BUFFER_POOL_H
+#define INCLUDED_BUFFER_POOL_H
+
+#include "memory_map.h"
+
+// Buffer Pool Management
+
+
+// define to have common buffer operations inlined
+#define INLINE_BUFFER_POOL 1
+
+void bp_init(void);
+
+#ifndef INLINE_BUFFER_POOL
+
+void bp_clear_buf(int bufnum);
+void bp_disable_port(int portnum);
+void bp_receive_to_buf(int bufnum, int port, int step, int fl, int ll);
+void bp_send_from_buf(int bufnum, int port, int step, int fl, int ll);
+
+#else
+
+static inline void
+bp_clear_buf(int bufnum)
+{
+ buffer_pool_ctrl->ctrl = BPC_BUFFER(bufnum) | BPC_PORT_NIL | BPC_CLR;
+}
+
+static inline void
+bp_disable_port(int portnum)
+{
+ // disable buffer connections to this port
+ buffer_pool_ctrl->ctrl = BPC_BUFFER_NIL | BPC_PORT(portnum);
+}
+
+static inline void
+bp_receive_to_buf(int bufnum, int port, int step, int fl, int ll)
+{
+ buffer_pool_ctrl->ctrl = (BPC_READ
+ | BPC_BUFFER(bufnum)
+ | BPC_PORT(port)
+ | BPC_STEP(step)
+ | BPC_FIRST_LINE(fl)
+ | BPC_LAST_LINE(ll));
+}
+
+static inline void
+bp_send_from_buf(int bufnum, int port, int step, int fl, int ll)
+{
+ buffer_pool_ctrl->ctrl = (BPC_WRITE
+ | BPC_BUFFER(bufnum)
+ | BPC_PORT(port)
+ | BPC_STEP(step)
+ | BPC_FIRST_LINE(fl)
+ | BPC_LAST_LINE(ll));
+}
+#endif
+#endif
diff --git a/firmware/microblaze/lib/clocks.c b/firmware/microblaze/lib/clocks.c
new file mode 100644
index 000000000..d9d4fcd3c
--- /dev/null
+++ b/firmware/microblaze/lib/clocks.c
@@ -0,0 +1,239 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <clocks.h>
+
+#include "memory_map.h"
+#include "ad9510.h"
+#include "spi.h"
+#include "u2_init.h"
+#include "nonstdio.h"
+
+void
+clocks_init(void)
+{
+ // Set up basic clocking functions in AD9510
+ ad9510_write_reg(0x45, 0x00); // CLK2 drives distribution
+
+ clocks_enable_fpga_clk(true, 1);
+
+ spi_wait();
+
+ // Set up PLL for 10 MHz reference
+ // Reg 4, A counter, Don't Care
+ ad9510_write_reg(0x05, 0x00); // Reg 5, B counter MSBs, 0
+ ad9510_write_reg(0x06, 0x05); // Reg 6, B counter LSBs, 5
+ // Reg 7, Loss of reference detect, doesn't work yet, 0
+ ad9510_write_reg(0x5A, 0x01); // Update Regs
+
+ // Primary clock configuration
+ clocks_mimo_config(MC_WE_DONT_LOCK);
+
+ // Set up other clocks
+ clocks_enable_test_clk(false, 0);
+ clocks_enable_tx_dboard(false, 0);
+ clocks_enable_rx_dboard(false, 0);
+ clocks_enable_eth_phyclk(false, 0);
+
+ // Enable clock to ADCs and DACs
+ clocks_enable_dac_clk(true, 1);
+ clocks_enable_adc_clk(true, 1);
+}
+
+
+void
+clocks_mimo_config(int flags)
+{
+ if (flags & _MC_WE_LOCK){
+ // Reg 8, Charge pump on, dig lock det, positive PFD, 47
+ ad9510_write_reg(0x08, 0x47);
+ }
+ else {
+ // Reg 8, Charge pump off, dig lock det, positive PFD
+ ad9510_write_reg(0x08, 0x00);
+ }
+
+ // Reg 9, Charge pump current, 0x40=3mA, 0x00=650uA
+ ad9510_write_reg(0x09, 0x00);
+ // Reg A, Prescaler of 2, everything normal 04
+ ad9510_write_reg(0x0A, 0x04);
+ // Reg B, R Div MSBs, 0
+ ad9510_write_reg(0x0B, 0x00);
+ // Reg C, R Div LSBs, 1
+ ad9510_write_reg(0x0C, 0x01);
+ // Reg D, Antibacklash, Digital lock det, 0
+
+ ad9510_write_reg(0x5A, 0x01); // Update Regs
+
+ spi_wait();
+
+ // Allow for clock switchover
+
+ if (flags & _MC_WE_LOCK){ // WE LOCK
+ if (flags & _MC_MIMO_CLK_INPUT) {
+ // Turn on ref output and choose the MIMO connector
+ output_regs->clk_ctrl = 0x15;
+ }
+ else {
+ // turn on ref output and choose the SMA
+ output_regs->clk_ctrl = 0x1C;
+ }
+ }
+ else { // WE DONT LOCK
+ // Disable both ext clk inputs
+ output_regs->clk_ctrl = 0x10;
+ }
+
+ // Do we drive a clock onto the MIMO connector?
+ if (flags & MC_PROVIDE_CLK_TO_MIMO)
+ clocks_enable_clkexp_out(true,10);
+ else
+ clocks_enable_clkexp_out(false,0);
+}
+
+bool
+clocks_lock_detect()
+{
+ if(pic_regs->pending & PIC_CLKSTATUS)
+ return true;
+ return false;
+}
+
+int inline
+clocks_gen_div(int divisor)
+{
+ int L,H;
+ L = (divisor>>1)-1;
+ H = divisor-L-2;
+ return (L<<4)|H;
+}
+
+#define CLOCK_OUT_EN 0x08
+#define CLOCK_OUT_DIS_CMOS 0x01
+#define CLOCK_OUT_DIS_PECL 0x02
+#define CLOCK_DIV_DIS 0x80
+#define CLOCK_DIV_EN 0x00
+
+#define CLOCK_MODE_PECL 1
+#define CLOCK_MODE_LVDS 2
+#define CLOCK_MODE_CMOS 3
+
+void
+clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mode)
+{
+ int enable_word, div_word, div_en_word;
+
+ switch(mode) {
+ case CLOCK_MODE_PECL :
+ enable_word = enable ? 0x08 : 0x0A;
+ break;
+ case CLOCK_MODE_LVDS :
+ enable_word = enable ? 0x02 : 0x03;
+ break;
+ case CLOCK_MODE_CMOS :
+ enable_word = enable ? 0x08 : 0x09;
+ break;
+ }
+ if(enable && (divisor>1)) {
+ div_word = clocks_gen_div(divisor);
+ div_en_word = CLOCK_DIV_EN;
+ }
+ else {
+ div_word = 0;
+ div_en_word = CLOCK_DIV_DIS;
+ }
+
+ ad9510_write_reg(reg_en,enable_word); // Output en/dis
+ ad9510_write_reg(reg_div,div_word); // Set divisor
+ ad9510_write_reg(reg_div+1,div_en_word); // Enable or Bypass Divider
+ ad9510_write_reg(0x5A, 0x01); // Update Regs
+}
+
+// Clock 0
+void
+clocks_enable_test_clk(bool enable, int divisor)
+{
+ clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL);
+}
+
+// Clock 1
+void
+clocks_enable_fpga_clk(bool enable, int divisor)
+{
+ clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL);
+}
+
+// Clock 2 on Rev 3, Clock 5 on Rev 4
+void
+clocks_enable_clkexp_out(bool enable, int divisor)
+{
+ if(u2_hw_rev_major == 3)
+ clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL);
+ else if(u2_hw_rev_major == 4) {
+ ad9510_write_reg(0x34,0x00); // Turn on fine delay
+ ad9510_write_reg(0x35,0x00); // Set Full Scale to nearly 10ns
+ ad9510_write_reg(0x36,0x1c); // Set fine delay. 0x20 is midscale
+ clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS);
+
+ }
+ else
+ putstr("ERR: Invalid Rev\n");
+}
+
+// Clock 5 on Rev 3, none (was 2) on Rev 4
+void
+clocks_enable_eth_phyclk(bool enable, int divisor)
+{
+ if(u2_hw_rev_major == 3)
+ clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS);
+ else if(u2_hw_rev_major == 4)
+ clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL);
+ else
+ putstr("ERR: Invalid Rev\n");
+}
+
+// Clock 3
+void
+clocks_enable_dac_clk(bool enable, int divisor)
+{
+ clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL);
+}
+
+// Clock 4
+void
+clocks_enable_adc_clk(bool enable, int divisor)
+{
+ clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS);
+}
+
+// Clock 6
+void
+clocks_enable_tx_dboard(bool enable, int divisor)
+{
+ clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS);
+}
+
+// Clock 7
+void
+clocks_enable_rx_dboard(bool enable, int divisor)
+{
+ clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS);
+}
diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h
new file mode 100644
index 000000000..141fc61e0
--- /dev/null
+++ b/firmware/microblaze/lib/clocks.h
@@ -0,0 +1,95 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_CLOCKS_H
+#define INCLUDED_CLOCKS_H
+
+/*
+ * Routines to configure our multitude of clocks
+ */
+
+#include <stdbool.h>
+#include <usrp2_clock_bits.h>
+
+
+/*!
+ * One time call to initialize all clocks to a reasonable state. We
+ * come out of here using our free running 100MHz oscilator and not
+ * providing a clock to the MIMO connector (CMC_WE_DONT_LOCK)
+ */
+void clocks_init(void);
+
+
+/*!
+ * \brief MIMO clock configuration.
+ *
+ * Configure our master clock source, and whether or not we drive a
+ * clock onto the mimo connector. See MC_flags in usrp2_mimo_config.h.
+ */
+void clocks_mimo_config(int flags);
+
+/*!
+ * \brief Lock Detect -- Return True if our PLL is locked
+ */
+bool clocks_lock_detect();
+
+/*!
+ * \brief Enable or disable test clock (extra clock signal)
+ */
+void clocks_enable_test_clk(bool enable, int divisor);
+
+/*!
+ * \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle.
+ */
+void clocks_enable_fpga_clk(bool enable, int divisor);
+
+/*!
+ * \brief Enable or disable clock output sent to MIMO connector
+ */
+void clocks_enable_clkexp_out(bool enable, int divisor);
+
+/*!
+ * \brief Enable or disable ethernet phyclk, should always be disabled
+ */
+void clocks_enable_eth_phyclk(bool enable, int divisor);
+
+/*!
+ * \brief Enable or disable clock to DAC
+ */
+void clocks_enable_dac_clk(bool enable, int divisor);
+
+/*!
+ * \brief Enable or disable clock to ADC
+ */
+void clocks_enable_adc_clk(bool enable, int divisor);
+
+/*!
+ * \brief Enable or disable clock to Rx daughterboard
+ */
+void clocks_enable_rx_dboard(bool enable, int divisor);
+
+
+/*!
+ * \brief Enable or disable clock to Tx daughterboard
+ */
+void clocks_enable_tx_dboard(bool enable, int divisor);
+
+
+#endif /* INCLUDED_CLOCKS_H */
diff --git a/firmware/microblaze/lib/dbsm.c b/firmware/microblaze/lib/dbsm.c
new file mode 100644
index 000000000..9d66ec39c
--- /dev/null
+++ b/firmware/microblaze/lib/dbsm.c
@@ -0,0 +1,297 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Double Buffering State Machine
+ */
+
+#include "dbsm.h"
+#include "memory_map.h"
+#include "buffer_pool.h"
+#include <stdbool.h>
+#include "nonstdio.h"
+#include <stdlib.h>
+
+typedef enum {
+ BS_EMPTY,
+ BS_FILLING,
+ BS_FULL,
+ BS_EMPTYING,
+} buffer_state_t;
+
+static buffer_state_t buffer_state[NBUFFERS];
+
+bool
+dbsm_nop_inspector(dbsm_t *sm, int buf_this)
+{
+ return false;
+}
+
+void
+dbsm_init(dbsm_t *sm, int buf0,
+ const buf_cmd_args_t *recv, const buf_cmd_args_t *send,
+ inspector_t inspect)
+{
+ if (buf0 & 0x1) // must be even
+ abort();
+
+ sm->buf0 = buf0;
+ sm->running = false;
+ sm->recv_args = *recv;
+ sm->send_args = *send;
+
+ sm->rx_idle = true;
+ sm->tx_idle = true;
+
+ sm->inspect = inspect;
+
+ // How much to adjust the last_line register.
+ // It's 1 for everything but the ethernet.
+ //sm->last_line_adj = recv->port == PORT_ETH ? 3 : 1;
+ sm->last_line_adj = 1;
+
+ buffer_state[sm->buf0] = BS_EMPTY;
+ buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
+
+ sm->precomputed_receive_to_buf_ctrl_word[0] =
+ (BPC_READ
+ | BPC_BUFFER(sm->buf0)
+ | BPC_PORT(sm->recv_args.port)
+ | BPC_STEP(1)
+ | BPC_FIRST_LINE(sm->recv_args.first_line)
+ | BPC_LAST_LINE(sm->recv_args.last_line));
+
+ sm->precomputed_receive_to_buf_ctrl_word[1] =
+ (BPC_READ
+ | BPC_BUFFER(sm->buf0 ^ 1)
+ | BPC_PORT(sm->recv_args.port)
+ | BPC_STEP(1)
+ | BPC_FIRST_LINE(sm->recv_args.first_line)
+ | BPC_LAST_LINE(sm->recv_args.last_line));
+
+ sm->precomputed_send_from_buf_ctrl_word[0] =
+ (BPC_WRITE
+ | BPC_BUFFER(sm->buf0)
+ | BPC_PORT(sm->send_args.port)
+ | BPC_STEP(1)
+ | BPC_FIRST_LINE(sm->send_args.first_line)
+ | BPC_LAST_LINE(0)); // last line filled in at runtime
+
+ sm->precomputed_send_from_buf_ctrl_word[1] =
+ (BPC_WRITE
+ | BPC_BUFFER(sm->buf0 ^ 1)
+ | BPC_PORT(sm->send_args.port)
+ | BPC_STEP(1)
+ | BPC_FIRST_LINE(sm->send_args.first_line)
+ | BPC_LAST_LINE(0)); // last line filled in at runtime
+
+}
+
+static inline void
+dbsm_receive_to_buf(dbsm_t *sm, int bufno)
+{
+ buffer_pool_ctrl->ctrl = sm->precomputed_receive_to_buf_ctrl_word[bufno & 1];
+}
+
+static inline void
+dbsm_send_from_buf(dbsm_t *sm, int bufno)
+{
+ buffer_pool_ctrl->ctrl =
+ (sm->precomputed_send_from_buf_ctrl_word[bufno & 1]
+ | BPC_LAST_LINE(buffer_pool_status->last_line[bufno] - sm->last_line_adj));
+}
+
+void
+dbsm_start(dbsm_t *sm)
+{
+ // printf("dbsm_start: buf0 = %d, recv_port = %d\n", sm->buf0, sm->recv_args.port);
+
+ sm->running = true;
+
+ buffer_state[sm->buf0] = BS_EMPTY;
+ buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
+
+ bp_clear_buf(sm->buf0);
+ bp_clear_buf(sm->buf0 ^ 1);
+
+ sm->tx_idle = true;
+ sm->rx_idle = false;
+ dbsm_receive_to_buf(sm, sm->buf0);
+ buffer_state[sm->buf0] = BS_FILLING;
+
+}
+
+
+void
+dbsm_stop(dbsm_t *sm)
+{
+ sm->running = false;
+ bp_clear_buf(sm->buf0);
+ bp_clear_buf(sm->buf0 ^ 1);
+ buffer_state[sm->buf0] = BS_EMPTY;
+ buffer_state[sm->buf0 ^ 1] = BS_EMPTY;
+}
+
+static void dbsm_process_helper(dbsm_t *sm, int buf_this);
+static void dbsm_error_helper(dbsm_t *sm, int buf_this);
+
+void
+dbsm_process_status(dbsm_t *sm, uint32_t status)
+{
+ if (!sm->running)
+ return;
+
+ if (status & (BPS_ERROR(sm->buf0) | BPS_ERROR(sm->buf0 ^ 1))){
+ putchar('E');
+ // Most likely an ethernet Rx error. We just restart the transfer.
+ if (status & (BPS_ERROR(sm->buf0)))
+ dbsm_error_helper(sm, sm->buf0);
+
+ if (status & (BPS_ERROR(sm->buf0 ^ 1)))
+ dbsm_error_helper(sm, sm->buf0 ^ 1);
+ }
+
+ if (status & BPS_DONE(sm->buf0))
+ dbsm_process_helper(sm, sm->buf0);
+
+ if (status & BPS_DONE(sm->buf0 ^ 1))
+ dbsm_process_helper(sm, sm->buf0 ^ 1);
+}
+
+static void
+dbsm_process_helper(dbsm_t *sm, int buf_this)
+{
+ int buf_other = buf_this ^ 1;
+
+ bp_clear_buf(buf_this);
+
+ if (buffer_state[buf_this] == BS_FILLING){
+ buffer_state[buf_this] = BS_FULL;
+ //
+ // does s/w handle this packet?
+ //
+ if (sm->inspect(sm, buf_this)){
+ // s/w handled the packet; refill the buffer
+ dbsm_receive_to_buf(sm, buf_this);
+ buffer_state[buf_this] = BS_FILLING;
+ }
+
+ else { // s/w didn't handle this; pass it on
+
+ if(buffer_state[buf_other] == BS_EMPTY){
+ dbsm_receive_to_buf(sm, buf_other);
+ buffer_state[buf_other] = BS_FILLING;
+ }
+ else
+ sm->rx_idle = true;
+
+ if (sm->tx_idle){
+ sm->tx_idle = false;
+ dbsm_send_from_buf(sm, buf_this);
+ buffer_state[buf_this] = BS_EMPTYING;
+ }
+ }
+ }
+ else { // buffer was emptying
+ buffer_state[buf_this] = BS_EMPTY;
+ if (sm->rx_idle){
+ sm->rx_idle = false;
+ dbsm_receive_to_buf(sm, buf_this);
+ buffer_state[buf_this] = BS_FILLING;
+ }
+ if (buffer_state[buf_other] == BS_FULL){
+ dbsm_send_from_buf(sm, buf_other);
+ buffer_state[buf_other] = BS_EMPTYING;
+ }
+ else
+ sm->tx_idle = true;
+ }
+}
+
+static void
+dbsm_error_helper(dbsm_t *sm, int buf_this)
+{
+ bp_clear_buf(buf_this); // clears ERROR flag
+
+ if (buffer_state[buf_this] == BS_FILLING){
+ dbsm_receive_to_buf(sm, buf_this); // restart the xfer
+ }
+ else { // buffer was emptying
+ dbsm_send_from_buf(sm, buf_this); // restart the xfer
+ }
+}
+
+/*
+ * Handle DSP Tx underrun
+ */
+void
+dbsm_handle_tx_underrun(dbsm_t *sm)
+{
+ // clear the DSP Tx state machine
+ sr_tx_ctrl->clear_state = 1;
+
+ // If there's a buffer that's empyting, clear it & flush xfer
+
+ if (buffer_state[sm->buf0] == BS_EMPTYING){
+ bp_clear_buf(sm->buf0);
+ sr_tx_ctrl->clear_state = 1; // flush partial packet
+ // drop frame in progress on ground. Pretend it finished
+ dbsm_process_helper(sm, sm->buf0);
+ }
+ else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){
+ bp_clear_buf(sm->buf0 ^ 1);
+ sr_tx_ctrl->clear_state = 1; // flush partial packet
+ // drop frame in progress on ground. Pretend it finished
+ dbsm_process_helper(sm, sm->buf0 ^ 1);
+ }
+}
+
+/*
+ * Handle DSP Rx overrun
+ */
+void
+dbsm_handle_rx_overrun(dbsm_t *sm)
+{
+ sr_rx_ctrl->clear_overrun = 1;
+
+ // If there's a buffer that's filling, clear it.
+ // Any restart will be the job of the caller.
+
+ if (buffer_state[sm->buf0] == BS_FILLING)
+ bp_clear_buf(sm->buf0);
+
+ if (buffer_state[sm->buf0 ^1] == BS_FILLING)
+ bp_clear_buf(sm->buf0 ^ 1);
+}
+
+void
+dbsm_wait_for_opening(dbsm_t *sm)
+{
+ if (buffer_state[sm->buf0] == BS_EMPTYING){
+ // wait for xfer to complete
+ int mask = BPS_DONE(sm->buf0) | BPS_ERROR(sm->buf0) | BPS_IDLE(sm->buf0);
+ while ((buffer_pool_status->status & mask) == 0)
+ ;
+ }
+ else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){
+ // wait for xfer to complete
+ int mask = BPS_DONE(sm->buf0 ^ 1) | BPS_ERROR(sm->buf0 ^ 1) | BPS_IDLE(sm->buf0 ^ 1);
+ while ((buffer_pool_status->status & mask) == 0)
+ ;
+ }
+}
diff --git a/firmware/microblaze/lib/dbsm.h b/firmware/microblaze/lib/dbsm.h
new file mode 100644
index 000000000..cb7e12fc3
--- /dev/null
+++ b/firmware/microblaze/lib/dbsm.h
@@ -0,0 +1,90 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_DBSM_H
+#define INCLUDED_DBSM_H
+
+/*
+ * Double Buffering State Machine
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct _dbsm;
+typedef struct _dbsm dbsm_t;
+
+/*
+ * pointer to function that does packet inspection.
+ *
+ * If one of these returns true, it means that the s/w
+ * handled that packet, and that it should NOT be passed
+ * on to the normal destination port.
+ */
+typedef bool (*inspector_t)(dbsm_t *sm, int buf_this);
+
+bool dbsm_nop_inspector(dbsm_t *sm, int buf_this); // returns false
+
+
+typedef struct
+{
+ uint16_t port;
+ uint16_t first_line;
+ uint16_t last_line;
+} buf_cmd_args_t;
+
+/*!
+ * double buffer state machine
+ */
+struct _dbsm
+{
+ uint8_t buf0; // Must be even. This machine uses buf0 and buf0+1
+ uint8_t running;
+ uint8_t rx_idle;
+ uint8_t tx_idle;
+ buf_cmd_args_t recv_args;
+ buf_cmd_args_t send_args;
+ inspector_t inspect;
+ uint32_t precomputed_receive_to_buf_ctrl_word[2];
+ uint32_t precomputed_send_from_buf_ctrl_word[2];
+ int last_line_adj;
+};
+
+void dbsm_init(dbsm_t *sm, int buf0,
+ const buf_cmd_args_t *recv, const buf_cmd_args_t *send,
+ inspector_t inspect);
+
+void dbsm_start(dbsm_t *sm);
+void dbsm_stop(dbsm_t *sm);
+void dbsm_process_status(dbsm_t *sm, uint32_t status);
+void dbsm_handle_tx_underrun(dbsm_t *sm);
+void dbsm_handle_rx_overrun(dbsm_t *sm);
+
+/*
+ * The cpu calls this when it want to ensure that it can send a buffer
+ * to the same destination being used by this state machine.
+ *
+ * If neither buffer is EMPTYING it returns immediately. If a buffer
+ * is EMPYTING, it waits for the h/w to transition to the DONE or
+ * ERROR state.
+ *
+ * When this function returns, the caller queues it's buffer and busy
+ * waits for it to complete.
+ */
+void dbsm_wait_for_opening(dbsm_t *sm);
+
+#endif /* INCLUDED_DBSM_H */
diff --git a/firmware/microblaze/lib/eeprom.c b/firmware/microblaze/lib/eeprom.c
new file mode 100644
index 000000000..b12ffe082
--- /dev/null
+++ b/firmware/microblaze/lib/eeprom.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "i2c.h"
+#include "mdelay.h"
+
+static const int EEPROM_PAGESIZE = 16;
+
+bool
+eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len)
+{
+ unsigned char cmd[2];
+ const unsigned char *p = (unsigned char *) buf;
+
+ // The simplest thing that could possibly work:
+ // all writes are single byte writes.
+ //
+ // We could speed this up using the page write feature,
+ // but we write so infrequently, why bother...
+
+ while (len-- > 0){
+ cmd[0] = eeprom_offset++;
+ cmd[1] = *p++;
+ bool r = i2c_write (i2c_addr, cmd, sizeof (cmd));
+ mdelay (10); // delay 10ms worst case write time
+ if (!r)
+ return false;
+ }
+ return true;
+}
+
+bool
+eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len)
+{
+ unsigned char *p = (unsigned char *) buf;
+
+ // We setup a random read by first doing a "zero byte write".
+ // Writes carry an address. Reads use an implicit address.
+
+ unsigned char cmd[1];
+ cmd[0] = eeprom_offset;
+ if (!i2c_write (i2c_addr, cmd, sizeof (cmd)))
+ return false;
+
+ while (len > 0){
+ // int n = std::min (len, MAX_EP0_PKTSIZE);
+ int n = len;
+ if (!i2c_read (i2c_addr, p, n))
+ return false;
+ len -= n;
+ p += n;
+ }
+ return true;
+}
+
diff --git a/firmware/microblaze/lib/eth_mac.c b/firmware/microblaze/lib/eth_mac.c
new file mode 100644
index 000000000..375d3f4d4
--- /dev/null
+++ b/firmware/microblaze/lib/eth_mac.c
@@ -0,0 +1,127 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "eth_mac.h"
+#include "memory_map.h"
+#include <stdbool.h>
+#include "eth_phy.h" // for simulation constants
+#include "mdelay.h"
+#include "stdio.h"
+
+#define PHY_ADDR 1
+
+void
+eth_mac_set_addr(const eth_mac_addr_t *src)
+{
+ eth_mac->ucast_hi =
+ (((unsigned int)src->addr[0])<<8) +
+ ((unsigned int)src->addr[1]);
+ eth_mac->ucast_lo =
+ (((unsigned int)src->addr[2])<<24) +
+ (((unsigned int)src->addr[3])<<16) +
+ (((unsigned int)src->addr[4])<<8) +
+ (((unsigned int)src->addr[5]));
+}
+
+
+void
+eth_mac_init(const eth_mac_addr_t *src)
+{
+ eth_mac->miimoder = 25; // divider from CPU clock (50MHz/25 = 2MHz)
+
+ eth_mac_set_addr(src);
+ eth_mac->settings = MAC_SET_PAUSE_EN | MAC_SET_PASS_BCAST | MAC_SET_PASS_UCAST | MAC_SET_PAUSE_SEND_EN;
+
+ eth_mac->pause_time = 38;
+ eth_mac->pause_thresh = 1200;
+
+ // set rx flow control high and low water marks
+ // unsigned int lwmark = (2*2048 + 64)/4; // 2 * 2048-byte frames + 1 * 64-byte pause frame
+ // eth_mac->fc_hwmark = lwmark + 2048/4; // plus a 2048-byte frame
+
+ // eth_mac->fc_lwmark = 600; // there are currently 2047 lines in the fifo
+ // eth_mac->fc_hwmark = 1200;
+ //eth_mac->fc_padtime = 1700; // how long before flow control runs out do we
+ // request a re-pause. Units of 8ns (bytes)
+
+ //eth_mac->tx_pause_en = 0; // pay attn to pause frames sent to us
+ //eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge
+ //eth_mac->pause_frame_send_en = 0; // enable sending pause frames
+}
+
+int
+eth_mac_read_rmon(int addr)
+{
+ int t = 0;
+ /*
+ eth_mac->rmon_rd_addr = addr;
+ eth_mac->rmon_rd_apply = 1;
+ while(eth_mac->rmon_rd_grant == 0)
+ ;
+
+ t = eth_mac->rmon_rd_dout;
+ eth_mac->rmon_rd_apply = 0;
+ */
+ return t;
+}
+
+int
+eth_mac_miim_read(int addr)
+{
+ if (hwconfig_simulation_p()){
+ switch(addr){
+ case PHY_LINK_AN:
+ return LANSR_MASTER | LANSR_LINK_GOOD | LANSR_SPEED_1000;
+ default:
+ return 0;
+ }
+ }
+
+ int phy_addr = PHY_ADDR;
+ eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr;
+ eth_mac->miicommand = MIIC_RSTAT;
+
+ while((eth_mac->miistatus & MIIS_BUSY) != 0)
+ ;
+
+ int r = eth_mac->miirx_data;
+ //printf("MIIM-READ ADDR 0x%x DATA 0x%x\n",addr, r);
+ return r;
+}
+
+void
+eth_mac_miim_write(int addr, int value)
+{
+ int phy_addr = PHY_ADDR;
+ eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr;
+ eth_mac->miitx_data = value;
+ eth_mac->miicommand = MIIC_WCTRLDATA;
+
+ //printf("MIIM-WRITE ADDR 0x%x VAL 0x%x\n",addr,value);
+ while((eth_mac->miistatus & MIIS_BUSY) != 0)
+ ;
+}
+
+int
+eth_mac_miim_read_status(void)
+{
+ if (hwconfig_simulation_p())
+ return 0;
+
+ return eth_mac->miistatus;
+}
diff --git a/firmware/microblaze/lib/eth_mac.h b/firmware/microblaze/lib/eth_mac.h
new file mode 100644
index 000000000..73feec955
--- /dev/null
+++ b/firmware/microblaze/lib/eth_mac.h
@@ -0,0 +1,32 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_ETH_MAC_H
+#define INCLUDED_ETH_MAC_H
+
+#include <net/eth_mac_addr.h>
+
+void eth_mac_init(const eth_mac_addr_t *src);
+
+void eth_mac_set_addr(const eth_mac_addr_t *src);
+int eth_mac_read_rmon(int addr);
+int eth_mac_miim_read(int addr);
+void eth_mac_miim_write(int addr, int value);
+int eth_mac_miim_read_status(void);
+
+#endif /* INCLUDED_ETH_MAC_H */
diff --git a/firmware/microblaze/lib/eth_mac_regs.h b/firmware/microblaze/lib/eth_mac_regs.h
new file mode 100644
index 000000000..d680f8de0
--- /dev/null
+++ b/firmware/microblaze/lib/eth_mac_regs.h
@@ -0,0 +1,62 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_ETH_MAC_REGS_H
+#define INCLUDED_ETH_MAC_REGS_H
+
+/*
+ * Simple GEMAC
+ *
+ */
+typedef struct {
+ volatile int settings;
+ volatile int ucast_hi;
+ volatile int ucast_lo;
+ volatile int mcast_hi;
+ volatile int mcast_lo;
+ volatile int miimoder;
+ volatile int miiaddress;
+ volatile int miitx_data;
+ volatile int miicommand;
+ volatile int miistatus;
+ volatile int miirx_data;
+ volatile int pause_time;
+ volatile int pause_thresh;
+} eth_mac_regs_t;
+
+// settings register
+#define MAC_SET_PAUSE_EN (1 << 0) // Makes us respect received pause frames (normally on)
+#define MAC_SET_PASS_ALL (1 << 1) // Enables promiscuous mode, currently broken
+#define MAC_SET_PASS_PAUSE (1 << 2) // Sends pause frames through (normally off)
+#define MAC_SET_PASS_BCAST (1 << 3) // Sends broadcast frames through (normally on)
+#define MAC_SET_PASS_MCAST (1 << 4) // Sends multicast frames that match mcast addr (normally off)
+#define MAC_SET_PASS_UCAST (1 << 5) // Sends unicast (normal) frames through if they hit in address filter (normally on)
+#define MAC_SET_PAUSE_SEND_EN (1 << 6) // Enables sending pause frames
+
+// miicommand register
+#define MIIC_SCANSSTAT (1 << 0) // Scan status
+#define MIIC_RSTAT (1 << 1) // Read status
+#define MIIC_WCTRLDATA (1 << 2) // Write control data
+
+// miistatus register
+#define MIIS_LINKFAIL (1 << 0) // The link failed
+#define MIIS_BUSY (1 << 1) // The MII is busy (operation in progress)
+#define MIIS_NVALID (1 << 2) // The data in the status register is invalid
+ // This it is only valid when the scan status is active.
+
+#endif /* INCLUDED_ETH_MAC_REGS_H */
diff --git a/firmware/microblaze/lib/eth_phy.h b/firmware/microblaze/lib/eth_phy.h
new file mode 100644
index 000000000..6c16f97b7
--- /dev/null
+++ b/firmware/microblaze/lib/eth_phy.h
@@ -0,0 +1,219 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Much of this was extracted from the Linux e1000_hw.h file */
+
+#ifndef INCLUDED_ETH_PHY_H
+#define INCLUDED_ETH_PHY_H
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+
+#define PHY_CTRL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+/* PHY 1000 MII Register additions in DP83856 */
+/* The part implements 0x00 thru 0x1f; we use these. */
+
+#define PHY_LINK_AN 0x11 /* Link and Auto Negotiation Status Reg */
+#define PHY_INT_STATUS 0x14 /* Interupt Status Reg (RO) */
+#define PHY_INT_MASK 0x15 /* Interrupt Mask Reg (RW) */
+#define PHY_INT_CLEAR 0x17 /* Interrupt Clear Reg (RW) */
+
+
+/* Bit definitions for some of the registers above */
+
+/* PHY Control Register (PHY_CTRL) */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register (PHY_STATUS) */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register (PHY_AUTONEG_ADV) */
+#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) (PHY_LP_ABILITY) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register (PHY_AUTONEG_EXP) */
+#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register (PHY_NEXT_PAGE_TX) */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* Link Partner Next Page Register (PHY_LP_NEXT_PAGE) */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* 1000BASE-T Control Register (PHY_1000T_CTRL) */
+#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register (PHY_1000T_STATUS) */
+#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_20 20
+#define FFE_IDLE_ERR_COUNT_TIMEOUT_100 100
+
+/* Extended Status Register (PHY_EXT_STATUS) */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */
+ /* (0=enable, 1=disable) */
+
+/* Link and Auto Negotiation Status Reg (PHY_LINK_AN) [READ-ONLY] */
+#define LANSR_MASTER 0x0001 /* 1=PHY is currently in master mode */
+#define LANSR_FULL_DUPLEX 0x0002 /* 1=PHY is currently full duplex */
+#define LANSR_LINK_GOOD 0x0004 /* 1=a good link is established */
+#define LANSR_SPEED_MASK 0x0018
+#define LANSR_SPEED_10 0x0000 /* 10Mb/s */
+#define LANSR_SPEED_100 0x0008 /* 100Mb/s */
+#define LANSR_SPEED_1000 0x0010 /* 1000Mb/s */
+#define LANSR_SPEED_RSRVD 0x0018 /* reserved */
+#define LANSR_NON_COMP_MODE 0x0020 /* 1=detects only in non-compliant mode */
+#define LANSR_DEEP_LOOPBACK 0x0040 /* 1=the PHY operates in deep loopback mode */
+#define LANSR_SHALLOW_LOOPBACK 0x0080 /* 1=the PHY operates in shallow loopback mode */
+#define LANSR_RSRVD_8 0x0100 /* reserved */
+#define LANSR_FIFO_ERR 0x0200 /* 1=FIFO error occurred */
+#define LANSR_MDIX_XOVER 0x0400 /* 1=PHY's MDI is in cross-over mode */
+#define LANSR_RSRVD_11 0x0800 /* resevered */
+#define LANSR_TP_POLARITY_REV 0xf000 /* Twisted pair polarity status A:D([15:12]) 1=reversed */
+
+/* Interrupt status, mask and clear regs (PHY_INT_{STATUS,MASK,CLEAR}) */
+#define PHY_INT_RSRVD_0 0x0001 /* reserved */
+#define PHY_INT_RSRVD_1 0x0002 /* reserved */
+#define PHY_INT_RSRVD_2 0x0004 /* reserved */
+#define PHY_INT_REM_FLT_CNG 0x0008 /* Remote Fault Changed */
+#define PHY_INT_AN_CMPL 0x0010 /* Auto-negotiation completion */
+#define PHY_INT_NXT_PG_RCVD 0x0020 /* Next Page Received */
+#define PHY_INT_JABBER_CNG 0x0040 /* Jabber Changed */
+#define PHY_INT_NO_LINK 0x0080 /* No link after auto-negotiation */
+#define PHY_INT_NO_HCD 0x0100 /* AN couldn't determine highest common denominator */
+#define PHY_INT_MAS_SLA_ERR 0x0200 /* Master / Slave Error: couldn't resolve */
+#define PHY_INT_PRL_DET_FLT 0x0400 /* Parallel detection fault */
+#define PHY_INT_POL_CNG 0x0800 /* Polarity of any channel changed */
+#define PHY_INT_MDIX_CNG 0x1000 /* MDIX changed. A pair swap occurred. */
+#define PHY_INT_DPLX_CNG 0x2000 /* Duplex changed */
+#define PHY_INT_LNK_CNG 0x4000 /* Link changed (asserted when a link is established or broken) */
+#define PHY_INT_SPD_CNG 0x8000 /* Speed changed */
+
+#endif /* INCLUDED_ETH_PHY_H */
diff --git a/firmware/microblaze/lib/ethernet.c b/firmware/microblaze/lib/ethernet.c
new file mode 100644
index 000000000..34a3ad7c1
--- /dev/null
+++ b/firmware/microblaze/lib/ethernet.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ethernet.h"
+#include "memory_map.h"
+#include "eth_phy.h"
+#include "eth_mac.h"
+#include "eth_mac_regs.h"
+#include "pic.h"
+#include "hal_io.h"
+#include "nonstdio.h"
+#include <stdbool.h>
+#include "i2c.h"
+#include "usrp2_i2c_addr.h"
+
+
+#define VERBOSE 0
+
+static ethernet_t ed_state;
+static ethernet_link_changed_callback_t ed_callback = 0;
+
+void
+ethernet_register_link_changed_callback(ethernet_link_changed_callback_t new_callback)
+{
+ ed_callback = new_callback;
+}
+
+
+static void
+ed_set_mac_speed(int speed)
+{
+ printf("Speed set to %d\n",speed);
+ /*
+ switch(speed){
+ case 10:
+ eth_mac->speed = 1;
+ break;
+ case 100:
+ eth_mac->speed = 2;
+ break;
+ case 1000:
+ eth_mac->speed = 4;
+ break;
+ default:
+ break;
+ }
+ */
+}
+
+static void
+ed_link_up(int speed)
+{
+ // putstr("ed_link_up: "); puthex16_nl(speed);
+
+ ed_set_mac_speed(speed);
+
+ if (ed_callback) // fire link changed callback
+ (*ed_callback)(speed);
+}
+
+static void
+ed_link_down(void)
+{
+ // putstr("ed_link_down\n");
+
+ if (ed_callback) // fire link changed callback
+ (*ed_callback)(0);
+}
+
+
+static void
+ed_link_speed_change(int speed)
+{
+ ed_link_down();
+ ed_link_up(speed);
+}
+
+static void
+print_flow_control(int flow_control)
+{
+ static const char *flow_control_msg[4] = {
+ "NONE", "WE_TX", "WE_RX", "SYMMETRIC"
+ };
+ putstr("ethernet flow control: ");
+ puts(flow_control_msg[flow_control & 0x3]);
+}
+
+static void
+check_flow_control_resolution(void)
+{
+ static const unsigned char table[16] = {
+ // index = {local_asm, local_pause, partner_asm, partner_pause}
+ FC_NONE, FC_NONE, FC_NONE, FC_NONE,
+ FC_NONE, FC_SYMM, FC_NONE, FC_SYMM,
+ FC_NONE, FC_NONE, FC_NONE, FC_WE_TX,
+ FC_NONE, FC_SYMM, FC_WE_RX, FC_SYMM
+ };
+
+ int us = eth_mac_miim_read(PHY_AUTONEG_ADV);
+ int lp = eth_mac_miim_read(PHY_LP_ABILITY);
+ int index = (((us >> 10) & 0x3) << 2) | ((lp >> 10) & 0x3);
+ ed_state.flow_control = table[index];
+
+ if (1)
+ print_flow_control(ed_state.flow_control);
+}
+
+/*
+ * Read the PHY state register to determine link state and speed
+ */
+static void
+ed_check_phy_state(void)
+{
+ int lansr = eth_mac_miim_read(PHY_LINK_AN);
+ eth_link_state_t new_state = LS_UNKNOWN;
+ int new_speed = S_UNKNOWN;
+
+ if (VERBOSE){
+ putstr("LANSR: ");
+ puthex16_nl(lansr);
+ }
+
+ if (lansr & LANSR_LINK_GOOD){ // link's up
+ if (VERBOSE)
+ puts(" LINK_GOOD");
+
+ new_state = LS_UP;
+ switch (lansr & LANSR_SPEED_MASK){
+ case LANSR_SPEED_10:
+ new_speed = 10;
+ break;
+
+ case LANSR_SPEED_100:
+ new_speed = 100;
+ break;
+
+ case LANSR_SPEED_1000:
+ new_speed = 1000;
+ break;
+
+ default:
+ new_speed = S_UNKNOWN;
+ break;
+ }
+
+ check_flow_control_resolution();
+ }
+ else { // link's down
+ if (VERBOSE)
+ puts(" NOT LINK_GOOD");
+
+ new_state = LS_DOWN;
+ new_speed = S_UNKNOWN;
+ }
+
+ if (new_state != ed_state.link_state){
+ ed_state.link_state = new_state; // remember new state
+ if (new_state == LS_UP)
+ ed_link_up(new_speed);
+ else if (new_state == LS_DOWN)
+ ed_link_down();
+ }
+ else if (new_state == LS_UP && new_speed != ed_state.link_speed){
+ ed_state.link_speed = new_speed; // remember new speed
+ ed_link_speed_change(new_speed);
+ }
+}
+
+/*
+ * This is fired when the ethernet PHY state changes
+ */
+static void
+eth_phy_irq_handler(unsigned irq)
+{
+ ed_check_phy_state();
+ eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all ints
+}
+
+void
+ethernet_init(void)
+{
+ eth_mac_init(ethernet_mac_addr());
+
+ ed_state.link_state = LS_UNKNOWN;
+ ed_state.link_speed = S_UNKNOWN;
+
+ // initialize MAC registers
+ // eth_mac->tx_hwmark = 0x1e;
+ //eth_mac->tx_lwmark = 0x19;
+
+ //eth_mac->crc_chk_en = 1;
+ //eth_mac->rx_max_length = 2048;
+
+ // configure PAUSE frame stuff
+ //eth_mac->tx_pause_en = 1; // pay attn to pause frames sent to us
+
+ //eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge
+ //eth_mac->pause_frame_send_en = 1; // enable sending pause frames
+
+
+ // setup PHY to interrupt on changes
+
+ unsigned mask =
+ (PHY_INT_AN_CMPL // auto-neg completed
+ | PHY_INT_NO_LINK // no link after auto-neg
+ | PHY_INT_NO_HCD // no highest common denominator
+ | PHY_INT_MAS_SLA_ERR // couldn't resolve master/slave
+ | PHY_INT_PRL_DET_FLT // parallel detection fault
+ | PHY_INT_LNK_CNG // link established or broken
+ | PHY_INT_SPD_CNG // speed changed
+ );
+
+ eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all pending interrupts
+ eth_mac_miim_write(PHY_INT_MASK, mask); // enable the ones we want
+
+ pic_register_handler(IRQ_PHY, eth_phy_irq_handler);
+
+ // Advertise our flow control configuation.
+ //
+ // We and the link partner each specify two bits in the base page
+ // related to autoconfiguration: NWAY_AR_PAUSE and NWAY_AR_ASM_DIR.
+ // The bits say what a device is "willing" to do, not what may actually
+ // happen as a result of the negotiation. There are 4 cases:
+ //
+ // PAUSE ASM_DIR
+ //
+ // 0 0 I have no flow control capability.
+ //
+ // 1 0 I both assert and respond to flow control.
+ //
+ // 0 1 I assert flow control, but cannot respond. That is,
+ // I want to be able to send PAUSE frames, but will ignore any
+ // you send to me. (This is our configuration.)
+ //
+ // 1 1 I can both assert and respond to flow control AND I am willing
+ // to operate symmetrically OR asymmetrically in EITHER direction.
+ // (We hope the link partner advertises this, otherwise we don't
+ // get what we want.)
+
+ int t = eth_mac_miim_read(PHY_AUTONEG_ADV);
+ t &= ~(NWAY_AR_PAUSE | NWAY_AR_ASM_DIR);
+ t |= NWAY_AR_ASM_DIR;
+
+ // Say we can't to 10BASE-T or 100BASE-TX, half or full duplex
+ t &= ~(NWAY_AR_10T_HD_CAPS | NWAY_AR_10T_FD_CAPS | NWAY_AR_100TX_HD_CAPS | NWAY_AR_100TX_FD_CAPS);
+
+ eth_mac_miim_write(PHY_AUTONEG_ADV, t);
+ int r = eth_mac_miim_read(PHY_AUTONEG_ADV); // DEBUG, read back
+ if (t != r){
+ printf("PHY_AUTONEG_ADV: wrote 0x%x, got 0x%x\n", t, r);
+ }
+
+ // Restart autonegotation.
+ // We want to ensure that we're advertising our PAUSE capabilities.
+ t = eth_mac_miim_read(PHY_CTRL);
+ eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG);
+}
+
+static bool
+unprogrammed(const void *t, size_t len)
+{
+ int i;
+ uint8_t *p = (uint8_t *)t;
+ bool all_zeros = true;
+ bool all_ones = true;
+ for (i = 0; i < len; i++){
+ all_zeros &= p[i] == 0x00;
+ all_ones &= p[i] == 0xff;
+ }
+ return all_ones | all_zeros;
+}
+
+//////////////////// MAC Addr Stuff ///////////////////////
+
+static int8_t src_mac_addr_initialized = false;
+static eth_mac_addr_t src_mac_addr = {{
+ 0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff
+ }};
+
+const eth_mac_addr_t *
+ethernet_mac_addr(void)
+{
+ if (!src_mac_addr_initialized){ // fetch from eeprom
+ src_mac_addr_initialized = true;
+
+ // if we're simulating, don't read the EEPROM model, it's REALLY slow
+ if (hwconfig_simulation_p())
+ return &src_mac_addr;
+
+ eth_mac_addr_t tmp;
+ bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp, sizeof(tmp));
+ if (!ok || unprogrammed(&tmp, sizeof(tmp))){
+ // use the default
+ }
+ else
+ src_mac_addr = tmp;
+ }
+
+ return &src_mac_addr;
+}
+
+bool
+ethernet_set_mac_addr(const eth_mac_addr_t *t)
+{
+ bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t));
+ if (ok){
+ src_mac_addr = *t;
+ src_mac_addr_initialized = true;
+ //eth_mac_set_addr(t); //this breaks the link
+ }
+
+ return ok;
+}
+
+//////////////////// IP Addr Stuff ///////////////////////
+
+static int8_t src_ip_addr_initialized = false;
+static struct ip_addr src_ip_addr = {
+ (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0)
+};
+
+
+const struct ip_addr *get_ip_addr(void)
+{
+ if (!src_ip_addr_initialized){ // fetch from eeprom
+ src_ip_addr_initialized = true;
+
+ // if we're simulating, don't read the EEPROM model, it's REALLY slow
+ if (hwconfig_simulation_p())
+ return &src_ip_addr;
+
+ struct ip_addr tmp;
+ bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, &tmp, sizeof(tmp));
+ if (!ok || unprogrammed(&tmp, sizeof(tmp))){
+ // use the default
+ }
+ else
+ src_ip_addr = tmp;
+ }
+
+ return &src_ip_addr;
+}
+
+bool set_ip_addr(const struct ip_addr *t){
+ bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, t, sizeof(struct ip_addr));
+ if (ok){
+ src_ip_addr = *t;
+ src_ip_addr_initialized = true;
+ }
+
+ return ok;
+}
+
+int
+ethernet_check_errors(void)
+{
+ // these registers are reset when read
+
+ int r = 0;
+ /*
+ if (eth_mac_read_rmon(0x05) != 0)
+ r |= RME_RX_CRC;
+ if (eth_mac_read_rmon(0x06) != 0)
+ r |= RME_RX_FIFO_FULL;
+ if (eth_mac_read_rmon(0x07) != 0)
+ r |= RME_RX_2SHORT_2LONG;
+
+ if (eth_mac_read_rmon(0x25) != 0)
+ r |= RME_TX_JAM_DROP;
+ if (eth_mac_read_rmon(0x26) != 0)
+ r |= RME_TX_FIFO_UNDER;
+ if (eth_mac_read_rmon(0x27) != 0)
+ r |= RME_TX_FIFO_OVER;
+ */
+ return r;
+}
diff --git a/firmware/microblaze/lib/ethernet.h b/firmware/microblaze/lib/ethernet.h
new file mode 100644
index 000000000..8c6d8b567
--- /dev/null
+++ b/firmware/microblaze/lib/ethernet.h
@@ -0,0 +1,93 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_ETHERNET_H
+#define INCLUDED_ETHERNET_H
+
+#include <net/eth_mac_addr.h>
+#include <lwip/ip_addr.h>
+#include <stdbool.h>
+
+typedef void (*ethernet_link_changed_callback_t)(int speed);
+
+
+/*!
+ * \brief one time call to initialize ethernet
+ */
+void ethernet_init(void);
+
+/*!
+ * \brief Specify the function to call on link state changes.
+ *
+ * When the link comes up, speed is the link speed in Mbit/s.
+ * When the link goes down, speed is 0.
+ */
+void ethernet_register_link_changed_callback(ethernet_link_changed_callback_t cb);
+
+/*!
+ * \returns ethernet MAC address
+ */
+const eth_mac_addr_t *ethernet_mac_addr(void);
+
+/*!
+ * \brief write mac address to eeprom and begin using it
+ */
+bool ethernet_set_mac_addr(const eth_mac_addr_t *t);
+
+/*!
+ * \returns IP address
+ */
+const struct ip_addr *get_ip_addr(void);
+
+/*!
+ * \brief write ip address to eeprom and begin using it
+ */
+bool set_ip_addr(const struct ip_addr *t);
+
+
+/*
+ * \brief read RMON regs and return error mask
+ */
+int ethernet_check_errors(void);
+
+#define RME_RX_CRC 0x0001
+#define RME_RX_FIFO_FULL 0x0002
+#define RME_RX_2SHORT_2LONG 0x0004
+
+#define RME_TX_JAM_DROP 0x0010
+#define RME_TX_FIFO_UNDER 0x0020
+#define RME_TX_FIFO_OVER 0x0040
+
+
+typedef enum { LS_UNKNOWN, LS_DOWN, LS_UP } eth_link_state_t;
+
+// flow control bitmasks
+#define FC_NONE 0x0
+#define FC_WE_TX 0x1 // we send PAUSE frames
+#define FC_WE_RX 0x2 // we honor received PAUSE frames
+#define FC_SYMM (FC_WE_TX | FC_WE_RX)
+
+#define S_UNKNOWN (-1) // unknown link speed
+
+typedef struct {
+ eth_link_state_t link_state;
+ int link_speed; // in Mb/s
+ int flow_control;
+} ethernet_t;
+
+#endif /* INCLUDED_ETHERNET_H */
diff --git a/firmware/microblaze/lib/ethertype.h b/firmware/microblaze/lib/ethertype.h
new file mode 100644
index 000000000..11f4bafec
--- /dev/null
+++ b/firmware/microblaze/lib/ethertype.h
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_ETHERTYPE_H
+#define INCLUDED_ETHERTYPE_H
+
+// all we care about
+
+#define ETHERTYPE_IPV4 0x0800
+#define ETHERTYPE_ARP 0x0806
+
+
+#endif /* INCLUDED_ETHERTYPE_H */
diff --git a/firmware/microblaze/lib/exit.c b/firmware/microblaze/lib/exit.c
new file mode 100644
index 000000000..95a3bf4de
--- /dev/null
+++ b/firmware/microblaze/lib/exit.c
@@ -0,0 +1,28 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+extern void _exit(int status);
+
+void
+exit(int status)
+{
+ _exit(status);
+}
diff --git a/firmware/microblaze/lib/hal_io.c b/firmware/microblaze/lib/hal_io.c
new file mode 100644
index 000000000..fdfa15000
--- /dev/null
+++ b/firmware/microblaze/lib/hal_io.c
@@ -0,0 +1,323 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// conditionalized on HAL_IO_USES_DBOARD_PINS && HAL_IO_USES_UART
+
+#include "hal_io.h"
+#include "memory_map.h"
+#include "hal_uart.h"
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+//#include <assert.h>
+
+/*
+ * ========================================================================
+ * GPIOS
+ * ========================================================================
+ */
+void
+hal_gpio_set_ddr(int bank, int value, int mask)
+{
+ bank &= 0x1;
+
+ if (bank == GPIO_TX_BANK){ // tx in top half
+ value <<= 16;
+ mask <<= 16;
+ }
+ else {
+ value &= 0xffff;
+ mask &= 0xffff;
+ }
+
+ int ei = hal_disable_ints();
+ gpio_base->ddr = (gpio_base->ddr & ~mask) | (value & mask);
+ hal_restore_ints(ei);
+}
+
+static bool
+code_to_int(char code, int *val)
+{
+ switch(code){
+ case 's': *val = GPIO_SEL_SW; return true;
+ case 'a': *val = GPIO_SEL_ATR; return true;
+ case '0': *val = GPIO_SEL_DEBUG_0; return true;
+ case '1': *val = GPIO_SEL_DEBUG_1; return true;
+ case '.':
+ default:
+ return false;
+ }
+}
+
+void
+hal_gpio_set_sel(int bank, int bitno, char code)
+{
+ bank &= 0x1;
+ int t;
+
+ if (!code_to_int(code, &t))
+ return;
+
+ int val = t << (2 * bitno);
+ int mask = 0x3 << (2 * bitno);
+
+ volatile uint32_t *sel = bank == GPIO_TX_BANK ? &gpio_base->tx_sel : &gpio_base->rx_sel;
+ int ei = hal_disable_ints();
+ int v = (*sel & ~mask) | (val & mask);
+ *sel = v;
+ hal_restore_ints(ei);
+
+ if (0)
+ printf("hal_gpio_set_sel(bank=%d, bitno=%d, code=%c) *sel = 0x%x\n",
+ bank, bitno, code, v);
+}
+
+void
+hal_gpio_set_sels(int bank, char *codes)
+{
+ //assert(strlen(codes) == 16);
+
+ int val = 0;
+ int mask = 0;
+ int i;
+
+ for (i = 15; i >= 0; i--){
+ val <<= 2;
+ mask <<= 2;
+ int t;
+ if (code_to_int(codes[i], &t)){
+ val |= t;
+ mask |= 0x3;
+ }
+ }
+
+ volatile uint32_t *sel = bank == GPIO_TX_BANK ? &gpio_base->tx_sel : &gpio_base->rx_sel;
+ int ei = hal_disable_ints();
+ *sel = (*sel & ~mask) | (val & mask);
+ hal_restore_ints(ei);
+}
+
+
+/*!
+ * \brief write \p value to gpio pins specified by \p mask.
+ */
+void
+hal_gpio_write(int bank, int value, int mask)
+{
+ static uint32_t _gpio_io_shadow;
+
+ bank &= 0x1;
+
+ if (bank == GPIO_TX_BANK){ // tx in top half
+ value <<= 16;
+ mask <<= 16;
+ }
+ else {
+ value &= 0xffff;
+ mask &= 0xffff;
+ }
+
+ //int ei = hal_disable_ints();
+ _gpio_io_shadow = (_gpio_io_shadow & ~mask) | (value & mask);
+ gpio_base->io = _gpio_io_shadow;
+ //hal_restore_ints(ei);
+}
+
+
+/*!
+ * \brief read GPIO bits
+ */
+int
+hal_gpio_read(int bank)
+{
+ bank &= 0x1;
+ int r = gpio_base->io;
+ if (bank == GPIO_TX_BANK)
+ r >>= 16;
+
+ return r & 0xffff;
+}
+
+/*
+ * ========================================================================
+ * leds
+ * ========================================================================
+ */
+
+static unsigned long leds_shadow = 0;
+static unsigned long led_src_shadow = 0;
+
+void
+hal_set_leds(int value, int mask)
+{
+ int ei = hal_disable_ints();
+ leds_shadow = (leds_shadow & ~mask) | (value & mask);
+ output_regs->leds = leds_shadow;
+ hal_restore_ints(ei);
+}
+
+// Allow hardware control over leds. 1 = hardware, 0 = software
+void
+hal_set_led_src(int value, int mask)
+{
+ int ei = hal_disable_ints();
+ led_src_shadow = (led_src_shadow & ~mask) | (value & mask);
+ output_regs->led_src = led_src_shadow;
+ hal_restore_ints(ei);
+}
+
+void
+hal_toggle_leds(int mask)
+{
+ int ei = hal_disable_ints();
+ leds_shadow ^= mask;
+ output_regs->leds = leds_shadow;
+ hal_restore_ints(ei);
+}
+
+
+// ================================================================
+// primitives
+// ================================================================
+
+#if defined(HAL_IO_USES_DBOARD_PINS)
+//
+// Does i/o using high 9-bits of rx daughterboard pins.
+//
+// 1 1 1 1 1 1
+// 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | char |W| |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//
+// Asserts W when writing char
+//
+
+#define W 0x0080
+
+void
+hal_io_init(void)
+{
+ // make high 9 bits of tx daughterboard outputs
+ hal_gpio_set_rx_mode(15, 7, GPIOM_OUTPUT);
+
+ // and set them to zero
+ hal_gpio_set_rx(0x0000, 0xff80);
+}
+
+void
+hal_finish(void)
+{
+ volatile unsigned long *p = (unsigned long *) 0xC2F0;
+ *p = 0;
+}
+
+// %c
+inline int
+putchar(int ch)
+{
+ hal_gpio_set_rx((s << 8) | W, 0xff80);
+ hal_gpio_set_rx(0, 0xff80);
+ return ch;
+}
+
+#elif defined(HAL_IO_USES_UART)
+
+void
+hal_io_init(void)
+{
+ hal_uart_init();
+}
+
+void
+hal_finish(void)
+{
+}
+
+// %c
+inline int
+putchar(int ch)
+{
+ hal_uart_putc(ch);
+ return ch;
+}
+
+int
+getchar(void)
+{
+ return hal_uart_getc();
+}
+
+#else // nop all i/o
+
+void
+hal_io_init(void)
+{
+}
+
+void
+hal_finish(void)
+{
+}
+
+// %c
+inline int
+putchar(int ch)
+{
+ return ch;
+}
+
+int
+getchar(void)
+{
+ return EOF;
+}
+
+#endif
+
+// ================================================================
+// (slightly) higher level functions
+//
+// These are here so we can inline the calls to putchar.
+// The rest of the stuff was moved to nonstdio.c
+// ================================================================
+
+// \n
+inline void
+newline(void)
+{
+ putchar('\n');
+}
+
+int
+putstr(const char *s)
+{
+ while (*s)
+ putchar(*s++);
+
+ return 0;
+}
+
+int
+puts(const char *s)
+{
+ putstr(s);
+ putchar('\n');
+ return 0;
+}
diff --git a/firmware/microblaze/lib/hal_io.h b/firmware/microblaze/lib/hal_io.h
new file mode 100644
index 000000000..f8ec617f8
--- /dev/null
+++ b/firmware/microblaze/lib/hal_io.h
@@ -0,0 +1,166 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_HAL_IO_H
+#define INCLUDED_HAL_IO_H
+
+#include "memory_map.h"
+
+void hal_io_init(void);
+void hal_finish();
+
+
+/*
+ * ------------------------------------------------------------------------
+ * The GPIO pins are organized into two banks of 16-bits.
+ * Bank 0 goes to the Tx daughterboard, Bank 1 goes to the Rx daughterboard.
+ *
+ * Each pin may be configured as an input or an output from the FPGA.
+ * For output pins, there are four signals which may be routed to the
+ * pin. The four signals are the value written by s/w, the output of
+ * the ATR controller, or two different sources of debug info from the
+ * FPGA fabric.
+ * ------------------------------------------------------------------------
+ */
+
+#define GPIO_TX_BANK 0 // pins that connect to the Tx daughterboard
+#define GPIO_RX_BANK 1 // pins that connect to the Rx daughterboard
+
+
+/*!
+ * \brief Set the data direction for GPIO pins
+ *
+ * If the bit is set, it's an output from the FPGA.
+ * \param value is a 16-bit bitmask of values
+ * \param mask is a 16-bit bitmask of which bits to effect.
+ */
+void hal_gpio_set_ddr(int bank, int value, int mask);
+
+/*!
+ * \brief Select the source of the signal for an output pin.
+ *
+ * \param code is is one of 's', 'a', '0', '1'
+ * where 's' selects software output, 'a' selects ATR output, '0' selects
+ * debug 0, '1' selects debug 1.
+ */
+void hal_gpio_set_sel(int bank, int bitno, char code);
+
+/*!
+ * \brief Select the source of the signal for the output pins.
+ *
+ * \param codes is is a string of 16 characters composed of '.', 's',
+ * 'a', '0', or '1' where '.' means "don't change", 's' selects
+ * software output, 'a' selects ATR output, '0' selects debug 0, '1'
+ * selects debug 1.
+ */
+void hal_gpio_set_sels(int bank, char *codes);
+
+
+/*!
+ * \brief write \p value to gpio pins specified by \p mask.
+ */
+void hal_gpio_write(int bank, int value, int mask);
+
+/*!
+ * \brief read GPIO bits
+ */
+int hal_gpio_read(int bank);
+
+
+/*
+ * ------------------------------------------------------------------------
+ * control the leds
+ *
+ * Low 4-bits are the general purpose leds on the board
+ * The next bit is the led on the ethernet connector
+ * ------------------------------------------------------------------------
+ */
+
+void hal_set_leds(int value, int mask);
+void hal_set_led_src(int value, int mask);
+void hal_toggle_leds(int mask);
+
+/*
+ * ------------------------------------------------------------------------
+ * simple timeouts
+ * ------------------------------------------------------------------------
+ */
+
+
+
+static inline void
+hal_set_timeout(int delta_ticks)
+{
+ sr_simple_timer->onetime = delta_ticks;
+}
+
+/*
+ * ------------------------------------------------------------------------
+ * interrupt enable/disable
+ * ------------------------------------------------------------------------
+ */
+
+/*!
+ * \brief Disable interrupts and return previous interrupt enable state.
+ * [Microblaze specific]
+ */
+static inline int
+hal_disable_ints(void)
+{
+ int result, t0;
+
+ asm volatile("mfs %0, rmsr \n\
+ andni %1, %0, 0x2 \n\
+ mts rmsr, %1"
+ : "=r" (result), "=r" (t0));
+ return result;
+}
+
+/*!
+ * \brief Enable interrupts and return previous interrupt enable state.
+ * [Microblaze specific]
+ */
+static inline int
+hal_enable_ints(void)
+{
+ int result, t0;
+
+ asm volatile("mfs %0, rmsr \n\
+ ori %1, %0, 0x2 \n\
+ mts rmsr, %1"
+ : "=r" (result), "=r" (t0));
+ return result;
+}
+
+/*!
+ * \brief Set interrupt enable state to \p prev_state.
+ * [Microblaze specific]
+ */
+static inline void
+hal_restore_ints(int prev_state)
+{
+ int t0, t1;
+ asm volatile("andi %0, %2, 0x2 \n\
+ mfs %1, rmsr \n\
+ andni %1, %1, 0x2 \n\
+ or %1, %1, %0 \n\
+ mts rmsr, %1"
+ : "=r" (t0), "=r"(t1) : "r" (prev_state));
+}
+
+#endif /* INCLUDED_HAL_IO_H */
diff --git a/firmware/microblaze/lib/hal_uart.c b/firmware/microblaze/lib/hal_uart.c
new file mode 100644
index 000000000..75b12b432
--- /dev/null
+++ b/firmware/microblaze/lib/hal_uart.c
@@ -0,0 +1,77 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hal_uart.h"
+#include "hal_io.h"
+#include "memory_map.h"
+
+// First pass, no interrupts
+
+// Replaced with divisors.py which generates best divisor
+//#define CALC_DIVISOR(rate) (WISHBONE_CLK_RATE / ((rate) * 16))
+
+#define NSPEEDS 6
+#define MAX_WB_DIV 4
+
+static const uint16_t
+divisor_table[MAX_WB_DIV+1][NSPEEDS] = {
+ { 2, 2, 2, 2, 2, 2}, // 0: can't happen
+ { 651, 326, 163, 109, 54, 27 }, // 1: 100 MHz
+ { 326, 163, 81, 54, 27, 14 }, // 2: 50 MHz
+ { 217, 109, 54, 36, 18, 9 }, // 3: 33.3333 MHz
+ { 163, 81, 41, 27, 14, 7 }, // 4: 25 MHz
+};
+
+#define u uart_regs
+
+void
+hal_uart_init(void)
+{
+ u->clkdiv = 217; // 230400 bps
+}
+
+void
+hal_uart_putc(int ch)
+{
+ if (ch == '\n') // FIXME for now map \n -> \r\n
+ hal_uart_putc('\r');
+
+ while (u->txlevel == 0) // wait for fifo to have space
+ ;
+
+ u->txchar = ch;
+}
+
+void
+hal_uart_putc_nowait(int ch)
+{
+ if (ch == '\n') // FIXME for now map \n -> \r\n
+ hal_uart_putc('\r');
+
+ if(u->txlevel) // If fifo has space
+ u->txchar = ch;
+}
+
+int
+hal_uart_getc(void)
+{
+ while ((u->rxlevel) == 0) // wait for data to be ready
+ ;
+
+ return u->rxchar;
+}
diff --git a/firmware/microblaze/lib/hal_uart.h b/firmware/microblaze/lib/hal_uart.h
new file mode 100644
index 000000000..2ddfa6259
--- /dev/null
+++ b/firmware/microblaze/lib/hal_uart.h
@@ -0,0 +1,68 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_HAL_UART_H
+#define INCLUDED_HAL_UART_H
+
+
+/*!
+ * \brief one-time call to init
+ */
+void hal_uart_init(void);
+
+typedef enum {
+ US_9600,
+ US_19200,
+ US_38400,
+ US_57600,
+ US_115200,
+ US_230400,
+} hal_uart_speed_t;
+
+typedef struct {
+ hal_uart_speed_t speed;
+} hal_uart_config_t;
+
+/*!
+ * \brief Set uart parameters
+ * Default is 115,200 bps, 8N1.
+ */
+void hal_uart_set_config(const hal_uart_config_t *c);
+
+/*!
+ * \brief Get uart configuation.
+ */
+void hal_uart_get_config(hal_uart_config_t *c);
+
+/*!
+ * \brief Enqueue \p ch for output over serial port
+ */
+void hal_uart_putc(int ch);
+
+/*!
+ * \brief Enqueue \p ch for output over serial port, silent fail if queue is full
+ */
+void hal_uart_putc_nowait(int ch);
+
+/*
+ * \brief Blocking read of next char from serial port
+ */
+int hal_uart_getc(void);
+
+
+#endif /* INCLUDED_HAL_UART_H */
diff --git a/firmware/microblaze/lib/i2c.c b/firmware/microblaze/lib/i2c.c
new file mode 100644
index 000000000..3f738733b
--- /dev/null
+++ b/firmware/microblaze/lib/i2c.c
@@ -0,0 +1,127 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "i2c.h"
+#include "memory_map.h"
+#include "stdint.h"
+
+#define MAX_WB_DIV 4 // maximum wishbone divisor (from 100 MHz MASTER_CLK)
+
+// prescaler divisor values for 100 kHz I2C [uses 5 * SCLK internally]
+
+#define PRESCALER(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 100000)) - 1)
+
+static uint16_t prescaler_values[MAX_WB_DIV+1] = {
+ 0xffff, // 0: can't happen
+ PRESCALER(1), // 1: 100 MHz
+ PRESCALER(2), // 2: 50 MHz
+ PRESCALER(3), // 3: 33.333 MHz
+ PRESCALER(4), // 4: 25 MHz
+};
+
+void
+i2c_init(void)
+{
+ i2c_regs->ctrl = 0; // disable core
+
+ // setup prescaler depending on wishbone divisor
+ int wb_div = hwconfig_wishbone_divisor();
+ if (wb_div > MAX_WB_DIV)
+ wb_div = MAX_WB_DIV;
+
+ i2c_regs->prescaler_lo = prescaler_values[wb_div] & 0xff;
+ i2c_regs->prescaler_hi = (prescaler_values[wb_div] >> 8) & 0xff;
+
+ i2c_regs->ctrl = I2C_CTRL_EN; // enable core
+
+ // FIXME interrupt driven?
+}
+
+static inline void
+wait_for_xfer(void)
+{
+ while (i2c_regs->cmd_status & I2C_ST_TIP) // wait for xfer to complete
+ ;
+}
+
+static inline bool
+wait_chk_ack(void)
+{
+ wait_for_xfer();
+
+ if ((i2c_regs->cmd_status & I2C_ST_RXACK) != 0){ // target NAK'd
+ return false;
+ }
+ return true;
+}
+
+bool
+i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len)
+{
+ if (len == 0) // reading zero bytes always works
+ return true;
+
+ while (i2c_regs->cmd_status & I2C_ST_BUSY)
+ ;
+
+ i2c_regs->data = (i2c_addr << 1) | 1; // 7 bit address and read bit (1)
+ // generate START and write addr
+ i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START;
+ if (!wait_chk_ack())
+ goto fail;
+
+ for (; len > 0; buf++, len--){
+ i2c_regs->cmd_status = I2C_CMD_RD | (len == 1 ? (I2C_CMD_NACK | I2C_CMD_STOP) : 0);
+ wait_for_xfer();
+ *buf = i2c_regs->data;
+ }
+ return true;
+
+ fail:
+ i2c_regs->cmd_status = I2C_CMD_STOP; // generate STOP
+ return false;
+}
+
+
+bool
+i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len)
+{
+ while (i2c_regs->cmd_status & I2C_ST_BUSY)
+ ;
+
+ i2c_regs->data = (i2c_addr << 1) | 0; // 7 bit address and write bit (0)
+
+ // generate START and write addr (and maybe STOP)
+ i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0);
+ if (!wait_chk_ack())
+ goto fail;
+
+ for (; len > 0; buf++, len--){
+ i2c_regs->data = *buf;
+ i2c_regs->cmd_status = I2C_CMD_WR | (len == 1 ? I2C_CMD_STOP : 0);
+ if (!wait_chk_ack())
+ goto fail;
+ }
+ return true;
+
+ fail:
+ i2c_regs->cmd_status = I2C_CMD_STOP; // generate STOP
+ return false;
+}
+
+
diff --git a/firmware/microblaze/lib/i2c.h b/firmware/microblaze/lib/i2c.h
new file mode 100644
index 000000000..ecb6aa0d2
--- /dev/null
+++ b/firmware/microblaze/lib/i2c.h
@@ -0,0 +1,39 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_I2C_H
+#define INCLUDED_I2C_H
+
+#include <stdbool.h>
+
+void i2c_init(void);
+bool i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len);
+bool i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len);
+
+
+// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard.
+// Which EEPROM is determined by i2c_addr. See i2c_addr.h
+
+bool eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len);
+
+// Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard.
+// Which EEPROM is determined by i2c_addr. See i2c_addr.h
+
+bool eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len);
+
+#endif /* INCLUDED_I2C_H */
diff --git a/firmware/microblaze/lib/if_arp.h b/firmware/microblaze/lib/if_arp.h
new file mode 100644
index 000000000..63519c4be
--- /dev/null
+++ b/firmware/microblaze/lib/if_arp.h
@@ -0,0 +1,153 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the ARP (RFC 826) protocol.
+ *
+ * Version: @(#)if_arp.h 1.0.1 04/16/93
+ *
+ * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
+ * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
+ * Ross Biro
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Florian La Roche,
+ * Jonathan Layes <layes@loran.com>
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> ARPHRD_HWX25
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_ARP_H
+#define _LINUX_IF_ARP_H
+
+/* ARP protocol HARDWARE identifiers. */
+#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */
+#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */
+#define ARPHRD_EETHER 2 /* Experimental Ethernet */
+#define ARPHRD_AX25 3 /* AX.25 Level 2 */
+#define ARPHRD_PRONET 4 /* PROnet token ring */
+#define ARPHRD_CHAOS 5 /* Chaosnet */
+#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */
+#define ARPHRD_ARCNET 7 /* ARCnet */
+#define ARPHRD_APPLETLK 8 /* APPLEtalk */
+#define ARPHRD_DLCI 15 /* Frame Relay DLCI */
+#define ARPHRD_ATM 19 /* ATM */
+#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */
+#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */
+#define ARPHRD_EUI64 27 /* EUI-64 */
+#define ARPHRD_INFINIBAND 32 /* InfiniBand */
+
+/* Dummy types for non ARP hardware */
+#define ARPHRD_SLIP 256
+#define ARPHRD_CSLIP 257
+#define ARPHRD_SLIP6 258
+#define ARPHRD_CSLIP6 259
+#define ARPHRD_RSRVD 260 /* Notional KISS type */
+#define ARPHRD_ADAPT 264
+#define ARPHRD_ROSE 270
+#define ARPHRD_X25 271 /* CCITT X.25 */
+#define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */
+#define ARPHRD_CAN 280 /* Controller Area Network */
+#define ARPHRD_PPP 512
+#define ARPHRD_CISCO 513 /* Cisco HDLC */
+#define ARPHRD_HDLC ARPHRD_CISCO
+#define ARPHRD_LAPB 516 /* LAPB */
+#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */
+#define ARPHRD_RAWHDLC 518 /* Raw HDLC */
+
+#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
+#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */
+#define ARPHRD_FRAD 770 /* Frame Relay Access Device */
+#define ARPHRD_SKIP 771 /* SKIP vif */
+#define ARPHRD_LOOPBACK 772 /* Loopback device */
+#define ARPHRD_LOCALTLK 773 /* Localtalk device */
+#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */
+#define ARPHRD_BIF 775 /* AP1000 BIF */
+#define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */
+#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */
+#define ARPHRD_IPGRE 778 /* GRE over IP */
+#define ARPHRD_PIMREG 779 /* PIMSM register interface */
+#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */
+#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */
+#define ARPHRD_ECONET 782 /* Acorn Econet */
+#define ARPHRD_IRDA 783 /* Linux-IrDA */
+/* ARP works differently on different FC media .. so */
+#define ARPHRD_FCPP 784 /* Point to point fibrechannel */
+#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */
+#define ARPHRD_FCPL 786 /* Fibrechannel public loop */
+#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */
+ /* 787->799 reserved for fibrechannel media types */
+#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */
+#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */
+#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */
+#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */
+
+#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
+#define ARPHRD_NONE 0xFFFE /* zero header length */
+
+/* ARP protocol opcodes. */
+#define ARPOP_REQUEST 1 /* ARP request */
+#define ARPOP_REPLY 2 /* ARP reply */
+#define ARPOP_RREQUEST 3 /* RARP request */
+#define ARPOP_RREPLY 4 /* RARP reply */
+#define ARPOP_InREQUEST 8 /* InARP request */
+#define ARPOP_InREPLY 9 /* InARP reply */
+#define ARPOP_NAK 10 /* (ATM)ARP NAK */
+
+
+/* ARP Flag values. */
+#define ATF_COM 0x02 /* completed entry (ha valid) */
+#define ATF_PERM 0x04 /* permanent entry */
+#define ATF_PUBL 0x08 /* publish entry */
+#define ATF_USETRAILERS 0x10 /* has requested trailers */
+#define ATF_NETMASK 0x20 /* want to use a netmask (only
+ for proxy entries) */
+#define ATF_DONTPUB 0x40 /* don't answer this addresses */
+
+typedef unsigned short __be16;
+
+/*
+ * This structure defines an ethernet arp header.
+ */
+struct arphdr
+{
+ __be16 ar_hrd; /* format of hardware address */
+ __be16 ar_pro; /* format of protocol address */
+ unsigned char ar_hln; /* length of hardware address */
+ unsigned char ar_pln; /* length of protocol address */
+ __be16 ar_op; /* ARP opcode (command) */
+
+#if 0
+ /*
+ * Ethernet looks like this : This bit is variable sized however...
+ */
+ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
+ unsigned char ar_sip[4]; /* sender IP address */
+ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
+ unsigned char ar_tip[4]; /* target IP address */
+#endif
+
+};
+
+/*
+ * This structure defines an ethernet arp header.
+ */
+struct arp_eth_ipv4
+{
+ __be16 ar_hrd; /* format of hardware address */
+ __be16 ar_pro; /* format of protocol address */
+ unsigned char ar_hln; /* length of hardware address */
+ unsigned char ar_pln; /* length of protocol address */
+ __be16 ar_op; /* ARP opcode (command) */
+
+ unsigned char ar_sha[6]; /* sender hardware address */
+ unsigned char ar_sip[4]; /* sender IP address */
+ unsigned char ar_tha[6]; /* target hardware address */
+ unsigned char ar_tip[4]; /* target IP address */
+};
+
+
+#endif /* _LINUX_IF_ARP_H */
diff --git a/firmware/microblaze/lib/mdelay.c b/firmware/microblaze/lib/mdelay.c
new file mode 100644
index 000000000..c8c119b1a
--- /dev/null
+++ b/firmware/microblaze/lib/mdelay.c
@@ -0,0 +1,73 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mdelay.h"
+#include "memory_map.h"
+
+// Delay about one millisecond.
+//
+// Need 33,333 cycles at 33 MHz.
+// Each time around the loop is 10 cycles
+//
+
+#define LOOPCNT(wb_div) (MASTER_CLK_RATE/(wb_div) / 10000)
+
+inline static void
+delay_1ms(int loop_count)
+{
+ int i;
+ for (i = 0; i < loop_count; i++){
+ asm volatile ("or r0, r0, r0\n\
+ or r0, r0, r0\n\
+ or r0, r0, r0\n\
+ or r0, r0, r0\n\
+ or r0, r0, r0\n\
+ or r0, r0, r0\n\
+ or r0, r0, r0\n");
+ }
+}
+
+// delay about ms milliseconds
+void
+mdelay(int ms)
+{
+ static int loop_count = -1;
+
+ if (hwconfig_simulation_p())
+ return;
+
+ if (loop_count < 0){
+ // set correct loop_count
+ static unsigned short lc[8] = {
+ 0,
+ LOOPCNT(1),
+ LOOPCNT(2),
+ LOOPCNT(3),
+ LOOPCNT(4),
+ LOOPCNT(5),
+ LOOPCNT(6),
+ LOOPCNT(7)
+ };
+
+ loop_count = lc[hwconfig_wishbone_divisor() & 0x7];
+ }
+
+ int i;
+ for (i = 0; i < ms; i++)
+ delay_1ms(loop_count);
+}
diff --git a/firmware/microblaze/lib/mdelay.h b/firmware/microblaze/lib/mdelay.h
new file mode 100644
index 000000000..226bbb3f7
--- /dev/null
+++ b/firmware/microblaze/lib/mdelay.h
@@ -0,0 +1,29 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_MDELAY_H
+#define INCLUDED_MDELAY_H
+
+/*!
+ * \brief Delay about ms milliseconds
+ *
+ * If simulating, _very_ short delay
+ */
+void mdelay(int ms);
+
+#endif /* INCLUDED_MDELAY_H */
diff --git a/firmware/microblaze/lib/memcpy_wa.c b/firmware/microblaze/lib/memcpy_wa.c
new file mode 100644
index 000000000..ef20efaa9
--- /dev/null
+++ b/firmware/microblaze/lib/memcpy_wa.c
@@ -0,0 +1,42 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "memcpy_wa.h"
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * For copying to/from non-byte-adressable memory, such as
+ * the buffers. dst, src, and nbytes must all satisfy (x % 4 == 0)
+ */
+void
+memcpy_wa(void *dst, const void *src, size_t nbytes)
+{
+ if (((intptr_t) dst & 0x3)
+ || ((intptr_t) src & 0x3)
+ || (nbytes & 0x3))
+ exit(1); /* die! */
+
+ int *dp = (int *) dst;
+ int *sp = (int *) src;
+ unsigned nw = nbytes/4;
+
+ unsigned i;
+ for (i = 0; i < nw; i++)
+ dp[i] = sp[i];
+}
diff --git a/firmware/microblaze/lib/memcpy_wa.h b/firmware/microblaze/lib/memcpy_wa.h
new file mode 100644
index 000000000..072fc148f
--- /dev/null
+++ b/firmware/microblaze/lib/memcpy_wa.h
@@ -0,0 +1,32 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_MEMCPY_WA_H
+#define INCLUDED_MEMCPY_WA_H
+
+#include <stddef.h>
+
+/*
+ * For copying to/from non-byte-adressable memory, such as
+ * the buffers. dst, src, and nbytes must all satisfy (x % 4 == 0)
+ */
+void memcpy_wa(void *dst, const void *src, size_t nbytes);
+
+#endif /* INCLUDED_MEMCPY_WA_H */
+
+
diff --git a/firmware/microblaze/lib/memory_map.h b/firmware/microblaze/lib/memory_map.h
new file mode 100644
index 000000000..fed1e5259
--- /dev/null
+++ b/firmware/microblaze/lib/memory_map.h
@@ -0,0 +1,796 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Overall Memory Map
+ * 0000-7FFF 32K RAM space (16K on 1500, 24K on 2000, 32K on DSP)
+ * 8000-BFFF 16K Buffer Pool
+ * C000-FFFF 16K Peripherals
+ */
+
+
+#ifndef INCLUDED_MEMORY_MAP_H
+#define INCLUDED_MEMORY_MAP_H
+
+#include <stdint.h>
+
+
+#define MASTER_CLK_RATE 100000000 // 100 MHz
+
+
+////////////////////////////////////////////////////////////////
+//
+// Memory map for embedded wishbone bus
+//
+////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////
+// Main RAM, Slave 0
+
+#define RAM_BASE 0x0000
+
+////////////////////////////////////////////////////////////////
+// Buffer Pool RAM, Slave 1
+//
+// The buffers themselves are located in Slave 1, Buffer Pool RAM.
+// The status registers are in Slave 5, Buffer Pool Status.
+// The control register is in Slave 7, Settings Bus.
+
+#define BUFFER_POOL_RAM_BASE 0x8000
+
+#define NBUFFERS 8
+#define BP_NLINES 0x0200 // number of 32-bit lines in a buffer
+#define BP_LAST_LINE (BP_NLINES - 1) // last line in a buffer
+
+#define buffer_pool_ram \
+ ((uint32_t *) BUFFER_POOL_RAM_BASE)
+
+#define buffer_ram(n) (&buffer_pool_ram[(n) * BP_NLINES])
+
+
+/////////////////////////////////////////////////////
+// SPI Core, Slave 2. See core docs for more info
+#define SPI_BASE 0xC000 // Base address (16-bit)
+
+typedef struct {
+ volatile uint32_t txrx0;
+ volatile uint32_t txrx1;
+ volatile uint32_t txrx2;
+ volatile uint32_t txrx3;
+ volatile uint32_t ctrl;
+ volatile uint32_t div;
+ volatile uint32_t ss;
+} spi_regs_t;
+
+#define spi_regs ((spi_regs_t *) SPI_BASE)
+
+
+// Masks for controlling different peripherals
+#define SPI_SS_AD9510 1
+#define SPI_SS_AD9777 2
+#define SPI_SS_RX_DAC 4
+#define SPI_SS_RX_ADC 8
+#define SPI_SS_RX_DB 16
+#define SPI_SS_TX_DAC 32
+#define SPI_SS_TX_ADC 64
+#define SPI_SS_TX_DB 128
+
+// Masks for different parts of CTRL reg
+#define SPI_CTRL_ASS (1<<13)
+#define SPI_CTRL_IE (1<<12)
+#define SPI_CTRL_LSB (1<<11)
+#define SPI_CTRL_TXNEG (1<<10)
+#define SPI_CTRL_RXNEG (1<< 9)
+#define SPI_CTRL_GO_BSY (1<< 8)
+#define SPI_CTRL_CHAR_LEN_MASK 0x7F
+
+////////////////////////////////////////////////
+// I2C, Slave 3
+// See Wishbone I2C-Master Core Specification.
+
+#define I2C_BASE 0xC400
+
+typedef struct {
+ volatile uint32_t prescaler_lo; // r/w
+ volatile uint32_t prescaler_hi; // r/w
+ volatile uint32_t ctrl; // r/w
+ volatile uint32_t data; // wr = transmit reg; rd = receive reg
+ volatile uint32_t cmd_status; // wr = command reg; rd = status reg
+} i2c_regs_t;
+
+#define i2c_regs ((i2c_regs_t *) I2C_BASE)
+
+#define I2C_CTRL_EN (1 << 7) // core enable
+#define I2C_CTRL_IE (1 << 6) // interrupt enable
+
+//
+// STA, STO, RD, WR, and IACK bits are cleared automatically
+//
+#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
+#define I2C_CMD_STOP (1 << 6) // generate stop condition
+#define I2C_CMD_RD (1 << 5) // read from slave
+#define I2C_CMD_WR (1 << 4) // write to slave
+#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
+#define I2C_CMD_RSVD_2 (1 << 2) // reserved
+#define I2C_CMD_RSVD_1 (1 << 1) // reserved
+#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
+
+#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
+#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
+#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
+#define I2C_ST_RSVD_4 (1 << 4) // reserved
+#define I2C_ST_RSVD_3 (1 << 3) // reserved
+#define I2C_ST_RSVD_2 (1 << 2) // reserved
+#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
+#define I2C_ST_IP (1 << 0) // Interrupt pending
+
+
+////////////////////////////////////////////////
+// GPIO, Slave 4
+//
+// These go to the daughterboard i/o pins
+
+#define GPIO_BASE 0xC800
+
+typedef struct {
+ volatile uint32_t io; // tx data in high 16, rx in low 16
+ volatile uint32_t ddr; // 32 bits, 1 means output. tx in high 16, rx in low 16
+ volatile uint32_t tx_sel; // 16 2-bit fields select which source goes to TX DB
+ volatile uint32_t rx_sel; // 16 2-bit fields select which source goes to RX DB
+} gpio_regs_t;
+
+// each 2-bit sel field is layed out this way
+#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
+#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
+#define GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric
+#define GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric
+
+#define gpio_base ((gpio_regs_t *) GPIO_BASE)
+
+///////////////////////////////////////////////////
+// Buffer Pool Status, Slave 5
+//
+// The buffers themselves are located in Slave 1, Buffer Pool RAM.
+// The status registers are in Slave 5, Buffer Pool Status.
+// The control register is in Slave 7, Settings Bus.
+
+#define BUFFER_POOL_STATUS_BASE 0xCC00
+
+typedef struct {
+ volatile uint32_t last_line[NBUFFERS]; // last line xfer'd in buffer
+ volatile uint32_t status; // error and done flags
+ volatile uint32_t hw_config; // see below
+ volatile uint32_t dummy[3];
+ volatile uint32_t irqs;
+ volatile uint32_t pri_enc_bp_status;
+ volatile uint32_t cycle_count;
+} buffer_pool_status_t;
+
+#define buffer_pool_status ((buffer_pool_status_t *) BUFFER_POOL_STATUS_BASE)
+
+/*
+ * Buffer n's xfer is done.
+ * Clear this bit by issuing bp_clear_buf(n)
+ */
+#define BPS_DONE(n) (0x00000001 << (n))
+#define BPS_DONE_0 BPS_DONE(0)
+#define BPS_DONE_1 BPS_DONE(1)
+#define BPS_DONE_2 BPS_DONE(2)
+#define BPS_DONE_3 BPS_DONE(3)
+#define BPS_DONE_4 BPS_DONE(4)
+#define BPS_DONE_5 BPS_DONE(5)
+#define BPS_DONE_6 BPS_DONE(6)
+#define BPS_DONE_7 BPS_DONE(7)
+
+/*
+ * Buffer n's xfer had an error.
+ * Clear this bit by issuing bp_clear_buf(n)
+ */
+#define BPS_ERROR(n) (0x00000100 << (n))
+#define BPS_ERROR_0 BPS_ERROR(0)
+#define BPS_ERROR_1 BPS_ERROR(1)
+#define BPS_ERROR_2 BPS_ERROR(2)
+#define BPS_ERROR_3 BPS_ERROR(3)
+#define BPS_ERROR_4 BPS_ERROR(4)
+#define BPS_ERROR_5 BPS_ERROR(5)
+#define BPS_ERROR_6 BPS_ERROR(6)
+#define BPS_ERROR_7 BPS_ERROR(7)
+
+/*
+ * Buffer n is idle. A buffer is idle if it's not
+ * DONE, ERROR, or processing a transaction. If it's
+ * IDLE, it's safe to start a new transaction.
+ *
+ * Clear this bit by starting a xfer with
+ * bp_send_from_buf or bp_receive_to_buf.
+ */
+#define BPS_IDLE(n) (0x00010000 << (n))
+#define BPS_IDLE_0 BPS_IDLE(0)
+#define BPS_IDLE_1 BPS_IDLE(1)
+#define BPS_IDLE_2 BPS_IDLE(2)
+#define BPS_IDLE_3 BPS_IDLE(3)
+#define BPS_IDLE_4 BPS_IDLE(4)
+#define BPS_IDLE_5 BPS_IDLE(5)
+#define BPS_IDLE_6 BPS_IDLE(6)
+#define BPS_IDLE_7 BPS_IDLE(7)
+
+/*
+ * Buffer n has a "slow path" packet in it.
+ * This bit is orthogonal to the bits above and indicates that
+ * the FPGA ethernet rx protocol engine has identified this packet
+ * as one requiring firmware intervention.
+ */
+#define BPS_SLOWPATH(n) (0x01000000 << (n))
+#define BPS_SLOWPATH_0 BPS_SLOWPATH(0)
+#define BPS_SLOWPATH_1 BPS_SLOWPATH(1)
+#define BPS_SLOWPATH_2 BPS_SLOWPATH(2)
+#define BPS_SLOWPATH_3 BPS_SLOWPATH(3)
+#define BPS_SLOWPATH_4 BPS_SLOWPATH(4)
+#define BPS_SLOWPATH_5 BPS_SLOWPATH(5)
+#define BPS_SLOWPATH_6 BPS_SLOWPATH(6)
+#define BPS_SLOWPATH_7 BPS_SLOWPATH(7)
+
+
+#define BPS_DONE_ALL 0x000000ff // mask of all dones
+#define BPS_ERROR_ALL 0x0000ff00 // mask of all errors
+#define BPS_IDLE_ALL 0x00ff0000 // mask of all idles
+#define BPS_SLOWPATH_ALL 0xff000000 // mask of all slowpaths
+
+// The hw_config register
+
+#define HWC_SIMULATION 0x80000000
+#define HWC_WB_CLK_DIV_MASK 0x0000000f
+
+/*!
+ * \brief return non-zero if we're running under the simulator
+ */
+inline static int
+hwconfig_simulation_p(void)
+{
+ return buffer_pool_status->hw_config & HWC_SIMULATION;
+}
+
+/*!
+ * \brief Return Wishbone Clock divisor.
+ * The processor runs at the Wishbone Clock rate which is MASTER_CLK_RATE / divisor.
+ */
+inline static int
+hwconfig_wishbone_divisor(void)
+{
+ return buffer_pool_status->hw_config & HWC_WB_CLK_DIV_MASK;
+}
+
+///////////////////////////////////////////////////
+// Ethernet Core, Slave 6
+
+#define ETH_BASE 0xD000
+
+#include "eth_mac_regs.h"
+
+#define eth_mac ((eth_mac_regs_t *) ETH_BASE)
+
+////////////////////////////////////////////////////
+// Settings Bus, Slave #7, Not Byte Addressable!
+//
+// Output-only from processor point-of-view.
+// 1KB of address space (== 256 32-bit write-only regs)
+
+
+#define MISC_OUTPUT_BASE 0xD400
+#define TX_PROTOCOL_ENGINE_BASE 0xD480
+#define RX_PROTOCOL_ENGINE_BASE 0xD4C0
+#define BUFFER_POOL_CTRL_BASE 0xD500
+#define LAST_SETTING_REG 0xD7FC // last valid setting register
+
+#define SR_MISC 0
+#define SR_TX_PROT_ENG 32
+#define SR_RX_PROT_ENG 48
+#define SR_BUFFER_POOL_CTRL 64
+#define SR_UDP_SM 96
+#define SR_TX_DSP 208
+#define SR_TX_CTRL 224
+#define SR_RX_DSP 160
+#define SR_RX_CTRL 176
+#define SR_TIME64 192
+#define SR_SIMTIMER 198
+#define SR_LAST 255
+
+#define _SR_ADDR(sr) (MISC_OUTPUT_BASE + (sr) * sizeof(uint32_t))
+
+// --- buffer pool control regs ---
+
+typedef struct {
+ volatile uint32_t ctrl;
+} buffer_pool_ctrl_t;
+
+// buffer pool ports
+
+#define PORT_SERDES 0 // serial/deserializer
+#define PORT_DSP 1 // DSP tx or rx pipeline
+#define PORT_ETH 2 // ethernet tx or rx
+#define PORT_RAM 3 // RAM tx or rx
+
+// the buffer pool ctrl register fields
+
+#define BPC_BUFFER(n) (((n) & 0xf) << 28)
+#define BPC_BUFFER_MASK BPC_BUFFER(~0)
+#define BPC_BUFFER_0 BPC_BUFFER(0)
+#define BPC_BUFFER_1 BPC_BUFFER(1)
+#define BPC_BUFFER_2 BPC_BUFFER(2)
+#define BPC_BUFFER_3 BPC_BUFFER(3)
+#define BPC_BUFFER_4 BPC_BUFFER(4)
+#define BPC_BUFFER_5 BPC_BUFFER(5)
+#define BPC_BUFFER_6 BPC_BUFFER(6)
+#define BPC_BUFFER_7 BPC_BUFFER(7)
+#define BPC_BUFFER_NIL BPC_BUFFER(0x8) // disable
+
+#define BPC_PORT(n) (((n) & 0x7) << 25)
+#define BPC_PORT_MASK BPC_PORT(~0)
+#define BPC_PORT_SERDES BPC_PORT(PORT_SERDES)
+#define BPC_PORT_DSP BPC_PORT(PORT_DSP)
+#define BPC_PORT_ETH BPC_PORT(PORT_ETH)
+#define BPC_PORT_RAM BPC_PORT(PORT_RAM)
+#define BPC_PORT_NIL BPC_PORT(0x4) // disable
+
+#define BPC_CLR (1 << 24) // mutually excl commands
+#define BPC_READ (1 << 23)
+#define BPC_WRITE (1 << 22)
+
+#define BPC_STEP(step) (((step) & 0xf) << 18)
+#define BPC_STEP_MASK BPC_STEP(~0)
+#define BPC_LAST_LINE(line) (((line) & 0x1ff) << 9)
+#define BPC_LAST_LINE_MASK BPC_LAST_LINE(~0)
+#define BPC_FIRST_LINE(line) (((line) & 0x1ff) << 0)
+#define BPC_FIRST_LINE_MASK BPC_FIRST_LINE(~0)
+
+#define buffer_pool_ctrl ((buffer_pool_ctrl_t *) BUFFER_POOL_CTRL_BASE)
+
+// --- misc outputs ---
+
+typedef struct {
+ volatile uint32_t clk_ctrl;
+ volatile uint32_t serdes_ctrl;
+ volatile uint32_t adc_ctrl;
+ volatile uint32_t leds;
+ volatile uint32_t phy_ctrl; // LSB is reset line to eth phy
+ volatile uint32_t debug_mux_ctrl;
+ volatile uint32_t ram_page; // FIXME should go somewhere else...
+ volatile uint32_t flush_icache; // Flush the icache
+ volatile uint32_t led_src; // HW or SW control for LEDs
+} output_regs_t;
+
+#define SERDES_ENABLE 8
+#define SERDES_PRBSEN 4
+#define SERDES_LOOPEN 2
+#define SERDES_RXEN 1
+
+#define ADC_CTRL_ON 0x0F
+#define ADC_CTRL_OFF 0x00
+
+// crazy order that matches the labels on the case
+
+#define LED_A (1 << 4)
+#define LED_B (1 << 1)
+#define LED_C (1 << 3)
+#define LED_D (1 << 0)
+#define LED_E (1 << 2)
+// LED_F // controlled by CPLD
+#define LED_RJ45 (1 << 5)
+
+#define output_regs ((output_regs_t *) MISC_OUTPUT_BASE)
+
+// --- udp tx regs ---
+
+typedef struct {
+ // Bits 19:16 are control info; bits 15:0 are data (see below)
+ // First two words are unused.
+ volatile uint32_t _nope[2];
+ //--- ethernet header - 14 bytes---
+ volatile struct{
+ uint32_t mac_dst_0_1; //word 2
+ uint32_t mac_dst_2_3;
+ uint32_t mac_dst_4_5;
+ uint32_t mac_src_0_1;
+ uint32_t mac_src_2_3;
+ uint32_t mac_src_4_5;
+ uint32_t ether_type; //word 8
+ } eth_hdr;
+ //--- ip header - 20 bytes ---
+ volatile struct{
+ uint32_t ver_ihl_tos; //word 9
+ uint32_t total_length;
+ uint32_t identification;
+ uint32_t flags_frag_off;
+ uint32_t ttl_proto;
+ uint32_t checksum;
+ uint32_t src_addr_high;
+ uint32_t src_addr_low;
+ uint32_t dst_addr_high;
+ uint32_t dst_addr_low; //word 18
+ } ip_hdr;
+ //--- udp header - 8 bytes ---
+ volatile struct{
+ uint32_t src_port; //word 19
+ uint32_t dst_port;
+ uint32_t length;
+ uint32_t checksum; //word 22
+ } udp_hdr;
+ volatile uint32_t _pad[32-23];
+} sr_udp_sm_t;
+
+// control bits (all expect UDP_SM_LAST_WORD are mutually exclusive)
+
+// This is the last word of the header
+#define UDP_SM_LAST_WORD (1 << 19)
+
+// Insert IP header checksum here. Data is the xor of 16'hFFFF and
+// the values written into regs 9-13 and 15-18.
+#define UDP_SM_INS_IP_HDR_CHKSUM (1 << 18)
+
+// Insert IP Length here (data ignored)
+#define UDP_SM_INS_IP_LEN (1 << 17)
+
+// Insert UDP Length here (data ignore)
+#define UDP_SM_INS_UDP_LEN (1 << 16)
+
+#define sr_udp_sm ((sr_udp_sm_t *) _SR_ADDR(SR_UDP_SM))
+
+// --- dsp tx regs ---
+
+#define MIN_CIC_INTERP 1
+#define MAX_CIC_INTERP 128
+
+typedef struct {
+ volatile uint32_t num_chan;
+ volatile uint32_t clear_state; // clears out state machine, fifos,
+} sr_tx_ctrl_t;
+
+#define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL))
+
+typedef struct {
+ volatile int32_t freq;
+ volatile uint32_t scale_iq; // {scale_i,scale_q}
+ volatile uint32_t interp_rate;
+ volatile uint32_t _padding0; // padding for the tx_mux
+ // NOT freq, scale, interp
+ /*!
+ * \brief output mux configuration.
+ *
+ * <pre>
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-------------------------------+-------+-------+-------+-------+
+ * | | DAC1 | DAC0 |
+ * +-------------------------------+-------+-------+-------+-------+
+ *
+ * There are N DUCs (1 now) with complex inputs and outputs.
+ * There are two DACs.
+ *
+ * Each 4-bit DACx field specifies the source for the DAC
+ * Each subfield is coded like this:
+ *
+ * 3 2 1 0
+ * +-------+
+ * | N |
+ * +-------+
+ *
+ * N specifies which DUC output is connected to this DAC.
+ *
+ * N which interp output
+ * --- -------------------
+ * 0 DUC 0 I
+ * 1 DUC 0 Q
+ * 2 DUC 1 I
+ * 3 DUC 1 Q
+ * F All Zeros
+ *
+ * The default value is 0x10
+ * </pre>
+ */
+ volatile uint32_t tx_mux;
+
+} dsp_tx_regs_t;
+
+#define dsp_tx_regs ((dsp_tx_regs_t *) _SR_ADDR(SR_TX_DSP))
+
+// --- VITA RX CTRL regs ---
+typedef struct {
+ // The following 3 are logically a single command register.
+ // They are clocked into the underlying fifo when time_ticks is written.
+ volatile uint32_t cmd; // {now, chain, num_samples(30)
+ volatile uint32_t time_secs;
+ volatile uint32_t time_ticks;
+
+ volatile uint32_t clear_overrun; // write anything to clear overrun
+ volatile uint32_t vrt_header; // word 0 of packet. FPGA fills in packet counter
+ volatile uint32_t vrt_stream_id; // word 1 of packet.
+ volatile uint32_t vrt_trailer;
+ volatile uint32_t nsamples_per_pkt;
+ volatile uint32_t nchannels; // 1 in basic case, up to 4 for vector sources
+ volatile uint32_t pad[7]; // Make each structure 16 elements long
+} sr_rx_ctrl_t;
+
+#define MAX_SAMPLES_PER_CMD 0x3fffffff
+#define MK_RX_CMD(nsamples, now, chain) \
+ ((((now) & 0x1) << 31) | (((chain) & 0x1) << 30) | ((nsamples) & 0x3fffffff))
+
+#define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL))
+
+// --- dsp rx regs ---
+#define MIN_CIC_DECIM 1
+#define MAX_CIC_DECIM 128
+
+typedef struct {
+ volatile int32_t freq;
+ volatile uint32_t scale_iq; // {scale_i,scale_q}
+ volatile uint32_t decim_rate;
+ volatile uint32_t dcoffset_i; // Bit 31 high sets fixed offset mode, using lower 14 bits,
+ // otherwise it is automatic
+ volatile uint32_t dcoffset_q; // Bit 31 high sets fixed offset mode, using lower 14 bits
+
+ /*!
+ * \brief input mux configuration.
+ *
+ * This determines which ADC (or constant zero) is connected to
+ * each DDC input. There are N DDCs (1 now). Each has two inputs.
+ *
+ * <pre>
+ * Mux value:
+ *
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | |Q0 |I0 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero)
+ * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero)
+ *
+ * The default value is 0x4
+ * </pre>
+ */
+ volatile uint32_t rx_mux; // called adc_mux in dsp_core_rx.v
+
+ /*!
+ * \brief Streaming GPIO configuration
+ *
+ * This determines whether the LSBs of I and Q samples come from the DSP
+ * pipeline or from the io_rx GPIO pins. To stream GPIO, one must first
+ * set the GPIO data direction register to have io_rx[15] and/or io_rx[14]
+ * configured as inputs. The GPIO pins will be sampled at the time the
+ * remainder of the DSP sample is strobed into the RX sample FIFO. There
+ * will be a decimation-dependent fixed time offset between the GPIO
+ * sample stream and the associated RF samples.
+ *
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | MBZ |Q|I|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * I 0=LSB comes from DSP pipeline (default)
+ * 1=LSB comes from io_rx[15]
+ *
+ * Q 0=LSB comes from DSP pipeline (default)
+ * 1=LSB comes from io_rx[14]
+ */
+ volatile uint32_t gpio_stream_enable;
+
+} dsp_rx_regs_t;
+
+#define dsp_rx_regs ((dsp_rx_regs_t *) _SR_ADDR(SR_RX_DSP))
+
+// ----------------------------------------------------------------
+// VITA49 64 bit time (write only)
+ /*!
+ * \brief Time 64 flags
+ *
+ * <pre>
+ *
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------------------------------------------------------+-+-+
+ * | |S|P|
+ * +-----------------------------------------------------------+-+-+
+ *
+ * P - PPS edge selection (0=negedge, 1=posedge, default=0)
+ * S - Source (0=sma, 1=mimo, 0=default)
+ *
+ * </pre>
+ */
+typedef struct {
+ volatile uint32_t secs; // value to set absolute secs to on next PPS
+ volatile uint32_t ticks; // value to set absolute ticks to on next PPS
+ volatile uint32_t flags; // flags - see chart above
+ volatile uint32_t imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0)
+} sr_time64_t;
+
+#define sr_time64 ((sr_time64_t *) _SR_ADDR(SR_TIME64))
+
+
+/*
+ * --- ethernet tx protocol engine regs (write only) ---
+ *
+ * These registers control the transmit portion of the ethernet
+ * protocol engine (out of USRP2). The protocol engine handles fifo
+ * status and sequence number insertion in outgoing packets, and
+ * automagically generates status packets when required to inform the
+ * host of changes in fifo availability.
+ *
+ * All outgoing packets have their fifo_status field set to the number
+ * of 32-bit lines of fifo available in the ethernet Rx fifo (see
+ * usrp2_eth_packet.h). Seqno's are set if FIXME, else 0.
+ *
+ * FIXME clean this up once we know how it's supposed to behave.
+ */
+
+typedef struct {
+ volatile uint32_t flags; // not yet fully defined (channel?)
+ volatile uint32_t mac_dst0123; // 4 bytes of destination mac addr
+ volatile uint32_t mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr
+ volatile uint32_t mac_src2345; // 4 bytes of destination mac addr
+ volatile uint32_t seqno; // Write to init seqno. It autoincs on match
+} tx_proto_engine_regs_t;
+
+#define tx_proto_engine ((tx_proto_engine_regs_t *) TX_PROTOCOL_ENGINE_BASE)
+
+/*
+ * --- ethernet rx protocol engine regs (write only) ---
+ *
+ * These registers control the receive portion of the ethernet
+ * protocol engine (into USRP2). The protocol engine offloads common
+ * packet inspection operations so that firmware has less to do on
+ * "fast path" packets.
+ *
+ * The registers define conditions which must be matched for a packet
+ * to be considered a "fast path" packet. If a received packet
+ * matches the src and dst mac address, ethertype, flags field, and
+ * expected seqno number it is considered a "fast path" packet, and
+ * the expected seqno is updated. If the packet fails to satisfy any
+ * of the above conditions it's a "slow path" packet, and the
+ * corresponding SLOWPATH flag will be set buffer_status register.
+ */
+
+typedef struct {
+ volatile uint32_t flags; // not yet fully defined (channel?)
+ volatile uint32_t mac_dst0123; // 4 bytes of destination mac addr
+ volatile uint32_t mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr
+ volatile uint32_t mac_src2345; // 4 bytes of destination mac addr
+ volatile uint32_t ethertype_pad; // ethertype in high 16-bits
+} rx_proto_engine_regs_t;
+
+#define rx_proto_engine ((rx_proto_engine_regs_t *) RX_PROTOCOL_ENGINE_BASE)
+
+
+
+///////////////////////////////////////////////////
+// Simple Programmable Interrupt Controller, Slave 8
+
+#define PIC_BASE 0xD800
+
+// Interrupt request lines
+// Bit numbers (LSB == 0) that correpond to interrupts into PIC
+
+#define IRQ_BUFFER 0 // buffer manager
+#define IRQ_ONETIME 1
+#define IRQ_SPI 2
+#define IRQ_I2C 3
+#define IRQ_PHY 4 // ethernet PHY
+#define IRQ_UNDERRUN 5
+#define IRQ_OVERRUN 6
+#define IRQ_PPS 7 // pulse per second
+#define IRQ_UART_RX 8
+#define IRQ_UART_TX 9
+#define IRQ_SERDES 10
+#define IRQ_CLKSTATUS 11
+#define IRQ_PERIODIC 12
+
+#define IRQ_TO_MASK(x) (1 << (x))
+
+#define PIC_BUFFER_INT IRQ_TO_MASK(IRQ_BUFFER)
+#define PIC_ONETIME_INT IRQ_TO_MASK(IRQ_ONETIME)
+#define PIC_SPI_INT IRQ_TO_MASK(IRQ_SPI)
+#define PIC_I2C_INT IRQ_TO_MASK(IRQ_I2C)
+#define PIC_PHY_INT IRQ_TO_MASK(IRQ_PHY)
+#define PIC_UNDERRUN_INT IRQ_TO_MASK(IRQ_UNDERRUN)
+#define PIC_OVERRUN_INT IRQ_TO_MASK(IRQ_OVERRUN)
+#define PIC_PPS_INT IRQ_TO_MASK(IRQ_PPS)
+#define PIC_UART_RX_INT IRQ_TO_MASK(IRQ_UART_RX)
+#define PIC_UART_TX_INT IRQ_TO_MASK(IRQ_UART_TX)
+#define PIC_SERDES IRQ_TO_MASK(IRQ_SERDES)
+#define PIC_CLKSTATUS IRQ_TO_MASK(IRQ_CLKSTATUS)
+
+typedef struct {
+ volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level
+ volatile uint32_t polarity; // mask: 1 -> rising edge
+ volatile uint32_t mask; // mask: 1 -> disabled
+ volatile uint32_t pending; // mask: 1 -> pending; write 1's to clear pending ints
+} pic_regs_t;
+
+#define pic_regs ((pic_regs_t *) PIC_BASE)
+
+// ----------------------------------------------------------------
+// WB_CLK_RATE is the time base for this
+typedef struct {
+ volatile uint32_t onetime; // Number of wb clk cycles till the onetime interrupt
+ volatile uint32_t periodic; // Repeat rate of periodic interrupt
+} sr_simple_timer_t;
+
+#define sr_simple_timer ((sr_simple_timer_t *) _SR_ADDR(SR_SIMTIMER))
+
+///////////////////////////////////////////////////
+// UART, Slave 10
+
+#define UART_BASE 0xE000
+
+typedef struct {
+ // All elements are 8 bits except for clkdiv (16), but we use uint32 to make
+ // the hardware for decoding easier
+ volatile uint32_t clkdiv; // Set to 50e6 divided by baud rate (no x16 factor)
+ volatile uint32_t txlevel; // Number of spaces in the FIFO for writes
+ volatile uint32_t rxlevel; // Number of available elements in the FIFO for reads
+ volatile uint32_t txchar; // Write characters to be sent here
+ volatile uint32_t rxchar; // Read received characters here
+} uart_regs_t;
+
+#define uart_regs ((uart_regs_t *) UART_BASE)
+
+///////////////////////////////////////////////////
+// ATR Controller, Slave 11
+
+#define ATR_BASE 0xE400
+
+typedef struct {
+ volatile uint32_t v[16];
+} atr_regs_t;
+
+#define ATR_IDLE 0x0 // indicies into v
+#define ATR_TX 0x1
+#define ATR_RX 0x2
+#define ATR_FULL 0x3
+
+#define atr_regs ((atr_regs_t *) ATR_BASE)
+
+///////////////////////////////////////////////////
+// SD Card SPI interface, Slave 13
+// All regs are 8 bits wide, but are accessed as if they are 32 bits
+
+#define SDSPI_BASE 0xEC00
+
+typedef struct {
+ volatile uint32_t status; // Write a 1 or 0 for controlling CS
+ volatile uint32_t clkdiv;
+ volatile uint32_t send_dat;
+ volatile uint32_t receive_dat;
+} sdspi_regs_t;
+
+#define sdspi_regs ((sdspi_regs_t *) SDSPI_BASE)
+
+///////////////////////////////////////////////////
+// External RAM interface, Slave 14
+// Pages are 1K. Page is 10 bits, set by a control register
+// output_regs->ram_page
+
+#define EXTRAM_BASE 0xF000
+#define extram ((volatile uint32_t *) EXTRAM_BASE)
+
+
+///////////////////////////////////////////////////
+
+#endif
+
diff --git a/firmware/microblaze/lib/memset_wa.c b/firmware/microblaze/lib/memset_wa.c
new file mode 100644
index 000000000..da5da21ab
--- /dev/null
+++ b/firmware/microblaze/lib/memset_wa.c
@@ -0,0 +1,45 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "memset_wa.h"
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * For setting non-byte-adressable memory, such as
+ * the buffers. dst and nbytes must all satisfy (x % 4 == 0)
+ */
+void *
+memset_wa(void *dst, int c, size_t nbytes)
+{
+ if (((intptr_t) dst & 0x3)
+ || (nbytes & 0x3))
+ exit(1); /* die! */
+
+ int *dp = (int *) dst;
+
+ c &= 0xff;
+ int v = (c << 24) | (c << 16) | (c << 8) | c;
+ unsigned nw = nbytes/4;
+
+ unsigned i;
+ for (i = 0; i < nw; i++)
+ dp[i] = v;
+
+ return dst;
+}
diff --git a/firmware/microblaze/lib/memset_wa.h b/firmware/microblaze/lib/memset_wa.h
new file mode 100644
index 000000000..46d903d53
--- /dev/null
+++ b/firmware/microblaze/lib/memset_wa.h
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_MEMSET_WA_H
+#define INCLUDED_MEMSET_WA_H
+
+#include <stdlib.h>
+
+void *memset_wa(void *s, int c, size_t n);
+
+
+#endif /* INCLUDED_MEMSET_WA_H */
diff --git a/firmware/microblaze/lib/net_common.c b/firmware/microblaze/lib/net_common.c
new file mode 100644
index 000000000..6c9509c92
--- /dev/null
+++ b/firmware/microblaze/lib/net_common.c
@@ -0,0 +1,449 @@
+/* -*- c -*- */
+/*
+ * Copyright 2009,2010 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "net_common.h"
+#include "banal.h"
+#include <hal_io.h>
+#include <buffer_pool.h>
+#include <memory_map.h>
+#include <memcpy_wa.h>
+#include <ethernet.h>
+#include <net/padded_eth_hdr.h>
+#include <lwip/ip.h>
+#include <lwip/udp.h>
+#include <lwip/icmp.h>
+#include <stdlib.h>
+#include <nonstdio.h>
+#include "arp_cache.h"
+#include "if_arp.h"
+#include <ethertype.h>
+#include <string.h>
+
+
+int cpu_tx_buf_dest_port = PORT_ETH;
+
+// If this is non-zero, this dbsm could be writing to the ethernet
+dbsm_t *ac_could_be_sending_to_eth;
+
+static inline bool
+ip_addr_eq(const struct ip_addr a, const struct ip_addr b)
+{
+ return a.addr == b.addr;
+}
+
+// ------------------------------------------------------------------------
+
+static eth_mac_addr_t _local_mac_addr;
+void register_mac_addr(const eth_mac_addr_t *mac_addr){
+ _local_mac_addr = *mac_addr;
+}
+
+static struct ip_addr _local_ip_addr;
+void register_ip_addr(const struct ip_addr *ip_addr){
+ _local_ip_addr = *ip_addr;
+}
+
+//-------------------------------------------------------------------------
+
+#define MAX_UDP_LISTENERS 6
+
+struct listener_entry {
+ unsigned short port;
+ udp_receiver_t rcvr;
+};
+
+static struct listener_entry listeners[MAX_UDP_LISTENERS];
+
+static struct listener_entry *
+find_listener_by_port(unsigned short port)
+{
+ for (int i = 0; i < MAX_UDP_LISTENERS; i++){
+ if (port == listeners[i].port)
+ return &listeners[i];
+ }
+ return 0;
+}
+
+static struct listener_entry *
+find_free_listener(void)
+{
+ for (int i = 0; i < MAX_UDP_LISTENERS; i++){
+ if (listeners[i].rcvr == 0)
+ return &listeners[i];
+ }
+ abort();
+}
+
+void
+register_udp_listener(int port, udp_receiver_t rcvr)
+{
+ struct listener_entry *lx = find_listener_by_port(port);
+ if (lx)
+ lx->rcvr = rcvr;
+ else {
+ lx = find_free_listener();
+ lx->port = port;
+ lx->rcvr = rcvr;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+
+/*!
+ * low level routine to assembly an ethernet frame and send it.
+ *
+ * \param dst destination mac address
+ * \param ethertype ethertype field
+ * \param buf0 first part of data
+ * \param len0 length of first part of data
+ * \param buf1 second part of data
+ * \param len1 length of second part of data
+ * \param buf2 third part of data
+ * \param len2 length of third part of data
+ */
+static void
+send_pkt(eth_mac_addr_t dst, int ethertype,
+ const void *buf0, size_t len0,
+ const void *buf1, size_t len1,
+ const void *buf2, size_t len2)
+{
+ // Wait for buffer to become idle
+ // FIXME can this ever not be ready?
+
+ //hal_set_leds(LED_BUF_BUSY, LED_BUF_BUSY);
+ while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0)
+ ;
+ //hal_set_leds(0, LED_BUF_BUSY);
+
+ // Assemble the header
+ padded_eth_hdr_t ehdr;
+ ehdr.pad = 0;
+ ehdr.dst = dst;
+ ehdr.src = _local_mac_addr;
+ ehdr.ethertype = ethertype;
+
+ uint32_t *p = buffer_ram(CPU_TX_BUF);
+
+ // Copy the pieces into the buffer
+ *p++ = 0x0; // slow path
+ memcpy_wa(p, &ehdr, sizeof(ehdr)); // 4 lines
+ p += sizeof(ehdr)/sizeof(uint32_t);
+
+
+ // FIXME modify memcpy_wa to do read/modify/write if reqd
+
+ if (len0 && ((len0 & 0x3) || (intptr_t) buf0 & 0x3))
+ printf("send_pkt: bad alignment of len0 and/or buf0\n");
+
+ if (len1 && ((len1 & 0x3) || (intptr_t) buf1 & 0x3))
+ printf("send_pkt: bad alignment of len1 and/or buf1\n");
+
+ if (len2 && ((len2 & 0x3) || (intptr_t) buf2 & 0x3))
+ printf("send_pkt: bad alignment of len2 and/or buf2\n");
+
+ if (len0){
+ memcpy_wa(p, buf0, len0);
+ p += len0/sizeof(uint32_t);
+ }
+ if (len1){
+ memcpy_wa(p, buf1, len1);
+ p += len1/sizeof(uint32_t);
+ }
+ if (len2){
+ memcpy_wa(p, buf2, len2);
+ p += len2/sizeof(uint32_t);
+ }
+
+ size_t total_len = (p - buffer_ram(CPU_TX_BUF)) * sizeof(uint32_t);
+ if (total_len < 60) // ensure that we don't try to send a short packet
+ total_len = 60;
+
+ // wait until nobody else is sending to the ethernet
+ if (ac_could_be_sending_to_eth){
+ //hal_set_leds(LED_ETH_BUSY, LED_ETH_BUSY);
+ dbsm_wait_for_opening(ac_could_be_sending_to_eth);
+ //hal_set_leds(0x0, LED_ETH_BUSY);
+ }
+
+ if (0){
+ printf("send_pkt to port %d, len = %d\n",
+ cpu_tx_buf_dest_port, (int) total_len);
+ print_buffer(buffer_ram(CPU_TX_BUF), total_len/4);
+ }
+
+ // fire it off
+ bp_send_from_buf(CPU_TX_BUF, cpu_tx_buf_dest_port, 1, 0, total_len/4);
+
+ // wait for it to complete (not long, it's a small pkt)
+ while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0)
+ ;
+
+ bp_clear_buf(CPU_TX_BUF);
+}
+
+unsigned int
+chksum_buffer(unsigned short *buf, int nshorts, unsigned int initial_chksum)
+{
+ unsigned int chksum = initial_chksum;
+ for (int i = 0; i < nshorts; i++)
+ CHKSUM(buf[i], &chksum);
+
+ return chksum;
+}
+
+
+void
+send_ip_pkt(struct ip_addr dst, int protocol,
+ const void *buf0, size_t len0,
+ const void *buf1, size_t len1)
+{
+ int ttl = 32;
+
+ struct ip_hdr ip;
+ IPH_VHLTOS_SET(&ip, 4, 5, 0);
+ IPH_LEN_SET(&ip, IP_HLEN + len0 + len1);
+ IPH_ID_SET(&ip, 0);
+ IPH_OFFSET_SET(&ip, IP_DF); /* don't fragment */
+ ip._ttl_proto = (ttl << 8) | (protocol & 0xff);
+ ip._chksum = 0;
+ ip.src = _local_ip_addr;
+ ip.dest = dst;
+
+ ip._chksum = ~chksum_buffer((unsigned short *) &ip,
+ sizeof(ip)/sizeof(short), 0);
+
+ eth_mac_addr_t dst_mac;
+ bool found = arp_cache_lookup_mac(&ip.dest, &dst_mac);
+ if (!found){
+ printf("net_common: failed to hit cache looking for ");
+ print_ip(ip.dest);
+ newline();
+ return;
+ }
+
+ send_pkt(dst_mac, ETHERTYPE_IPV4,
+ &ip, sizeof(ip), buf0, len0, buf1, len1);
+}
+
+void
+send_udp_pkt(int src_port, struct socket_address dst,
+ const void *buf, size_t len)
+{
+ struct udp_hdr udp _AL4;
+ udp.src = src_port;
+ udp.dest = dst.port;
+ udp.len = UDP_HLEN + len;
+ udp.chksum = 0;
+
+ send_ip_pkt(dst.addr, IP_PROTO_UDP,
+ &udp, sizeof(udp), buf, len);
+}
+
+static void
+handle_udp_packet(struct ip_addr src_ip, struct ip_addr dst_ip,
+ struct udp_hdr *udp, size_t len)
+{
+ if (len != udp->len){
+ printf("UDP inconsistent lengths: %d %d\n", (int)len, udp->len);
+ return;
+ }
+
+ unsigned char *payload = ((unsigned char *) udp) + UDP_HLEN;
+ int payload_len = len - UDP_HLEN;
+
+ if (0){
+ printf("\nUDP: src = %d dst = %d len = %d\n",
+ udp->src, udp->dest, udp->len);
+
+ //print_bytes(0, payload, payload_len);
+ }
+
+ struct listener_entry *lx = find_listener_by_port(udp->dest);
+ if (lx){
+ struct socket_address src = make_socket_address(src_ip, udp->src);
+ struct socket_address dst = make_socket_address(dst_ip, udp->dest);
+ lx->rcvr(src, dst, payload, payload_len);
+ }
+}
+
+static void
+handle_icmp_packet(struct ip_addr src, struct ip_addr dst,
+ struct icmp_echo_hdr *icmp, size_t len)
+{
+ switch (icmp->type){
+ case ICMP_DUR: // Destinatino Unreachable
+ //stop_streaming(); //FIXME
+ if (icmp->code == ICMP_DUR_PORT){ // port unreachable
+ //struct udp_hdr *udp = (struct udp_hdr *)((char *)icmp + 28);
+ //printf("icmp port unr %d\n", udp->dest);
+ putchar('i');
+ }
+ else {
+ //printf("icmp dst unr (code: %d)", icmp->code);
+ putchar('i');
+ }
+ break;
+
+ case ICMP_ECHO:{
+ struct icmp_echo_hdr echo_reply;
+ echo_reply.type = 0;
+ echo_reply.code = 0;
+ echo_reply.chksum = 0;
+ echo_reply.id = icmp->id;
+ echo_reply.seqno = icmp->seqno;
+ echo_reply.chksum = ~chksum_buffer(
+ (unsigned short *)&echo_reply,
+ sizeof(echo_reply)/sizeof(short),
+ 0);
+ send_ip_pkt(
+ src, IP_PROTO_ICMP, &echo_reply, sizeof(echo_reply),
+ ((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr),
+ len - sizeof(struct icmp_echo_hdr)
+ );
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void __attribute__((unused))
+print_arp_ip(const unsigned char ip[4])
+{
+ printf("%d.%d.%d.%d", ip[0], ip[1], ip[2],ip[3]);
+}
+
+static void
+send_arp_reply(struct arp_eth_ipv4 *req, eth_mac_addr_t our_mac)
+{
+ struct arp_eth_ipv4 reply _AL4;
+ reply.ar_hrd = req->ar_hrd;
+ reply.ar_pro = req->ar_pro;
+ reply.ar_hln = req->ar_hln;
+ reply.ar_pln = req->ar_pln;
+ reply.ar_op = ARPOP_REPLY;
+ memcpy(reply.ar_sha, &our_mac, 6);
+ memcpy(reply.ar_sip, req->ar_tip, 4);
+ memcpy(reply.ar_tha, req->ar_sha, 6);
+ memcpy(reply.ar_tip, req->ar_sip, 4);
+
+ eth_mac_addr_t t;
+ memcpy(t.addr, reply.ar_tha, 6);
+ send_pkt(t, ETHERTYPE_ARP, &reply, sizeof(reply), 0, 0, 0, 0);
+}
+
+
+static void
+handle_arp_packet(struct arp_eth_ipv4 *p, size_t size)
+{
+ if (size < sizeof(struct arp_eth_ipv4)){
+ printf("\nhandle_arp: weird size = %d\n", (int)size);
+ return;
+ }
+
+ if (0){
+ printf("ar_hrd = %d\n", p->ar_hrd);
+ printf("ar_pro = %d\n", p->ar_pro);
+ printf("ar_hln = %d\n", p->ar_hln);
+ printf("ar_pln = %d\n", p->ar_pln);
+ printf("ar_op = %d\n", p->ar_op);
+ printf("ar_sha = "); print_mac_addr(p->ar_sha); newline();
+ printf("ar_sip = "); print_arp_ip(p->ar_sip); newline();
+ printf("ar_tha = "); print_mac_addr(p->ar_tha); newline();
+ printf("ar_tip = "); print_arp_ip(p->ar_tip); newline();
+ }
+
+ if (p->ar_hrd != ARPHRD_ETHER
+ || p->ar_pro != ETHERTYPE_IPV4
+ || p->ar_hln != 6
+ || p->ar_pln != 4)
+ return;
+
+ if (p->ar_op != ARPOP_REQUEST)
+ return;
+
+ struct ip_addr sip;
+ struct ip_addr tip;
+
+ sip.addr = get_int32(p->ar_sip);
+ tip.addr = get_int32(p->ar_tip);
+
+ if (ip_addr_eq(tip, _local_ip_addr)){ // They're looking for us...
+ send_arp_reply(p, _local_mac_addr);
+ }
+}
+
+void
+handle_eth_packet(uint32_t *p, size_t nlines)
+{
+ //print_buffer(p, nlines);
+
+ int ethertype = p[3] & 0xffff;
+
+ if (ethertype == ETHERTYPE_ARP){
+ struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(p + 4);
+ handle_arp_packet(arp, nlines*sizeof(uint32_t) - 14);
+ }
+ else if (ethertype == ETHERTYPE_IPV4){
+ struct ip_hdr *ip = (struct ip_hdr *)(p + 4);
+ if (IPH_V(ip) != 4 || IPH_HL(ip) != 5) // ignore pkts w/ bad version or options
+ return;
+
+ if (IPH_OFFSET(ip) & (IP_MF | IP_OFFMASK)) // ignore fragmented packets
+ return;
+
+ // FIXME filter on dest ip addr (should be broadcast or for us)
+
+ arp_cache_update(&ip->src, (eth_mac_addr_t *)(((char *)p)+8));
+
+ int protocol = IPH_PROTO(ip);
+ int len = IPH_LEN(ip) - IP_HLEN;
+
+ switch (protocol){
+ case IP_PROTO_UDP:
+ handle_udp_packet(ip->src, ip->dest, (struct udp_hdr *)(((char *)ip) + IP_HLEN), len);
+ break;
+
+ case IP_PROTO_ICMP:
+ handle_icmp_packet(ip->src, ip->dest, (struct icmp_echo_hdr *)(((char *)ip) + IP_HLEN), len);
+ break;
+
+ default: // ignore
+ break;
+ }
+ }
+ else
+ return; // Not ARP or IPV4, ignore
+}
+
+// ------------------------------------------------------------------------
+
+void
+print_ip(struct ip_addr ip)
+{
+ unsigned int t = ntohl(ip.addr);
+ printf("%d.%d.%d.%d",
+ (t >> 24) & 0xff,
+ (t >> 16) & 0xff,
+ (t >> 8) & 0xff,
+ t & 0xff);
+}
diff --git a/firmware/microblaze/lib/net_common.h b/firmware/microblaze/lib/net_common.h
new file mode 100644
index 000000000..112669b46
--- /dev/null
+++ b/firmware/microblaze/lib/net_common.h
@@ -0,0 +1,50 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009,2010 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_NET_COMMON_H
+#define INCLUDED_NET_COMMON_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <dbsm.h>
+#include <net/socket_address.h>
+#include <net/eth_mac_addr.h>
+
+#define CPU_TX_BUF 7 // cpu -> eth
+
+extern int cpu_tx_buf_dest_port;
+
+// If this is non-zero, this dbsm could be writing to the ethernet
+extern dbsm_t *ac_could_be_sending_to_eth;
+
+void stop_streaming(void);
+
+typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst,
+ unsigned char *payload, int payload_len);
+
+void register_mac_addr(const eth_mac_addr_t *mac_addr);
+
+void register_ip_addr(const struct ip_addr *ip_addr);
+
+void register_udp_listener(int port, udp_receiver_t rcvr);
+
+void send_udp_pkt(int src_port, struct socket_address dst,
+ const void *buf, size_t len);
+
+void handle_eth_packet(uint32_t *p, size_t nlines);
+
+#endif /* INCLUDED_NET_COMMON_H */
diff --git a/firmware/microblaze/lib/nonstdio.c b/firmware/microblaze/lib/nonstdio.c
new file mode 100644
index 000000000..1c991afee
--- /dev/null
+++ b/firmware/microblaze/lib/nonstdio.c
@@ -0,0 +1,80 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <nonstdio.h>
+
+static const char hex[16] = "0123456789ABCDEF";
+
+// %x
+void
+puthex4(unsigned long x)
+{
+ putchar(hex[x & 0xf]);
+}
+
+// %02x
+void
+puthex8(unsigned long x)
+{
+ putchar(hex[(x >> 4) & 0xf]);
+ putchar(hex[x & 0xf]);
+}
+
+// %04x
+void
+puthex16(unsigned long x)
+{
+ puthex8(x >> 8);
+ puthex8(x);
+}
+
+// %08x
+void
+puthex32(unsigned long x)
+{
+ puthex16(x >> 16);
+ puthex16(x);
+}
+
+void
+puthex4_nl(unsigned long x)
+{
+ puthex4(x);
+ newline();
+}
+
+void
+puthex8_nl(unsigned long x)
+{
+ puthex8(x);
+ newline();
+}
+
+void
+puthex16_nl(unsigned long x)
+{
+ puthex16(x);
+ newline();
+}
+
+void
+puthex32_nl(unsigned long x)
+{
+ puthex32(x);
+ newline();
+}
diff --git a/firmware/microblaze/lib/nonstdio.h b/firmware/microblaze/lib/nonstdio.h
new file mode 100644
index 000000000..3fd9e39bb
--- /dev/null
+++ b/firmware/microblaze/lib/nonstdio.h
@@ -0,0 +1,46 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_NONSTDIO_H
+#define INCLUDED_NONSTDIO_H
+
+#include <stdio.h>
+#include <usrp2_types.h>
+#include <stddef.h>
+
+void putstr(const char *s); // cf puts, no added newline
+void puthex4(unsigned long x); // output 1 hex digit
+void puthex8(unsigned long x); // output 2 hex digits
+void puthex16(unsigned long x); // output 4 hex digits
+void puthex32(unsigned long x); // output 8 hex digits
+void puthex4_nl(unsigned long x); // ... followed by newline
+void puthex8_nl(unsigned long x);
+void puthex16_nl(unsigned long x);
+void puthex32_nl(unsigned long x);
+#define puthex puthex32
+#define puthex_nl puthex32_nl
+void newline(); // putchar('\n')
+
+void print_mac_addr(const unsigned char addr[6]);
+void print_fxpt_freq(u2_fxpt_freq_t v);
+void print_fxpt_gain(u2_fxpt_gain_t v);
+void print_uint64(uint64_t v);
+
+void print_buffer(uint32_t *buf, size_t n);
+
+#endif /* INCLUDED_NONSTDIO_H */
diff --git a/firmware/microblaze/lib/pic.c b/firmware/microblaze/lib/pic.c
new file mode 100644
index 000000000..4575bd775
--- /dev/null
+++ b/firmware/microblaze/lib/pic.c
@@ -0,0 +1,94 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pic.h"
+#include "hal_io.h"
+#include "memory_map.h"
+
+
+#define NVECTORS 8
+
+/*
+ * Our secondary interrupt vector.
+ */
+irq_handler_t pic_vector[NVECTORS] = {
+ nop_handler,
+ nop_handler,
+ nop_handler,
+ nop_handler,
+ nop_handler,
+ nop_handler,
+ nop_handler,
+ nop_handler
+};
+
+
+void
+pic_init(void)
+{
+ // uP is level triggered
+
+ pic_regs->mask = ~0; // mask all interrupts
+ pic_regs->edge_enable = PIC_ONETIME_INT | PIC_PHY_INT;
+ pic_regs->polarity = ~0 & ~PIC_PHY_INT; // rising edge
+ pic_regs->pending = ~0; // clear all pending ints
+}
+
+/*
+ * This magic gets pic_interrupt_handler wired into the
+ * system interrupt handler with the appropriate prologue and
+ * epilogue.
+ */
+void pic_interrupt_handler() __attribute__ ((interrupt_handler));
+
+void pic_interrupt_handler()
+{
+ // pending and not masked interrupts
+ int live = pic_regs->pending & ~pic_regs->mask;
+
+ // FIXME loop while there are interrupts to service.
+ // That will reduce our overhead.
+
+ // handle the first one set
+ int i;
+ int mask;
+ for (i=0, mask=1; i < NVECTORS; i++, mask <<= 1){
+ if (mask & live){ // handle this one
+ // puthex_nl(i);
+ (*pic_vector[i])(i);
+ pic_regs->pending = mask; // clear pending interrupt
+ return;
+ }
+ }
+}
+
+void
+pic_register_handler(unsigned irq, irq_handler_t handler)
+{
+ if (irq >= NVECTORS)
+ return;
+ pic_vector[irq] = handler;
+
+ pic_regs->mask &= ~IRQ_TO_MASK(irq);
+}
+
+void
+nop_handler(unsigned irq)
+{
+ // nop
+}
diff --git a/firmware/microblaze/lib/pic.h b/firmware/microblaze/lib/pic.h
new file mode 100644
index 000000000..68918f9ad
--- /dev/null
+++ b/firmware/microblaze/lib/pic.h
@@ -0,0 +1,35 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_PIC_H
+#define INCLUDED_PIC_H
+
+typedef void (*irq_handler_t)(unsigned irq);
+
+void pic_init(void);
+void pic_register_handler(unsigned irq, irq_handler_t handler);
+
+void nop_handler(unsigned irq); // default handler does nothing
+
+// FIXME inline assembler
+int pic_disable_interrupts();
+int pic_enable_interrupts();
+void pic_restore_interrupts(int prev_status);
+
+
+#endif /* INCLUDED_PIC_H */
diff --git a/firmware/microblaze/lib/print_buffer.c b/firmware/microblaze/lib/print_buffer.c
new file mode 100644
index 000000000..9f9104bb5
--- /dev/null
+++ b/firmware/microblaze/lib/print_buffer.c
@@ -0,0 +1,36 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <nonstdio.h>
+
+void
+print_buffer(uint32_t *buf, size_t n)
+{
+ size_t i;
+ for (i = 0; i < n; i++){
+ if (i % 4 == 0)
+ puthex16(i * 4);
+
+ putchar(' ');
+ puthex32(buf[i]);
+ if (i % 4 == 3)
+ newline();
+ }
+
+ newline();
+}
+
diff --git a/firmware/microblaze/lib/print_fxpt.c b/firmware/microblaze/lib/print_fxpt.c
new file mode 100644
index 000000000..185bbc51b
--- /dev/null
+++ b/firmware/microblaze/lib/print_fxpt.c
@@ -0,0 +1,83 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <nonstdio.h>
+
+/*
+ * print uint64_t
+ */
+void
+print_uint64(uint64_t u)
+{
+ const char *_hex = "0123456789ABCDEF";
+ if (u >= 10)
+ print_uint64(u/10);
+ putchar(_hex[u%10]);
+}
+
+static void
+print_thousandths(int thousandths)
+{
+ putchar('.');
+ if (thousandths < 100)
+ putchar('0');
+ if (thousandths < 10)
+ putchar('0');
+ printf("%d", thousandths);
+}
+
+
+void
+print_fxpt_freq(u2_fxpt_freq_t v)
+{
+ if (v < 0){
+ v = -v;
+ putchar('-');
+ }
+
+ int64_t int_part = v >> 20;
+ int32_t frac_part = v & ((1 << 20) - 1);
+
+#if 0
+ // would work, if we had it
+ printf("%lld.%03d", int_part, (frac_part * 1000) >> 20);
+#else
+ print_uint64(int_part);
+ print_thousandths((frac_part * 1000) >> 20);
+#endif
+}
+
+void
+print_fxpt_gain(u2_fxpt_gain_t v)
+{
+ if (v < 0){
+ v = -v;
+ putchar('-');
+ }
+
+ int32_t int_part = v >> 7;
+ int32_t frac_part = v & ((1 << 7) - 1);
+
+#if 0
+ // would work, if we had it
+ printf("%d.%03d", int_part, (frac_part * 1000) >> 7);
+#else
+ printf("%d", int_part);
+ print_thousandths((frac_part * 1000) >> 7);
+#endif
+}
+
diff --git a/firmware/microblaze/lib/print_mac_addr.c b/firmware/microblaze/lib/print_mac_addr.c
new file mode 100644
index 000000000..838fd614a
--- /dev/null
+++ b/firmware/microblaze/lib/print_mac_addr.c
@@ -0,0 +1,30 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "nonstdio.h"
+
+void
+print_mac_addr(const unsigned char addr[6])
+{
+ puthex8(addr[0]); putchar(':');
+ puthex8(addr[1]); putchar(':');
+ puthex8(addr[2]); putchar(':');
+ puthex8(addr[3]); putchar(':');
+ puthex8(addr[4]); putchar(':');
+ puthex8(addr[5]);
+}
+
diff --git a/firmware/microblaze/lib/print_rmon_regs.c b/firmware/microblaze/lib/print_rmon_regs.c
new file mode 100644
index 000000000..6d9986909
--- /dev/null
+++ b/firmware/microblaze/lib/print_rmon_regs.c
@@ -0,0 +1,44 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "print_rmon_regs.h"
+#include "eth_mac.h"
+#include "nonstdio.h"
+
+void
+print_rmon_regs(void)
+{
+ int i;
+ for (i=0; i <= 0x10; i++){
+ putstr("RMON[0x");
+ puthex8(i);
+ putstr("] = ");
+ printf("%d\n", eth_mac_read_rmon(i));
+ }
+
+ for (i=0x20; i <= 0x30; i++){
+ putstr("RMON[0x");
+ puthex8(i);
+ putstr("] = ");
+ printf("%d\n", eth_mac_read_rmon(i));
+ }
+}
diff --git a/firmware/microblaze/lib/print_rmon_regs.h b/firmware/microblaze/lib/print_rmon_regs.h
new file mode 100644
index 000000000..44e52da84
--- /dev/null
+++ b/firmware/microblaze/lib/print_rmon_regs.h
@@ -0,0 +1,24 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_PRINT_RMON_REGS_H
+#define INCLUDED_PRINT_RMON_REGS_H
+
+void print_rmon_regs(void);
+
+#endif /* INCLUDED_PRINT_RMON_REGS_H */
diff --git a/firmware/microblaze/lib/printf.c b/firmware/microblaze/lib/printf.c
new file mode 100644
index 000000000..45bd57cb9
--- /dev/null
+++ b/firmware/microblaze/lib/printf.c
@@ -0,0 +1,134 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Based on code from the SDCC z80 library ;)
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+static void
+_printn(unsigned u, unsigned base, char issigned,
+ void (*emitter)(char, void *), void *pData)
+{
+ const char *_hex = "0123456789ABCDEF";
+ if (issigned && ((int)u < 0)) {
+ (*emitter)('-', pData);
+ u = (unsigned)-((int)u);
+ }
+ if (u >= base)
+ _printn(u/base, base, 0, emitter, pData);
+ (*emitter)(_hex[u%base], pData);
+}
+
+static void
+_printf(const char *format, void (*emitter)(char, void *),
+ void *pData, va_list va)
+{
+ while (*format) {
+ if (*format != '%')
+ (*emitter)(*format, pData);
+ else {
+ switch (*++format) {
+ case 0: /* hit end of format string */
+ return;
+ case 'c':
+ {
+ char c = (char)va_arg(va, int);
+ (*emitter)(c, pData);
+ break;
+ }
+ case 'u':
+ {
+ unsigned u = va_arg(va, unsigned);
+ _printn(u, 10, 0, emitter, pData);
+ break;
+ }
+ case 'd':
+ {
+ unsigned u = va_arg(va, unsigned);
+ _printn(u, 10, 1, emitter, pData);
+ break;
+ }
+ case 'x':
+ case 'p':
+ {
+ unsigned u = va_arg(va, unsigned);
+ _printn(u, 16, 0, emitter, pData);
+ break;
+ }
+ case 's':
+ {
+ char *s = va_arg(va, char *);
+ while (*s) {
+ (*emitter)(*s, pData);
+ s++;
+ }
+ break;
+ }
+ }
+ }
+ format++;
+ }
+}
+
+static void
+_char_emitter(char c, void *pData __attribute__((unused)))
+{
+ putchar(c);
+}
+
+int
+printf(const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+
+ _printf(format, _char_emitter, NULL, va);
+
+ va_end(va);
+
+ // wrong return value...
+ return 0;
+}
+
+
+#if 0
+
+// Totally dangerous. Don't use
+static void
+_buf_emitter(char c, void *pData)
+{
+ *((*((char **)pData)))++ = c;
+}
+
+int sprintf(char *pInto, const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+
+ _printf(format, _buf_emitter, &pInto, va);
+ *pInto++ = '\0';
+
+ va_end(va);
+
+ // FIXME wrong return value
+ return 0;
+}
+#endif
diff --git a/firmware/microblaze/lib/printf.c.smaller b/firmware/microblaze/lib/printf.c.smaller
new file mode 100644
index 000000000..4d858648d
--- /dev/null
+++ b/firmware/microblaze/lib/printf.c.smaller
@@ -0,0 +1,134 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Based on code from the SDCC z80 library ;)
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <hal_io.h> /* FIXME refactor into stdio */
+
+#define PUTCHAR(x) hal_putc(x)
+
+
+static void
+_printn(unsigned u, unsigned base, char issigned)
+{
+ const char *_hex = "0123456789ABCDEF";
+ if (issigned && ((int)u < 0)) {
+ PUTCHAR('-');
+ u = (unsigned)-((int)u);
+ }
+ if (u >= base)
+ _printn(u/base, base, 0);
+ PUTCHAR(_hex[u%base]);
+}
+
+static void
+_printf(const char *format, va_list va)
+{
+ while (*format) {
+ if (*format != '%')
+ PUTCHAR(*format);
+ else {
+ switch (*++format) {
+ case 0: /* hit end of format string */
+ return;
+ case 'c':
+ {
+ char c = (char)va_arg(va, int);
+ PUTCHAR(c);
+ break;
+ }
+ case 'u':
+ {
+ unsigned u = va_arg(va, unsigned);
+ _printn(u, 10, 0);
+ break;
+ }
+ case 'd':
+ {
+ unsigned u = va_arg(va, unsigned);
+ _printn(u, 10, 1);
+ break;
+ }
+ case 'x':
+ case 'p':
+ {
+ unsigned u = va_arg(va, unsigned);
+ _printn(u, 16, 0);
+ break;
+ }
+ case 's':
+ {
+ char *s = va_arg(va, char *);
+ while (*s) {
+ PUTCHAR(*s);
+ s++;
+ }
+ break;
+ }
+ }
+ }
+ format++;
+ }
+}
+
+#if 0
+static void
+_char_emitter(char c, void *pData __attribute__((unused)))
+{
+ hal_putc(c);
+}
+#endif
+
+int
+printf(const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+
+ _printf(format, va);
+
+ // wrong return value...
+ return 0;
+}
+
+
+#if 0
+
+// Totally dangerous. Don't use
+static void
+_buf_emitter(char c, void *pData)
+{
+ *((*((char **)pData)))++ = c;
+}
+
+int sprintf(char *pInto, const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+
+ _printf(format, _buf_emitter, &pInto, va);
+ *pInto++ = '\0';
+
+ // FIXME wrong return value
+ return 0;
+}
+#endif
diff --git a/firmware/microblaze/lib/sd.c b/firmware/microblaze/lib/sd.c
new file mode 100644
index 000000000..d000b28ae
--- /dev/null
+++ b/firmware/microblaze/lib/sd.c
@@ -0,0 +1,197 @@
+/* -*- c -*- */
+/*
+ * Copyright 2008 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sd.h"
+#include "memory_map.h"
+#include "stdint.h"
+#include "stdio.h"
+
+static inline void
+sd_packarg(unsigned char *argument,unsigned int value)
+{
+ argument[3] = (unsigned char)(value >> 24);
+ argument[2] = (unsigned char)(value >> 16);
+ argument[1] = (unsigned char)(value >> 8);
+ argument[0] = (unsigned char)(value);
+}
+
+int
+sd_init(void)
+{
+ unsigned char response[5];
+ unsigned char argument[4];
+ int i,j;
+
+ for(i=0;i<4;i++)
+ argument[i] = 0;
+
+ // Set clock to less than 400 kHz to start out
+ sdspi_regs->clkdiv = 128;
+
+ // Delay at least 74 cycles
+ sd_assert_cs();
+ for(i = 0; i < 100; i++)
+ sd_send_byte(SD_IDLE);
+ sd_deassert_cs();
+
+ // Initialization Sequence -- CMD0 CMD55 ACMD41 CMD58
+ // Put card in idle state
+ if(sd_send_command(SD_CMD0,SD_CMD0_R,response,argument)==0)
+ return 0; // Something went wrong in command
+
+ j = 0;
+ do {
+ j++;
+ if(sd_send_command(SD_CMD55,SD_CMD55_R,response,argument)==1)
+ sd_send_command(SD_ACMD41,SD_ACMD41_R,response,argument);
+ else
+ j = SD_IDLE_WAIT_MAX;
+ }
+ while(((response[0] & SD_MSK_IDLE) == SD_MSK_IDLE) && (j < SD_IDLE_WAIT_MAX));
+
+ if(j>= SD_IDLE_WAIT_MAX) // IDLE timeout exceeded, card asleep
+ return 0;
+
+ // CMD58 reads the SD card capabilities
+ if(sd_send_command(SD_CMD58,SD_CMD58_R,response,argument)==0)
+ return 0; // CMD58 FAIL
+
+ if((response[2] & SD_MSK_OCR_33) != SD_MSK_OCR_33)
+ return 0; // Card doesn't do 3.3V
+
+ //printf("OCR = %x %x %x %x\n",response[0],response[1],response[2],response[3]);
+
+ // Set blocklen here
+ sd_packarg(argument,SD_BLOCKLEN);
+ if(sd_send_command(SD_CMD16,SD_CMD16_R,response,argument)==0)
+ return 0; // Set Blocklen failed
+
+ // Reset back to high speed
+ sdspi_regs->clkdiv = 4;
+ //puts("finished init\n");
+ return 1;
+}
+
+int sd_send_command(unsigned char cmd,unsigned char response_type,
+ unsigned char *response,unsigned char *argument)
+{
+ int i;
+ char response_length;
+ unsigned char tmp;
+
+ sd_assert_cs();
+ sd_send_byte((cmd & 0x3F) | 0x40);
+ for(i=3;i>=0;i--)
+ sd_send_byte(argument[i]);
+ sd_send_byte(SD_CRC); // Always the same
+
+ response_length = 0;
+ switch(response_type)
+ {
+ case SD_R1:
+ case SD_R1B:
+ response_length = 1;
+ break;
+ case SD_R2:
+ response_length = 2;
+ break;
+ case SD_R3:
+ response_length = 5;
+ break;
+ default:
+ break;
+ }
+
+ // Wait for a response, which will have a 0 start bit
+ i = 0;
+ do
+ {
+ tmp = sd_rcv_byte();
+ i++;
+ }
+ while(((tmp & 0x80) != 0) && i < SD_CMD_TIMEOUT);
+
+ if(i>= SD_CMD_TIMEOUT)
+ {
+ sd_deassert_cs();
+ //puts("cmd send timeout\n");
+ return 0;
+ }
+
+ for(i=response_length-1; i>=0; i--)
+ {
+ response[i] = tmp;
+ tmp = sd_rcv_byte();
+ }
+ i = 0;
+ if(response_type == SD_R1B)
+ {
+ do
+ {
+ i++;
+ tmp = sd_rcv_byte();
+ }
+ while(tmp != SD_IDLE);
+ sd_send_byte(SD_IDLE);
+ }
+
+ //puts("send cmd success\n");
+ sd_deassert_cs();
+ return 1;
+}
+
+int
+sd_read_block (unsigned int blockaddr, unsigned char *buf)
+{
+ unsigned char response[5];
+ unsigned char argument[4];
+ unsigned int i = 0;
+ unsigned char tmp;
+
+ blockaddr <<= SD_BLOCKLEN_NBITS;
+ sd_packarg(argument,blockaddr);
+ if(sd_send_command(SD_CMD17,SD_CMD17_R,response,argument)==0)
+ return 0; //Failed READ;
+ if(response[0] != 0)
+ return 0; //Misaligned READ
+
+ sd_assert_cs();
+ i = 0;
+ do
+ {
+ tmp = sd_rcv_byte();
+ i++;
+ }
+ while((tmp == 0xFF) && (i < SD_RD_TIMEOUT));
+ if((i>= SD_RD_TIMEOUT) ||((tmp & SD_MSK_TOK_DATAERROR) == 0))
+ {
+ sd_send_byte(SD_IDLE); // Send a dummy before quitting
+ return 0; // Data ERROR
+ }
+ for(i=0;i<SD_BLOCKLEN;i++)
+ buf[i] = sd_rcv_byte();
+ return 1;
+
+}
+
+int
+sd_write_block(unsigned int blockaddr, const unsigned char *buf)
+{
+ // FIXME not implemented yet
+ return 0;
+}
diff --git a/firmware/microblaze/lib/sd.h b/firmware/microblaze/lib/sd.h
new file mode 100644
index 000000000..e2d0ae38e
--- /dev/null
+++ b/firmware/microblaze/lib/sd.h
@@ -0,0 +1,122 @@
+/* -*- c -*- */
+/*
+ * Copyright 2008 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_SD_H
+#define INCLUDED_SD_H
+
+#include "memory_map.h"
+
+#define SD_READY 1
+#define SD_IDLE_WAIT_MAX 100
+#define SD_CMD_TIMEOUT 100
+#define SD_RD_TIMEOUT 1000
+
+#define SD_CMD0 0
+#define SD_CMD1 1
+#define SD_CMD9 9
+#define SD_CMD10 10
+#define SD_CMD12 12
+#define SD_CMD13 13
+#define SD_CMD16 16
+#define SD_CMD17 17
+#define SD_CMD18 18
+#define SD_CMD24 24
+#define SD_CMD25 25
+#define SD_CMD27 27
+#define SD_CMD28 28
+#define SD_CMD29 29
+#define SD_CMD30 30
+#define SD_CMD32 32
+#define SD_CMD33 33
+#define SD_CMD38 38
+#define SD_CMD55 55
+#define SD_CMD58 58
+#define SD_CMD59 59
+#define SD_ACMD41 41
+#define SD_IDLE 0xFF
+#define SD_CRC 0x95
+
+#define SD_R1 1
+#define SD_R1B 2
+#define SD_R2 3
+#define SD_R3 4
+
+#define SD_CMD0_R SD_R1
+#define SD_CMD16_R SD_R1
+#define SD_CMD17_R SD_R1
+#define SD_CMD55_R SD_R1
+#define SD_ACMD41_R SD_R1
+#define SD_CMD58_R SD_R3
+
+#define SD_BLOCKLEN 512
+#define SD_BLOCKLEN_NBITS 9
+
+#define SD_MSK_IDLE 0x01
+#define SD_MSK_OCR_33 0xC0
+#define SD_MSK_TOK_DATAERROR 0xE0
+
+
+int sd_init(void);
+
+static inline void
+sd_assert_cs(void)
+{
+ // Wait for idle before doing anything
+ while(sdspi_regs->status != SD_READY)
+ ;
+ sdspi_regs->status = 1;
+}
+
+static inline void
+sd_deassert_cs(void)
+{
+ // Wait for idle before doing anything
+ while(sdspi_regs->status != SD_READY)
+ ;
+ sdspi_regs->status = 0;
+}
+
+static inline char
+sd_rcv_byte(void)
+{
+ // Wait for idle before doing anything
+ while(sdspi_regs->status != SD_READY)
+ ;
+ sdspi_regs->send_dat = SD_IDLE;
+ while(sdspi_regs->status != SD_READY)
+ ;
+ return sdspi_regs-> receive_dat;
+}
+
+static inline void
+sd_send_byte(char dat)
+{
+ // Wait for idle before doing anything
+ while(sdspi_regs->status != SD_READY)
+ ; // Wait for status = 1 (ready)
+ sdspi_regs->send_dat = dat;
+}
+
+
+int sd_send_command(unsigned char cmd,unsigned char response_type,
+ unsigned char *response,unsigned char *argument);
+
+int sd_read_block (unsigned int blockaddr, unsigned char *buf);
+int sd_write_block(unsigned int blockaddr, const unsigned char *buf);
+
+#endif /* INCLUDED_SD_H */
diff --git a/firmware/microblaze/lib/spi.c b/firmware/microblaze/lib/spi.c
new file mode 100644
index 000000000..937397df6
--- /dev/null
+++ b/firmware/microblaze/lib/spi.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2007,2008 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "spi.h"
+#include "memory_map.h"
+
+void
+spi_init(void)
+{
+ /*
+ * f_sclk = f_wb / ((div + 1) * 2)
+ */
+ spi_regs->div = 1; // 0 = Div by 2 (25 MHz); 1 = Div-by-4 (12.5 MHz)
+}
+
+void
+spi_wait(void)
+{
+ while (spi_regs->ctrl & SPI_CTRL_GO_BSY)
+ ;
+}
+
+uint32_t
+spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags)
+{
+ flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG);
+ int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags;
+
+ spi_wait();
+
+ // Tell it which SPI slave device to access
+ spi_regs->ss = slave & 0xff;
+
+ // Data we will send
+ spi_regs->txrx0 = data;
+
+ // Run it -- write once and rewrite with GO set
+ spi_regs->ctrl = ctrl;
+ spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY;
+
+ if(readback) {
+ spi_wait();
+ return spi_regs->txrx0;
+ }
+ else
+ return 0;
+}
diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h
new file mode 100644
index 000000000..f5b69b270
--- /dev/null
+++ b/firmware/microblaze/lib/spi.h
@@ -0,0 +1,52 @@
+/* -*- c -*- */
+/*
+ * Copyright 2006,2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_SPI_H
+#define INCLUDED_SPI_H
+
+#include <memory_map.h>
+#include <stdbool.h>
+
+/*!
+ * \brief One time call to initialize SPI
+ */
+void spi_init(void);
+
+/*!
+ * \brief Wait for last SPI transaction to complete.
+ * Unless you need to know it completed, it's not necessary to call this.
+ */
+void spi_wait(void);
+
+#define SPI_TXONLY false // readback: no
+#define SPI_TXRX true // readback: yes
+
+/*
+ * Flags for spi_transact
+ */
+#define SPIF_PUSH_RISE 0 // push tx data on rising edge of SCLK
+#define SPIF_PUSH_FALL SPI_CTRL_TXNEG // push tx data on falling edge of SCLK
+#define SPIF_LATCH_RISE 0 // latch rx data on rising edge of SCLK
+#define SPIF_LATCH_FALL SPI_CTRL_RXNEG // latch rx data on falling edge of SCLK
+
+
+uint32_t
+spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags);
+
+
+#endif /* INCLUDED_SPI_H */
diff --git a/firmware/microblaze/lib/stdint.h b/firmware/microblaze/lib/stdint.h
new file mode 100644
index 000000000..b5a8611a9
--- /dev/null
+++ b/firmware/microblaze/lib/stdint.h
@@ -0,0 +1,34 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007,2009 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_STDINT_H
+#define INCLUDED_STDINT_H
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+#endif /* INCLUDED_STDINT_H */
diff --git a/firmware/microblaze/lib/stdio.h b/firmware/microblaze/lib/stdio.h
new file mode 100644
index 000000000..12a7ed0bb
--- /dev/null
+++ b/firmware/microblaze/lib/stdio.h
@@ -0,0 +1,38 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_STDIO_H
+#define INCLUDED_STDIO_H
+
+// very trimmed down stdio.h See also nonstdio.h
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+int putchar(int c);
+int puts(const char *s);
+int printf(const char *format, ...);
+
+int getchar(void);
+
+#endif /* INCLUDED_STDIO_H */
diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c
new file mode 100644
index 000000000..399d834cb
--- /dev/null
+++ b/firmware/microblaze/lib/u2_init.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "u2_init.h"
+#include "memory_map.h"
+#include "spi.h"
+#include "pic.h"
+#include "hal_io.h"
+#include "buffer_pool.h"
+#include "hal_uart.h"
+#include "i2c.h"
+#include "mdelay.h"
+#include "clocks.h"
+#include "usrp2_i2c_addr.h"
+
+//#include "nonstdio.h"
+
+unsigned char u2_hw_rev_major;
+unsigned char u2_hw_rev_minor;
+
+static inline void
+get_hw_rev(void)
+{
+ bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &u2_hw_rev_minor, 1);
+ ok &= eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &u2_hw_rev_major, 1);
+}
+
+/*
+ * We ought to arrange for this to be called before main, but for now,
+ * we require that the user's main call u2_init as the first thing...
+ */
+bool
+u2_init(void)
+{
+ // Set GPIOs to inputs, disable GPIO streaming
+ hal_gpio_set_ddr(GPIO_TX_BANK, 0x0000, 0xffff);
+ hal_gpio_set_ddr(GPIO_RX_BANK, 0x0000, 0xffff);
+
+ hal_gpio_write(GPIO_TX_BANK, 0x0000, 0xffff); // init s/w output value to zero
+ hal_gpio_write(GPIO_RX_BANK, 0x0000, 0xffff);
+
+ dsp_rx_regs->gpio_stream_enable = 0; // I, Q LSBs come from DSP
+
+ hal_io_init();
+
+ // init spi, so that we can switch over to the high-speed clock
+ spi_init();
+
+ // init i2c so we can read our rev
+ i2c_init();
+ get_hw_rev();
+
+ // set up the default clocks
+ clocks_init();
+
+ // clocks_enable_test_clk(true,1);
+
+ // Enable ADCs
+ output_regs->adc_ctrl = ADC_CTRL_ON;
+
+ // Initial values for tx and rx mux registers
+ dsp_tx_regs->tx_mux = 0x10;
+ dsp_rx_regs->rx_mux = 0x44444444;
+
+ // Set up serdes
+ output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN);
+
+ pic_init(); // progammable interrupt controller
+ bp_init(); // buffer pool
+
+ hal_enable_ints();
+
+ // flash all leds to let us know board is alive
+ hal_set_leds(0x0, 0x1f);
+ mdelay(100);
+ hal_set_leds(0x1f, 0x1f);
+ mdelay(100);
+ hal_set_leds(0x1, 0x1f); // Leave the first one on
+
+#if 0
+ // test register readback
+ int rr, vv;
+ vv = ad9777_read_reg(0);
+ printf("ad9777 reg[0] = 0x%x\n", vv);
+
+ for (rr = 0x04; rr <= 0x0d; rr++){
+ vv = ad9510_read_reg(rr);
+ printf("ad9510 reg[0x%x] = 0x%x\n", rr, vv);
+ }
+#endif
+
+ return true;
+}
diff --git a/firmware/microblaze/lib/u2_init.h b/firmware/microblaze/lib/u2_init.h
new file mode 100644
index 000000000..334791189
--- /dev/null
+++ b/firmware/microblaze/lib/u2_init.h
@@ -0,0 +1,31 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_U2_INIT_H
+#define INCLUDED_U2_INIT_H
+
+#include <stdbool.h>
+
+extern unsigned char u2_hw_rev_major;
+extern unsigned char u2_hw_rev_minor;
+
+/*!
+ * one-time init
+ */
+bool u2_init(void);
+
+#endif /* INCLUDED_U2_INIT_H */
diff --git a/firmware/microblaze/lib/usrp2_bytesex.h b/firmware/microblaze/lib/usrp2_bytesex.h
new file mode 100644
index 000000000..2b74f2a0b
--- /dev/null
+++ b/firmware/microblaze/lib/usrp2_bytesex.h
@@ -0,0 +1,66 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_USRP2_BYTESEX_H
+#define INCLUDED_USRP2_BYTESEX_H
+
+// The USRP2 speaks big-endian...
+// Use the standard include files or provide substitutions for
+// htons and friends
+
+#if defined(HAVE_ARPA_INET_H)
+#include <arpa/inet.h>
+#elif defined(HAVE_NETINET_IN_H)
+#include <netinet/in.h>
+#else
+#include <stdint.h>
+
+#ifdef WORDS_BIGENDIAN // nothing to do...
+
+static inline uint32_t htonl(uint32_t x){ return x; }
+static inline uint16_t htons(uint16_t x){ return x; }
+static inline uint32_t ntohl(uint32_t x){ return x; }
+static inline uint16_t ntohs(uint16_t x){ return x; }
+
+#else
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+
+static inline uint16_t
+bswap_16 (uint16_t x)
+{
+ return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
+}
+
+static inline uint32_t
+bswap_32 (uint32_t x)
+{
+ return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \
+ | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
+}
+#endif
+
+static inline uint32_t htonl(uint32_t x){ return bswap_32(x); }
+static inline uint16_t htons(uint16_t x){ return bswap_16(x); }
+static inline uint32_t ntohl(uint32_t x){ return bswap_32(x); }
+static inline uint16_t ntohs(uint16_t x){ return bswap_16(x); }
+
+#endif
+#endif
+#endif /* INCLUDED_USRP2_BYTESEX_H */
diff --git a/firmware/microblaze/lib/wb16550.h b/firmware/microblaze/lib/wb16550.h
new file mode 100644
index 000000000..7522f4438
--- /dev/null
+++ b/firmware/microblaze/lib/wb16550.h
@@ -0,0 +1,98 @@
+/* -*- c -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+// Wishbone National Semiconductor 16550A compatible UART
+
+#ifndef INCLUDED_WB16550_H
+#define INCLUDED_WB16550_H
+
+#include <stdint.h>
+
+typedef struct {
+ volatile uint8_t data; // 0 r/w: r: rx fifo, w: tx fifo (if DLAB: LSB of divisor)
+ volatile uint8_t ier; // 1 r/w: Interrupt Enable Register (if DLAB: MSB of divisor)
+ volatile uint8_t iir_fcr; // 2 r/w: r: Interrupt ID Register,
+ // w: Fifo Control Register
+ volatile uint8_t lcr; // 3 r/w: Line Control Register
+ volatile uint8_t mcr; // 4 w: Modem Control Register
+ volatile uint8_t lsr; // 5 r: Line Status Register
+ volatile uint8_t msr; // 6 r: Modem Status Register
+
+} wb16550_reg_t;
+
+#define UART_IER_RDI 0x01 // Enable received data interrupt
+#define UART_IER_THRI 0x02 // Enable transmitter holding reg empty int.
+#define UART_IER_RLSI 0x04 // Enable receiver line status interrupt
+#define UART_IER_MSI 0x08 // Enable modem status interrupt
+
+#define UART_IIR_NO_INT 0x01 // No interrupts pending
+#define UART_IIR_ID_MASK 0x06 // Mask for interrupt ID
+#define UART_IIR_MSI 0x00 // Modem status interrupt
+#define UART_IIR_THRI 0x02 // Tx holding register empty int
+#define UART_IIR_RDI 0x04 // Rx data available int
+#define UART_IIR_RLSI 0x06 // Receiver line status int
+
+#define UART_FCR_ENABLE_FIFO 0x01 // ignore, always enabled
+#define UART_FCR_CLEAR_RCVR 0x02 // Clear the RCVR FIFO
+#define UART_FCR_CLEAR_XMIT 0x04 // Clear the XMIT FIFO
+#define UART_FCR_TRIGGER_MASK 0xC0 // Mask for FIFO trigger range
+#define UART_FCR_TRIGGER_1 0x00 // Rx fifo trigger level: 1 byte
+#define UART_FCR_TRIGGER_4 0x40 // Rx fifo trigger level: 4 bytes
+#define UART_FCR_TRIGGER_8 0x80 // Rx fifo trigger level: 8 bytes
+#define UART_FCR_TRIGGER_14 0xC0 // Rx fifo trigger level: 14 bytes
+
+#define UART_LCR_DLAB 0x80 // Divisor latch access bit
+#define UART_LCR_SBC 0x40 // Set break control
+#define UART_LCR_SPAR 0x20 // Stick parity
+#define UART_LCR_EPAR 0x10 // Even parity select
+#define UART_LCR_PARITY 0x08 // Parity Enable
+#define UART_LCR_STOP 0x04 // Stop bits: 0=1 bit, 1=2 bits
+#define UART_LCR_WLEN5 0x00 // Wordlength: 5 bits
+#define UART_LCR_WLEN6 0x01 // Wordlength: 6 bits
+#define UART_LCR_WLEN7 0x02 // Wordlength: 7 bits
+#define UART_LCR_WLEN8 0x03 // Wordlength: 8 bits
+
+#define UART_MCR_LOOP 0x10 // Enable loopback test mode
+#define UART_MCR_OUT2n 0x08 // Out2 complement (loopback mode)
+#define UART_MCR_OUT1n 0x04 // Out1 complement (loopback mode)
+#define UART_MCR_RTSn 0x02 // RTS complement
+#define UART_MCR_DTRn 0x01 // DTR complement
+
+#define UART_LSR_TEMT 0x40 // Transmitter empty
+#define UART_LSR_THRE 0x20 // Transmit-hold-register empty
+#define UART_LSR_BI 0x10 // Break interrupt indicator
+#define UART_LSR_FE 0x08 // Frame error indicator
+#define UART_LSR_PE 0x04 // Parity error indicator
+#define UART_LSR_OE 0x02 // Overrun error indicator
+#define UART_LSR_DR 0x01 // Receiver data ready
+#define UART_LSR_BRK_ERROR_BITS 0x1E // BI, FE, PE, OE bits
+#define UART_LSR_ERROR 0x80 // At least 1 PE, FE or BI are in the fifo
+
+#define UART_MSR_DCD 0x80 // Data Carrier Detect
+#define UART_MSR_RI 0x40 // Ring Indicator
+#define UART_MSR_DSR 0x20 // Data Set Ready
+#define UART_MSR_CTS 0x10 // Clear to Send
+#define UART_MSR_DDCD 0x08 // Delta DCD
+#define UART_MSR_TERI 0x04 // Trailing edge ring indicator
+#define UART_MSR_DDSR 0x02 // Delta DSR
+#define UART_MSR_DCTS 0x01 // Delta CTS
+#define UART_MSR_ANY_DELTA 0x0F // Any of the delta bits!
+
+
+#endif // INCLUDED_WB16550_H