aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/zpu/lib
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/zpu/lib')
-rw-r--r--firmware/zpu/lib/CMakeLists.txt48
-rw-r--r--firmware/zpu/lib/_exit.c27
-rw-r--r--firmware/zpu/lib/abort.c32
-rw-r--r--firmware/zpu/lib/ad9510.c42
-rw-r--r--firmware/zpu/lib/ad9510.h30
-rw-r--r--firmware/zpu/lib/arp_cache.c90
-rw-r--r--firmware/zpu/lib/arp_cache.h33
-rw-r--r--firmware/zpu/lib/banal.c31
-rw-r--r--firmware/zpu/lib/banal.h71
-rw-r--r--firmware/zpu/lib/clocks.c121
-rw-r--r--firmware/zpu/lib/clocks.h30
-rw-r--r--firmware/zpu/lib/compiler.h26
-rw-r--r--firmware/zpu/lib/eeprom.c81
-rw-r--r--firmware/zpu/lib/eth_addrs.c106
-rw-r--r--firmware/zpu/lib/eth_mac.c121
-rw-r--r--firmware/zpu/lib/eth_mac.h32
-rw-r--r--firmware/zpu/lib/ethernet.h100
-rw-r--r--firmware/zpu/lib/ethertype.h27
-rw-r--r--firmware/zpu/lib/exit.c28
-rw-r--r--firmware/zpu/lib/hal_io.c274
-rw-r--r--firmware/zpu/lib/hal_io.h96
-rw-r--r--firmware/zpu/lib/hal_uart.c121
-rw-r--r--firmware/zpu/lib/hal_uart.h92
-rw-r--r--firmware/zpu/lib/i2c.c129
-rw-r--r--firmware/zpu/lib/i2c.h39
-rw-r--r--firmware/zpu/lib/i2c_async.c206
-rw-r--r--firmware/zpu/lib/i2c_async.h50
-rw-r--r--firmware/zpu/lib/if_arp.h153
-rw-r--r--firmware/zpu/lib/ihex.c57
-rw-r--r--firmware/zpu/lib/ihex.h18
-rw-r--r--firmware/zpu/lib/mdelay.c31
-rw-r--r--firmware/zpu/lib/mdelay.h29
-rw-r--r--firmware/zpu/lib/memcpy_wa.c42
-rw-r--r--firmware/zpu/lib/memcpy_wa.h32
-rw-r--r--firmware/zpu/lib/memory_map.h458
-rw-r--r--firmware/zpu/lib/memset_wa.c45
-rw-r--r--firmware/zpu/lib/memset_wa.h27
-rw-r--r--firmware/zpu/lib/net/eth_mac_addr.h29
-rw-r--r--firmware/zpu/lib/net/padded_eth_hdr.h37
-rw-r--r--firmware/zpu/lib/net/socket_address.h41
-rw-r--r--firmware/zpu/lib/net_common.c503
-rw-r--r--firmware/zpu/lib/net_common.h61
-rw-r--r--firmware/zpu/lib/nonstdio.c123
-rw-r--r--firmware/zpu/lib/nonstdio.h47
-rw-r--r--firmware/zpu/lib/pic.c89
-rw-r--r--firmware/zpu/lib/pic.h36
-rw-r--r--firmware/zpu/lib/pkt_ctrl.c100
-rw-r--r--firmware/zpu/lib/pkt_ctrl.h63
-rw-r--r--firmware/zpu/lib/print_addrs.c33
-rw-r--r--firmware/zpu/lib/print_buffer.c36
-rw-r--r--firmware/zpu/lib/print_rmon_regs.c44
-rw-r--r--firmware/zpu/lib/print_rmon_regs.h24
-rw-r--r--firmware/zpu/lib/printf.c134
-rw-r--r--firmware/zpu/lib/printf.c.smaller134
-rw-r--r--firmware/zpu/lib/spi.c55
-rw-r--r--firmware/zpu/lib/spi.h49
-rw-r--r--firmware/zpu/lib/stdint.h34
-rw-r--r--firmware/zpu/lib/stdio.h38
-rw-r--r--firmware/zpu/lib/u2_init.c84
-rw-r--r--firmware/zpu/lib/u2_init.h28
-rw-r--r--firmware/zpu/lib/udp_fw_update.h75
-rw-r--r--firmware/zpu/lib/udp_uart.c116
-rw-r--r--firmware/zpu/lib/udp_uart.h36
63 files changed, 5024 insertions, 0 deletions
diff --git a/firmware/zpu/lib/CMakeLists.txt b/firmware/zpu/lib/CMakeLists.txt
new file mode 100644
index 000000000..ce6b7fa44
--- /dev/null
+++ b/firmware/zpu/lib/CMakeLists.txt
@@ -0,0 +1,48 @@
+#
+# Copyright 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/>.
+#
+
+########################################################################
+SET(COMMON_SRCS
+ ${CMAKE_SOURCE_DIR}/lib/u2_init.c
+ ${CMAKE_SOURCE_DIR}/lib/abort.c
+ ${CMAKE_SOURCE_DIR}/lib/ad9510.c
+ ${CMAKE_SOURCE_DIR}/lib/clocks.c
+ ${CMAKE_SOURCE_DIR}/lib/eeprom.c
+ ${CMAKE_SOURCE_DIR}/lib/eth_addrs.c
+ ${CMAKE_SOURCE_DIR}/lib/eth_mac.c
+ ${CMAKE_SOURCE_DIR}/lib/_exit.c
+ ${CMAKE_SOURCE_DIR}/lib/exit.c
+ ${CMAKE_SOURCE_DIR}/lib/hal_io.c
+ ${CMAKE_SOURCE_DIR}/lib/hal_uart.c
+ ${CMAKE_SOURCE_DIR}/lib/i2c.c
+ ${CMAKE_SOURCE_DIR}/lib/mdelay.c
+ ${CMAKE_SOURCE_DIR}/lib/memcpy_wa.c
+ ${CMAKE_SOURCE_DIR}/lib/memset_wa.c
+ ${CMAKE_SOURCE_DIR}/lib/nonstdio.c
+ ${CMAKE_SOURCE_DIR}/lib/pic.c
+ ${CMAKE_SOURCE_DIR}/lib/pkt_ctrl.c
+ ${CMAKE_SOURCE_DIR}/lib/print_addrs.c
+ ${CMAKE_SOURCE_DIR}/lib/print_rmon_regs.c
+ ${CMAKE_SOURCE_DIR}/lib/print_buffer.c
+ ${CMAKE_SOURCE_DIR}/lib/printf.c
+ ${CMAKE_SOURCE_DIR}/lib/ihex.c
+ ${CMAKE_SOURCE_DIR}/lib/spi.c
+ ${CMAKE_SOURCE_DIR}/lib/net_common.c
+ ${CMAKE_SOURCE_DIR}/lib/arp_cache.c
+ ${CMAKE_SOURCE_DIR}/lib/banal.c
+ ${CMAKE_SOURCE_DIR}/lib/udp_uart.c
+)
diff --git a/firmware/zpu/lib/_exit.c b/firmware/zpu/lib/_exit.c
new file mode 100644
index 000000000..9b40ab2ee
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/abort.c b/firmware/zpu/lib/abort.c
new file mode 100644
index 000000000..d1d709392
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/ad9510.c b/firmware/zpu/lib/ad9510.c
new file mode 100644
index 000000000..4021a9bf7
--- /dev/null
+++ b/firmware/zpu/lib/ad9510.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012 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/>.
+ */
+
+#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, SPI_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,
+ SPI_PUSH_FALL | SPI_LATCH_FALL);
+ return r & 0xff;
+}
diff --git a/firmware/zpu/lib/ad9510.h b/firmware/zpu/lib/ad9510.h
new file mode 100644
index 000000000..a395e5223
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/arp_cache.c b/firmware/zpu/lib/arp_cache.c
new file mode 100644
index 000000000..8e14d8f17
--- /dev/null
+++ b/firmware/zpu/lib/arp_cache.c
@@ -0,0 +1,90 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009-2011 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/zpu/lib/arp_cache.h b/firmware/zpu/lib/arp_cache.h
new file mode 100644
index 000000000..e0e125d89
--- /dev/null
+++ b/firmware/zpu/lib/arp_cache.h
@@ -0,0 +1,33 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009-2011 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/zpu/lib/banal.c b/firmware/zpu/lib/banal.c
new file mode 100644
index 000000000..dfb8df355
--- /dev/null
+++ b/firmware/zpu/lib/banal.c
@@ -0,0 +1,31 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009-2011 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);
+}
diff --git a/firmware/zpu/lib/banal.h b/firmware/zpu/lib/banal.h
new file mode 100644
index 000000000..e9e55bca5
--- /dev/null
+++ b/firmware/zpu/lib/banal.h
@@ -0,0 +1,71 @@
+/* -*- c -*- */
+/*
+ * Copyright 2009-2011 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>
+
+#define dimof(x) (sizeof(x)/sizeof(x[0]))
+
+//-------------- 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);
+}
+
+#endif /* INCLUDED_BANAL_H */
diff --git a/firmware/zpu/lib/clocks.c b/firmware/zpu/lib/clocks.c
new file mode 100644
index 000000000..bc1954e13
--- /dev/null
+++ b/firmware/zpu/lib/clocks.c
@@ -0,0 +1,121 @@
+//
+// Copyright 2010-2011 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/>.
+ */
+
+#include <clocks.h>
+#include <stdbool.h>
+#include "memory_map.h"
+#include "ad9510.h"
+#include "spi.h"
+
+/*!
+ * \brief Lock Detect -- Return True if our PLL is locked
+ */
+bool clocks_lock_detect();
+
+/*!
+ * \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle.
+ */
+void clocks_enable_fpga_clk(bool enable, int divisor);
+
+void
+clocks_init(void)
+{
+ // Set up basic clocking functions in AD9510
+ ad9510_write_reg(0x45, 0x01);
+
+ //enable the 100MHz clock output to the FPGA for 50MHz CPU clock
+ clocks_enable_fpga_clk(true, 1);
+
+ //! Cannot SPI wait since SPI is on DSP clock
+ //! because DSP clock goes away until DCM reset.
+ //! However, spi is quick, the cpu is slow, its already ready...
+ //spi_wait();
+
+ //wait for the clock to stabilize
+ while(!clocks_lock_detect());
+
+ //issue a reset to the DCM so it locks up to the new freq
+ output_regs->clk_ctrl |= CLK_RESET;
+}
+
+bool
+clocks_lock_detect()
+{
+ return (pic_regs->pending & PIC_CLKSTATUS);
+}
+
+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
+
+//CHANGED: set to PECL for default behavior
+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_LVDS :
+ enable_word = enable ? 0x02 : 0x03;
+ break;
+ case CLOCK_MODE_CMOS :
+ enable_word = enable ? 0x08 : 0x09;
+ break;
+ case CLOCK_MODE_PECL :
+ default:
+ enable_word = enable ? 0x08 : 0x0A;
+ 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 1
+void
+clocks_enable_fpga_clk(bool enable, int divisor)
+{
+ clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL);
+}
diff --git a/firmware/zpu/lib/clocks.h b/firmware/zpu/lib/clocks.h
new file mode 100644
index 000000000..7bc7a3cda
--- /dev/null
+++ b/firmware/zpu/lib/clocks.h
@@ -0,0 +1,30 @@
+//
+// Copyright 2010-2011 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
+
+/*!
+ * One time call to initialize the master clock to a reasonable state.
+ * We come out of here using our free running 100MHz oscillator.
+ */
+void clocks_init(void);
+
+#endif /* INCLUDED_CLOCKS_H */
diff --git a/firmware/zpu/lib/compiler.h b/firmware/zpu/lib/compiler.h
new file mode 100644
index 000000000..f677bdc3b
--- /dev/null
+++ b/firmware/zpu/lib/compiler.h
@@ -0,0 +1,26 @@
+/* -*- 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_COMPILER_H
+#define INCLUDED_COMPILER_H
+
+// FIXME gcc specific.
+#define _AL4 __attribute__((aligned (4)))
+
+#define FORCE_INLINE inline __attribute__((always_inline))
+
+#endif /* INCLUDED_COMPILER_H */
diff --git a/firmware/zpu/lib/eeprom.c b/firmware/zpu/lib/eeprom.c
new file mode 100644
index 000000000..d4e170046
--- /dev/null
+++ b/firmware/zpu/lib/eeprom.c
@@ -0,0 +1,81 @@
+/*
+ * 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"
+#include "usrp2/fw_common.h"
+
+static const int EEPROM_PAGESIZE = 16;
+
+bool find_safe_booted_flag(void) {
+ unsigned char flag_byte;
+ eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1);
+ return (flag_byte == 0x5E);
+}
+
+void set_safe_booted_flag(bool flag) {
+ unsigned char flag_byte = flag ? 0x5E : 0xDC;
+ eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1);
+}
+
+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/zpu/lib/eth_addrs.c b/firmware/zpu/lib/eth_addrs.c
new file mode 100644
index 000000000..6d3347cf3
--- /dev/null
+++ b/firmware/zpu/lib/eth_addrs.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010-2012 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 "ethernet.h"
+#include "memory_map.h"
+#include "nonstdio.h"
+#include <stdbool.h>
+#include <string.h>
+#include "i2c.h"
+#include "usrp2/fw_common.h"
+
+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;
+}
+
+typedef struct{
+ eth_mac_addr_t mac_addr;
+ struct ip_addr ip_addr;
+ struct ip_addr gateway;
+ struct ip_addr subnet;
+} eth_addrs_t;
+
+static bool eth_addrs_initialized = false;
+
+static const eth_addrs_t default_eth_addrs = {
+ .mac_addr = {{0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff}},
+ .ip_addr = {(192 << 24 | 168 << 16 | 10 << 8 | 2 << 0)},
+ .gateway = {(192 << 24 | 168 << 16 | 10 << 8 | 1 << 0)},
+ .subnet = {(255 << 24 | 255 << 16 | 255 << 8 | 0 << 0)},
+};
+
+static eth_addrs_t current_eth_addrs;
+
+static void eth_addrs_init(void){
+ if (eth_addrs_initialized) return;
+ eth_addrs_initialized = true;
+
+ #define eth_addrs_init_x(addr, x){ \
+ const bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, addr, &current_eth_addrs.x, sizeof(current_eth_addrs.x)); \
+ if (!ok || unprogrammed(&current_eth_addrs.x, sizeof(current_eth_addrs.x))){ \
+ memcpy(&current_eth_addrs.x, &default_eth_addrs.x, sizeof(current_eth_addrs.x)); \
+ } \
+ }
+
+ eth_addrs_init_x(USRP2_EE_MBOARD_MAC_ADDR, mac_addr);
+ eth_addrs_init_x(USRP2_EE_MBOARD_IP_ADDR, ip_addr);
+ eth_addrs_init_x(USRP2_EE_MBOARD_GATEWAY, gateway);
+ eth_addrs_init_x(USRP2_EE_MBOARD_SUBNET, subnet);
+
+}
+
+const eth_mac_addr_t *ethernet_mac_addr(void){
+ eth_addrs_init();
+ return &current_eth_addrs.mac_addr;
+}
+
+const struct ip_addr *get_ip_addr(void){
+ eth_addrs_init();
+ return &current_eth_addrs.ip_addr;
+}
+
+const struct ip_addr *get_subnet(void){
+ eth_addrs_init();
+ return &current_eth_addrs.subnet;
+}
+
+const struct ip_addr *get_gateway(void){
+ eth_addrs_init();
+ return &current_eth_addrs.gateway;
+}
+
+bool set_ip_addr(const struct ip_addr *t){
+ const bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr));
+ if (ok) current_eth_addrs.ip_addr = *t;
+ return ok;
+}
+
+void eth_addrs_set_default(void){
+ eth_addrs_initialized = true;
+ memcpy(&current_eth_addrs, &default_eth_addrs, sizeof(default_eth_addrs));
+}
diff --git a/firmware/zpu/lib/eth_mac.c b/firmware/zpu/lib/eth_mac.c
new file mode 100644
index 000000000..581a5c69f
--- /dev/null
+++ b/firmware/zpu/lib/eth_mac.c
@@ -0,0 +1,121 @@
+/* -*- 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)
+{
+ /* disable because MAC_SET_PASS_ALL is set below
+ 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 | MAC_SET_PASS_ALL;
+
+ 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)
+{
+
+ 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/zpu/lib/eth_mac.h b/firmware/zpu/lib/eth_mac.h
new file mode 100644
index 000000000..73feec955
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/ethernet.h b/firmware/zpu/lib/ethernet.h
new file mode 100644
index 000000000..b5b08cb8c
--- /dev/null
+++ b/firmware/zpu/lib/ethernet.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010-2012 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/>.
+ */
+
+#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);
+
+/*!
+ * \returns IP address
+ */
+const struct ip_addr *get_ip_addr(void);
+
+/*!
+ * \returns gateway address
+ */
+const struct ip_addr *get_gateway(void);
+
+/*!
+ * \returns subnet address
+ */
+const struct ip_addr *get_subnet(void);
+
+/*!
+ * \brief write ip address to eeprom and begin using it
+ */
+bool set_ip_addr(const struct ip_addr *t);
+
+//! Apply default settings to eth addrs
+void eth_addrs_set_default(void);
+
+/*
+ * \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/zpu/lib/ethertype.h b/firmware/zpu/lib/ethertype.h
new file mode 100644
index 000000000..235981193
--- /dev/null
+++ b/firmware/zpu/lib/ethertype.h
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009-2011 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/zpu/lib/exit.c b/firmware/zpu/lib/exit.c
new file mode 100644
index 000000000..95a3bf4de
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/hal_io.c b/firmware/zpu/lib/hal_io.c
new file mode 100644
index 000000000..d4be324f5
--- /dev/null
+++ b/firmware/zpu/lib/hal_io.c
@@ -0,0 +1,274 @@
+/* -*- 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 "memory_map.h"
+#include "hal_uart.h"
+#include "hal_io.h"
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * ========================================================================
+ * 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
+fputchar(hal_uart_name_t u, int ch)
+{
+ hal_uart_putc(u, ch);
+ return ch;
+}
+
+inline int
+putchar(int ch)
+{
+ hal_uart_putc(DEFAULT_UART, ch);
+ return ch;
+}
+
+int
+fgetchar(hal_uart_name_t u)
+{
+ return hal_uart_getc(u);
+}
+
+int
+getchar(void)
+{
+ return fgetchar(DEFAULT_UART);
+}
+
+#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
+fnewline(hal_uart_name_t u)
+{
+ fputchar(u, '\n');
+}
+
+inline void
+newline(void)
+{
+ fnewline(DEFAULT_UART);
+}
+
+int
+fputstr(hal_uart_name_t u, const char *s)
+{
+ while (*s)
+ fputchar(u, *s++);
+
+ return 0;
+}
+
+int
+fnputstr(hal_uart_name_t u, const char *s, int len)
+{
+ int x = 0;
+ while (*s && (len > x++))
+ fputchar(u, *s++);
+
+ return x;
+}
+
+int
+putstr(const char *s)
+{
+ return fputstr(DEFAULT_UART, s);
+}
+
+int
+fputs(hal_uart_name_t u, const char *s)
+{
+ fputstr(u, s);
+ fputchar(u, '\n');
+ return 0;
+}
+
+int puts(const char *s)
+{
+ return fputs(DEFAULT_UART, s);
+}
+
+char *
+fgets(hal_uart_name_t u, char * const s)
+{
+ char *x = s;
+ while((*x=(char)hal_uart_getc(u)) != '\n') x++;
+ *x = 0;
+ return s;
+}
+
+int
+fngets(hal_uart_name_t u, char * const s, int len)
+{
+ char *x = s;
+ while(((*x=(char)hal_uart_getc(u)) != '\n') && ((x-s) < len)) x++;
+ *x = 0;
+ return (x-s);
+}
+
+int
+fngets_noblock(hal_uart_name_t u, char * const s, int len)
+{
+ int i;
+ for(i=0; i < len; i++) {
+ int ret = hal_uart_getc_noblock(u);
+ s[i] = (char) ret;
+ if((ret == -1) || (s[i] == '\n')) break;
+ }
+ s[i] = 0;
+
+ return i;
+}
+
+char *
+gets(char * const s)
+{
+ return fgets(DEFAULT_UART, s);
+}
+
diff --git a/firmware/zpu/lib/hal_io.h b/firmware/zpu/lib/hal_io.h
new file mode 100644
index 000000000..7a617685c
--- /dev/null
+++ b/firmware/zpu/lib/hal_io.h
@@ -0,0 +1,96 @@
+/* -*- 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"
+#include "hal_uart.h"
+
+void hal_io_init(void);
+void hal_finish();
+char *gets(char * const s);
+int fputstr(hal_uart_name_t u, const char *s);
+int fnputstr(hal_uart_name_t u, const char *s, int len);
+int fngets(hal_uart_name_t u, char * const s, int len);
+int fngets_noblock(hal_uart_name_t u, char * const s, int len);
+
+/*
+ * ------------------------------------------------------------------------
+ * 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)
+{
+ return 0; /* NOP */
+}
+
+/*!
+ * \brief Enable interrupts and return previous interrupt enable state.
+ * [Microblaze specific]
+ */
+static inline int
+hal_enable_ints(void)
+{
+ return 0; /* NOP */
+}
+
+/*!
+ * \brief Set interrupt enable state to \p prev_state.
+ * [Microblaze specific]
+ */
+static inline void
+hal_restore_ints(int prev_state)
+{
+ /* NOP */
+}
+
+#endif /* INCLUDED_HAL_IO_H */
diff --git a/firmware/zpu/lib/hal_uart.c b/firmware/zpu/lib/hal_uart.c
new file mode 100644
index 000000000..af60bed6a
--- /dev/null
+++ b/firmware/zpu/lib/hal_uart.c
@@ -0,0 +1,121 @@
+/* -*- 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 "memory_map.h"
+#include "hal_uart.h"
+#include "hal_io.h"
+#include "mdelay.h"
+
+//just to save you from going insane, note that firmware/FPGA UARTs [0-2] correspond to serial ports [1-3].
+//so in software, we refer to UART_DEBUG as UART0, but it transmits on pin TXD<1>. see the UART assignments in hal_uart.h.
+
+#define NSPEEDS 6
+#define MAX_WB_DIV 4
+
+//if you're going to recalculate the divisors, it's just uart_clock_rate / baud_rate.
+//uart_clock_rate is 50MHz for USRP2.
+static const uint16_t
+divisor_table[NSPEEDS] = {
+ 5208, // 9600
+ 2604, // 19200
+ 1302, // 38400
+ 868, // 57600
+ 434, // 115200
+ 217 // 230400
+};
+
+static char uart_mode[4] = {
+ [UART_DEBUG] = UART_MODE_ONLCR,
+ [UART_EXP] = UART_MODE_ONLCR,
+ [UART_GPS] = UART_MODE_ONLCR
+};
+
+static char uart_speeds[4] = {
+ [UART_DEBUG] = US_230400,
+ [UART_EXP] = US_230400,
+ [UART_GPS] = US_115200
+};
+
+void
+hal_uart_set_mode(hal_uart_name_t uart, int mode)
+{
+ uart_mode[uart] = mode;
+}
+
+void hal_uart_set_speed(hal_uart_name_t uart, hal_uart_speed_t speed)
+{
+ uart_regs[uart].clkdiv = divisor_table[speed];
+}
+
+void
+hal_uart_init(void)
+{
+ for(int i = 0; i < 3; i++) {
+ hal_uart_set_mode(i, uart_mode[i]);
+ hal_uart_set_speed(i, uart_speeds[i]);
+ }
+}
+
+void
+hal_uart_putc(hal_uart_name_t u, int ch)
+{
+ if ((ch == '\n') && (uart_mode[u] == UART_MODE_ONLCR)) //map \n->\r\n if necessary
+ hal_uart_putc(u, '\r');
+
+ while (uart_regs[u].txlevel == 0) // wait for fifo to have space
+ ;
+
+ uart_regs[u].txchar = ch;
+}
+
+void
+hal_uart_putc_nowait(hal_uart_name_t u, int ch)
+{
+ if ((ch == '\n') && (uart_mode[u] == UART_MODE_ONLCR)) //map \n->\r\n if necessary
+ hal_uart_putc(u, '\r');
+
+ if(uart_regs[u].txlevel) // If fifo has space
+ uart_regs[u].txchar = ch;
+}
+
+int
+hal_uart_getc(hal_uart_name_t u)
+{
+ while ((uart_regs[u].rxlevel) == 0) // wait for data to be ready
+ ;
+
+ return uart_regs[u].rxchar;
+}
+
+int
+hal_uart_getc_noblock(hal_uart_name_t u)
+{
+// int timeout = 0;
+// while (((uart_regs[u].rxlevel) == 0) && (timeout++ < HAL_UART_TIMEOUT_MS))
+// mdelay(1);
+ if(uart_regs[u].rxlevel == 0) return -1;
+ return uart_regs[u].rxchar;
+}
+
+int hal_uart_rx_flush(hal_uart_name_t u)
+{
+ char x = 0;
+ while(uart_regs[u].rxlevel) x = uart_regs[u].rxchar;
+ return x;
+}
+
diff --git a/firmware/zpu/lib/hal_uart.h b/firmware/zpu/lib/hal_uart.h
new file mode 100644
index 000000000..793aface0
--- /dev/null
+++ b/firmware/zpu/lib/hal_uart.h
@@ -0,0 +1,92 @@
+/* -*- 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 uart mode flags
+ */
+#define UART_MODE_RAW 0x0000 // no mapping on input or output
+#define UART_MODE_ONLCR 0x0001 // map \n to \r\n on output (default)
+
+#define DEFAULT_UART UART_DEBUG //which UART printf, gets, etc. use
+
+typedef enum {
+ US_9600 = 0,
+ US_19200 = 1,
+ US_38400 = 2,
+ US_57600 = 3,
+ US_115200 = 4,
+ US_230400 = 5
+} hal_uart_speed_t;
+
+typedef struct {
+ hal_uart_speed_t speed;
+} hal_uart_config_t;
+
+typedef enum {
+ UART_DEBUG = 0,
+ UART_EXP = 1,
+ UART_GPS = 2
+} hal_uart_name_t;
+
+/*
+ * \brief Set uart mode
+ */
+void hal_uart_set_mode(hal_uart_name_t uart, int flags);
+
+/*!
+ * \brief one-time call to init
+ */
+void hal_uart_init(void);
+
+/*!
+ * \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(hal_uart_name_t u, int ch);
+
+/*!
+ * \brief Enqueue \p ch for output over serial port, silent fail if queue is full
+ */
+void hal_uart_putc_nowait(hal_uart_name_t u, int ch);
+
+/*
+ * \brief Blocking read of next char from serial port
+ */
+int hal_uart_getc(hal_uart_name_t u);
+
+/*
+ * \brief Non-blocking read of next char from serial port, return -1 if nothing available
+ */
+int hal_uart_getc_noblock(hal_uart_name_t u);
+
+int hal_uart_rx_flush(hal_uart_name_t u);
+
+#endif /* INCLUDED_HAL_UART_H */
diff --git a/firmware/zpu/lib/i2c.c b/firmware/zpu/lib/i2c.c
new file mode 100644
index 000000000..d230f462c
--- /dev/null
+++ b/firmware/zpu/lib/i2c.c
@@ -0,0 +1,129 @@
+/* -*- 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"
+#include <string.h>
+#include "nonstdio.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 * 400000)) - 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; //| I2C_CTRL_IE; // enable core
+
+ //now this is done separately to maintain common code for async and sync
+ //pic_register_handler(IRQ_I2C, i2c_irq_handler);
+}
+
+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/zpu/lib/i2c.h b/firmware/zpu/lib/i2c.h
new file mode 100644
index 000000000..1af4d72df
--- /dev/null
+++ b/firmware/zpu/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>
+#include "stdint.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);
+
+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);
+
+bool find_safe_booted_flag(void);
+void set_safe_booted_flag(bool flag);
+
+#endif /* INCLUDED_I2C_H */
diff --git a/firmware/zpu/lib/i2c_async.c b/firmware/zpu/lib/i2c_async.c
new file mode 100644
index 000000000..05c4c3a09
--- /dev/null
+++ b/firmware/zpu/lib/i2c_async.c
@@ -0,0 +1,206 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+/*
+ * 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/>.
+ */
+
+ //i2c_async.c: asynchronous (interrupt-driven) routines for I2C.
+ //separated out here so we can have a small I2C lib for bootloader and
+ //retain interrupt-driven I2C for the main app.
+
+#include "memory_map.h"
+#include "stdint.h"
+#include <string.h>
+#include "pic.h"
+#include "nonstdio.h"
+#include "i2c_async.h"
+
+ //asynchronous (interrupt-driven) i2c state variables
+volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer
+volatile uint8_t *volatile i2c_bufptr = i2c_buf; //ptr to current position
+volatile uint8_t i2c_len = 0; //length remaining in current transfer
+volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state
+i2c_dir_t i2c_dir; //I2C transfer direction
+
+void (*volatile i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete
+static void i2c_irq_handler(unsigned irq);
+inline void i2c_async_err(void);
+
+void i2c_register_handler(void) {
+ pic_register_handler(IRQ_I2C, i2c_irq_handler);
+}
+
+
+static void i2c_irq_handler(unsigned irq) {
+//i2c state machine.
+
+ //printf("I2C irq handler\n");
+ //first let's make sure nothing is f'ed up
+ //TODO: uncomment this error checking when we have some way to handle errors
+// if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it
+// printf("\tNACK received\n");
+// i2c_async_err();
+// return;
+// }// else printf("\tACK received, proceeding\n");
+
+ if(i2c_regs->cmd_status & I2C_ST_AL) {
+ printf("\tArbitration lost!\n");
+ i2c_async_err();
+ return;
+ }
+
+ if(i2c_regs->cmd_status & I2C_ST_TIP) {
+ //printf("\tI2C still busy in interrupt\n");
+ return;
+ }
+
+ //now decide what to do
+ switch(i2c_state) {
+
+ case I2C_STATE_IDLE:
+ //this is an error. in idle state, we shouldn't be transferring data, and the fact that the IRQ fired is terrible bad.
+ printf("AAAAAHHHHH INTERRUPT IN THE IDLE STATE AAAHHHHHHHHH\n");
+ i2c_async_err();
+ break;
+
+ case I2C_STATE_CONTROL_BYTE_SENT: //here we've sent the control byte, and we're either clocking data in or out now, but we haven't received a byte yet.
+ case I2C_STATE_DATA: //here we're sending/receiving data and if we're receiving there's data in the data reg
+
+ //if(i2c_state == I2C_STATE_DATA) printf("\tI2C in state DATA with dir=%d and len=%d\n", i2c_dir, i2c_len);
+ //else printf("\tI2C in state CONTROL_BYTE_SENT with dir=%d and len=%d\n", i2c_dir, i2c_len);
+
+ if(i2c_dir == I2C_DIR_READ) {
+ if(i2c_state == I2C_STATE_DATA) *(i2c_bufptr++) = i2c_regs->data;
+ //printf("\tRead %x\n", *(i2c_bufptr-1));
+ //set up another data byte
+ if(i2c_len > 1) //only one more byte to transfer
+ i2c_regs->cmd_status = I2C_CMD_RD;
+ else
+ i2c_regs->cmd_status = I2C_CMD_RD | I2C_CMD_NACK | I2C_CMD_STOP;
+ }
+ else if(i2c_dir == I2C_DIR_WRITE) {
+ //write a byte
+ //printf("\tWriting %x\n", *i2c_bufptr);
+ i2c_regs->data = *(i2c_bufptr++);
+ if(i2c_len > 1)
+ i2c_regs->cmd_status = I2C_CMD_WR;
+ else {
+ //printf("\tGenerating STOP\n");
+ i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_STOP;
+ }
+ };
+ i2c_len--;
+ if(i2c_len == 0) i2c_state = I2C_STATE_LAST_BYTE;
+ else i2c_state = I2C_STATE_DATA; //takes care of the addr_sent->data transition
+ break;
+
+
+ case I2C_STATE_LAST_BYTE: //here we've already sent the last read request and the last data is waiting for us.
+ //printf("\tI2C in state LAST BYTE\n");
+
+ if(i2c_dir == I2C_DIR_READ) {
+ *(i2c_bufptr++) = i2c_regs->data;
+ //printf("\tRead %x\n", *(i2c_bufptr-1));
+ i2c_state = I2C_STATE_DATA_READY;
+ } else {
+ i2c_state = I2C_STATE_IDLE;
+ }
+ i2c_regs->ctrl &= ~I2C_CTRL_IE; //disable interrupts until next time
+
+ if(i2c_callback) {
+ i2c_callback(); //if we registered a callback, call it!
+ }
+
+ break;
+
+
+ default: //terrible things have happened.
+ break;
+ }
+
+}
+
+void i2c_register_callback(void (*volatile callback)(void)) {
+ i2c_callback = callback;
+}
+
+inline void i2c_async_err(void) {
+ i2c_state = I2C_STATE_IDLE;
+ i2c_regs->ctrl &= ~I2C_CTRL_IE;
+ printf("I2C error\n");
+//TODO: set an error flag instead of just dropping things on the floor
+ i2c_regs->cmd_status = I2C_CMD_STOP;
+}
+
+bool i2c_async_read(uint8_t addr, unsigned int len) {
+ //printf("Starting async read\n");
+ if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle
+ if(len == 0) return true; //just idiot-proofing
+ if(len > sizeof(i2c_buf)) return false;
+
+ //disable I2C interrupts and clear pending interrupts on the I2C device
+ i2c_regs->ctrl &= ~I2C_CTRL_IE;
+ i2c_regs->cmd_status |= I2C_CMD_IACK;
+
+ i2c_len = len;
+ i2c_dir = I2C_DIR_READ;
+ i2c_bufptr = i2c_buf;
+ //then set up the transfer by issuing the control byte
+ i2c_regs->ctrl |= I2C_CTRL_IE;
+ i2c_regs->data = (addr << 1) | 0x01; //7 bit addr and read bit
+ i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr
+ //update the state so the irq handler knows what's going on
+ i2c_state = I2C_STATE_CONTROL_BYTE_SENT;
+ return true;
+}
+
+bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) {
+ //printf("Starting async write\n");
+ if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle
+ if(len > sizeof(i2c_buf)) return false;
+
+ //disable I2C interrupts and clear pending interrupts on the I2C device
+ i2c_regs->ctrl &= ~I2C_CTRL_IE;
+ i2c_regs->cmd_status |= I2C_CMD_IACK;
+
+ //copy the buffer into our own if writing
+ memcpy((void *)i2c_buf, buf, len);
+
+ i2c_len = len;
+ i2c_dir = I2C_DIR_WRITE;
+ i2c_bufptr = i2c_buf;
+ //then set up the transfer by issuing the control byte
+ i2c_regs->ctrl |= I2C_CTRL_IE;
+ i2c_regs->data = (addr << 1) | 0x00; //7 bit addr and read bit
+ i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr
+ //update the state so the irq handler knows what's going on
+ i2c_state = I2C_STATE_CONTROL_BYTE_SENT;
+
+ return true;
+}
+
+//TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request.
+bool i2c_async_data_ready(void *buf) {
+ if(i2c_state == I2C_STATE_DATA_READY) {
+ i2c_state = I2C_STATE_IDLE;
+ memcpy(buf, (void *)i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this
+ //printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf);
+ return true;
+ }
+ return false;
+}
+
diff --git a/firmware/zpu/lib/i2c_async.h b/firmware/zpu/lib/i2c_async.h
new file mode 100644
index 000000000..e6095fca6
--- /dev/null
+++ b/firmware/zpu/lib/i2c_async.h
@@ -0,0 +1,50 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+/*
+ * 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_I2C_ASYNC_H
+#define INCLUDED_I2C_ASYNC_H
+
+#include <stdbool.h>
+#include "stdint.h"
+
+typedef enum { I2C_STATE_IDLE,
+ I2C_STATE_CONTROL_BYTE_SENT,
+ I2C_STATE_DATA,
+ I2C_STATE_LAST_BYTE,
+ I2C_STATE_DATA_READY,
+ I2C_STATE_ERROR
+ } i2c_state_t;
+
+typedef enum { I2C_DIR_WRITE=0, I2C_DIR_READ=1 } i2c_dir_t;
+
+bool i2c_async_read(uint8_t addr, unsigned int len);
+bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len);
+bool i2c_async_data_ready(void *);
+//static void i2c_irq_handler(unsigned irq);
+void i2c_register_callback(void (*callback)(void));
+void i2c_register_handler(void);
+
+// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard.
+// Which EEPROM is determined by i2c_addr. See i2c_addr.h
+
+bool eeprom_write_async (int i2c_addr, int eeprom_offset, const void *buf, int len, void (*callback)(void));
+bool eeprom_read_async(int i2c_addr, int eeprom_offset, void *buf, int len, void (*callback)(void));
+
+#endif /* INCLUDED_I2C_ASYNC_H */
diff --git a/firmware/zpu/lib/if_arp.h b/firmware/zpu/lib/if_arp.h
new file mode 100644
index 000000000..63519c4be
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/ihex.c b/firmware/zpu/lib/ihex.c
new file mode 100644
index 000000000..97ecf73b6
--- /dev/null
+++ b/firmware/zpu/lib/ihex.c
@@ -0,0 +1,57 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 Ettus Research LLC
+ *
+ */
+
+#include "ihex.h"
+#include <ctype.h> //man that pulls in a lot of shit
+
+//this is not safe and you should run isxdigit beforehand
+uint8_t asc2nibble(char input) {
+ if(input > 'Z') return input - 'W';
+ else if(input > '9') return input - '7';
+ else return input - '0';
+}
+
+int ihex_parse(char input[], ihex_record_t *record) {
+ //given a NULL-TERMINATED input string (use gets()) in I16HEX format, write the binary record in record. return 0 on success.
+
+ uint8_t inputlen;
+ uint8_t t, i, checksum_calc=0, checksum_read;
+
+ //first check for ":" leading character
+ if(input[0] != ':') return -1;
+
+ //then check the string for only valid ASCII ['0'-'F']
+ inputlen=1;
+ while(input[inputlen]) {
+ if( !isxdigit(input[inputlen++]) ) return -2;
+ }
+
+ //then read the length.
+ record->length = (asc2nibble(input[1]) << 4) + asc2nibble(input[2]);
+ if(input[(record->length<<1) + 11] != 0) return -3; //if we're missing a null terminator in the right place
+
+ //then read the address.
+ record->addr = (asc2nibble(input[3]) << 12) + (asc2nibble(input[4]) << 8) + (asc2nibble(input[5]) << 4) + asc2nibble(input[6]);
+
+ //then read the record type.
+ record->type = (asc2nibble(input[7]) << 4) + asc2nibble(input[8]);
+// if(record->type > 4) return -4;
+
+ //then read the data, which goes from input[9] to input[9+length*2].
+ for(i=0; i < record->length; i++) {
+ t = 9 + (i<<1);
+ record->data[i] = (asc2nibble(input[t]) << 4) + (asc2nibble(input[t + 1]));
+ checksum_calc += record->data[i]; //might as well keep a running checksum as we read
+ }
+ checksum_calc += record->length + record->type + (record->addr >> 8) + (record->addr & 0xFF); //get the rest of the data into that checksum
+ checksum_calc = ~checksum_calc + 1; //checksum is 2's complement
+
+ //now read the checksum of the record
+ checksum_read = (asc2nibble(input[9 + (record->length<<1)]) << 4) + asc2nibble(input[10 + (record->length<<1)]);
+ if(checksum_calc != checksum_read) return -5; //compare 'em
+
+ return 0;
+}
diff --git a/firmware/zpu/lib/ihex.h b/firmware/zpu/lib/ihex.h
new file mode 100644
index 000000000..9f471fbe2
--- /dev/null
+++ b/firmware/zpu/lib/ihex.h
@@ -0,0 +1,18 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 Ettus Research LLC
+ *
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct {
+ uint8_t type;
+ size_t length;
+ uint32_t addr;
+ uint8_t *data;
+} ihex_record_t;
+
+
+int ihex_parse(char input[], ihex_record_t *record);
diff --git a/firmware/zpu/lib/mdelay.c b/firmware/zpu/lib/mdelay.c
new file mode 100644
index 000000000..8f9b14112
--- /dev/null
+++ b/firmware/zpu/lib/mdelay.c
@@ -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/>.
+ */
+
+#include "mdelay.h"
+#include "memory_map.h"
+
+void mdelay(int ms){
+ if (hwconfig_simulation_p()) return;
+ for(int i = 0; i < ms; i++){
+ static const uint32_t num_ticks = MASTER_CLK_RATE/1000;
+ const uint32_t ticks_begin = router_status->time64_ticks_rb;
+ while((router_status->time64_ticks_rb - ticks_begin) < num_ticks){
+ /*NOP*/
+ }
+ }
+}
diff --git a/firmware/zpu/lib/mdelay.h b/firmware/zpu/lib/mdelay.h
new file mode 100644
index 000000000..226bbb3f7
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/memcpy_wa.c b/firmware/zpu/lib/memcpy_wa.c
new file mode 100644
index 000000000..ef20efaa9
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/memcpy_wa.h b/firmware/zpu/lib/memcpy_wa.h
new file mode 100644
index 000000000..072fc148f
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/memory_map.h b/firmware/zpu/lib/memory_map.h
new file mode 100644
index 000000000..4290ee20a
--- /dev/null
+++ b/firmware/zpu/lib/memory_map.h
@@ -0,0 +1,458 @@
+// Copyright 2010-2012 Ettus Research LLC
+/*
+ * 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/>.
+ */
+
+#ifndef INCLUDED_MEMORY_MAP_H
+#define INCLUDED_MEMORY_MAP_H
+
+#include <stdint.h>
+
+#define MASTER_CLK_RATE 100000000 // 100 MHz
+
+////////////////////////////////////////////////////////////////////////
+// Define slave bases
+////////////////////////////////////////////////////////////////////////
+#define ROUTER_RAM_BASE 0x4000
+#define SPI_BASE 0x5000
+#define I2C_BASE 0x5400
+#define GPIO_BASE 0x5800
+#define READBACK_BASE 0x5C00
+#define ETH_BASE 0x6000
+#define SETTING_REGS_BASE 0x7000
+#define PIC_BASE 0x8000
+#define UART_BASE 0x8800
+#define ATR_BASE 0x8C00
+#ifdef USRP2
+#define SDSPI_BASE 0xB000
+#endif
+#ifdef USRP2P
+#define ICAP_BASE 0xA000
+#define SPIF_BASE 0xB000
+#define RAM_BASE 0xC000
+#endif
+
+/////////////////////////////////////////////////////
+// SPI Core, Slave 2. See core docs for more info
+/////////////////////////////////////////////////////
+
+// 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
+#define SPI_SS_ADS62P44 256
+
+// 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
+////////////////////////////////////////////////
+
+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
+
+///////////////////////////////////////////////////
+// Packet Router Status, Slave 5
+///////////////////////////////////////////////////
+
+typedef struct {
+ volatile uint32_t spi;
+ volatile uint32_t _padding[7];
+ volatile uint32_t status;
+ volatile uint32_t _unused;
+ volatile uint32_t time64_secs_rb;
+ volatile uint32_t time64_ticks_rb;
+ volatile uint32_t compat_num;
+ volatile uint32_t irqs;
+} router_status_t;
+
+#define SPI_READY_IRQ (1 << 12)
+
+#define router_status ((router_status_t *) READBACK_BASE)
+#define readback_mux ((router_status_t *) READBACK_BASE) //alias with a better name
+
+/*!
+ * \brief return non-zero if we're running under the simulator
+ */
+inline static int
+hwconfig_simulation_p(void)
+{
+ return 0;
+}
+
+/*!
+ * \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 2;
+}
+
+///////////////////////////////////////////////////
+// Ethernet Core, Slave 6
+///////////////////////////////////////////////////
+
+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.
+
+#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 SR_MISC 0 // 7 regs
+#define SR_SIMTIMER 8 // 2
+#define SR_TIME64 10 // 6
+#define SR_BUF_POOL 16 // 4
+#define SR_SPI_CORE 20 // 3
+#define SR_RX_FRONT 24 // 5
+#define SR_RX_CTRL0 32 // 9
+#define SR_RX_DSP0 48 // 7
+#define SR_RX_CTRL1 80 // 9
+#define SR_RX_DSP1 96 // 7
+
+#define SR_TX_FRONT 128 // ?
+#define SR_TX_CTRL 144 // 6
+#define SR_TX_DSP 160 // 5
+
+#define SR_UDP_SM 192 // 64
+
+#define _SR_ADDR(sr) (SETTING_REGS_BASE + (sr) * sizeof(uint32_t))
+
+#define SR_ADDR_BLDRDONE _SR_ADDR(5)
+
+// --- spi core control regs ---
+
+typedef struct {
+ volatile uint32_t divider;
+ volatile uint32_t control;
+ volatile uint32_t data;
+} spi_core_t;
+
+#define SPI_CORE_SLAVE_SELECT_SHIFT 0
+#define SPI_CORE_NUM_BITS_SHIFT 24
+#define SPI_CORE_DATA_IN_EDGE_SHIFT 30
+#define SPI_CORE_DATA_OUT_EDGE_SHIFT 31
+
+#define spi_core ((spi_core_t *) _SR_ADDR(SR_SPI_CORE))
+
+// --- packet router control regs ---
+
+typedef struct {
+ volatile uint32_t mode_ctrl;
+ volatile uint32_t ip_addr;
+ volatile uint32_t data_ports; //dsp0 (low 16) dsp1 (high 16)
+ volatile uint32_t iface_ctrl;
+} router_ctrl_t;
+
+#define router_ctrl ((router_ctrl_t *) _SR_ADDR(SR_BUF_POOL))
+
+// --- 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 led_src; // HW or SW control for LEDs
+ volatile uint32_t flush_icache; // Flush the icache
+} output_regs_t;
+
+#define CLK_RESET (1<<4)
+#define CLK_ENABLE (1<<3) | (1<<2)
+#define CLK_SEL (1<<1) | (1<<0)
+
+#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_E (1 << 2)
+#define LED_D (1 << 0)
+#define LED_C (1 << 3)
+// LED_F // controlled by CPLD
+#define LED_RJ45 (1 << 5)
+
+#define output_regs ((output_regs_t *) SETTING_REGS_BASE)
+
+// --- protocol framer regs ---
+
+typedef struct{
+ struct{
+ volatile uint32_t entry[16];
+ } table[4];
+} sr_proto_framer_t;
+
+#define sr_proto_framer_regs ((sr_proto_framer_t *) _SR_ADDR(SR_UDP_SM))
+
+// --- VITA TX CTRL regs ---
+
+typedef struct {
+ volatile uint32_t _pad[4];
+ volatile uint32_t cyc_per_up;
+} sr_tx_ctrl_t;
+
+#define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL))
+
+// --- VITA RX CTRL regs ---
+typedef struct {
+ volatile uint32_t _pad[3];
+ volatile uint32_t clear;
+} sr_rx_ctrl_t;
+
+#define sr_rx_ctrl0 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL0))
+#define sr_rx_ctrl1 ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL1))
+
+// ----------------------------------------------------------------
+// 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))
+
+///////////////////////////////////////////////////////
+// Simple Programmable Interrupt Controller, Slave 8
+///////////////////////////////////////////////////////
+
+// 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_BUTTON 13
+
+#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)
+#define PIC_BUTTON IRQ_TO_MASK(IRQ_BUTTON)
+
+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
+///////////////////////////////////////////////////
+
+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
+ volatile uint32_t padding[3]; //what is this i don't even
+} uart_regs_t;
+
+#define uart_regs ((uart_regs_t *) UART_BASE)
+
+///////////////////////////////////////////////////
+// SD Card SPI interface, Slave 13
+// All regs are 8 bits wide, but are accessed as if they are 32 bits
+///////////////////////////////////////////////////
+#ifdef USRP2
+
+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)
+
+#endif //USRP2
+
+///////////////////////////////////////////////////
+// ICAP, Slave 13
+///////////////////////////////////////////////////
+#ifdef USRP2P
+
+typedef struct {
+ uint32_t icap; //only the lower 8 bits matter
+} icap_regs_t;
+
+#define icap_regs ((icap_regs_t *) ICAP_BASE)
+
+///////////////////////////////////////////////////
+// SPI Flash interface, Slave 14
+// Control register definitions are the same as SPI, so use SPI_CTRL_ASS, etc.
+// Peripheral mask not needed since bus is dedicated (CE held low)
+///////////////////////////////////////////////////
+
+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;
+} spif_regs_t;
+
+#define spif_regs ((spif_regs_t *) SPIF_BASE)
+
+#endif //USRP2P
+
+#endif /* INCLUDED_MEMORY_MAP_H */
diff --git a/firmware/zpu/lib/memset_wa.c b/firmware/zpu/lib/memset_wa.c
new file mode 100644
index 000000000..da5da21ab
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/memset_wa.h b/firmware/zpu/lib/memset_wa.h
new file mode 100644
index 000000000..46d903d53
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/net/eth_mac_addr.h b/firmware/zpu/lib/net/eth_mac_addr.h
new file mode 100644
index 000000000..01bf91988
--- /dev/null
+++ b/firmware/zpu/lib/net/eth_mac_addr.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2009-2011 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_ETH_MAC_ADDR_H
+#define INCLUDED_ETH_MAC_ADDR_H
+
+#include <stdint.h>
+
+// Ethernet MAC address
+
+typedef struct {
+ uint8_t addr[6];
+} eth_mac_addr_t;
+
+#endif /* INCLUDED_ETH_MAC_ADDR_H */
diff --git a/firmware/zpu/lib/net/padded_eth_hdr.h b/firmware/zpu/lib/net/padded_eth_hdr.h
new file mode 100644
index 000000000..df816734f
--- /dev/null
+++ b/firmware/zpu/lib/net/padded_eth_hdr.h
@@ -0,0 +1,37 @@
+/* -*- 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_PADDED_ETH_HDR_H
+#define INCLUDED_PADDED_ETH_HDR_H
+
+#include <compiler.h>
+#include <net/eth_mac_addr.h>
+
+/*!
+ * \brief Standard 14-byte ethernet header plus two leading bytes of padding.
+ *
+ * This is what a buffer contains in line 1 when using the "slow mode"
+ */
+typedef struct {
+ uint16_t pad;
+ eth_mac_addr_t dst;
+ eth_mac_addr_t src;
+ uint16_t ethertype;
+} _AL4 padded_eth_hdr_t;
+
+
+#endif /* INCLUDED_PADDED_ETH_HDR_H */
diff --git a/firmware/zpu/lib/net/socket_address.h b/firmware/zpu/lib/net/socket_address.h
new file mode 100644
index 000000000..336f30a0c
--- /dev/null
+++ b/firmware/zpu/lib/net/socket_address.h
@@ -0,0 +1,41 @@
+/* -*- c -*- */
+/*
+ * Copyright 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_SOCKET_ADDRESS_H
+#define INCLUDED_SOCKET_ADDRESS_H
+
+#include <lwip/ip_addr.h>
+
+// port and address are in network byte order
+
+typedef struct socket_address {
+ unsigned short port;
+ struct ip_addr addr;
+} socket_address_t;
+
+static inline struct socket_address
+make_socket_address(struct ip_addr addr, int port)
+{
+ struct socket_address r;
+ r.port = port;
+ r.addr = addr;
+ return r;
+}
+
+
+
+#endif /* INCLUDED_SOCKET_ADDRESS_H */
diff --git a/firmware/zpu/lib/net_common.c b/firmware/zpu/lib/net_common.c
new file mode 100644
index 000000000..9b75006d3
--- /dev/null
+++ b/firmware/zpu/lib/net_common.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2009-2012 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 <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>
+#include "pkt_ctrl.h"
+
+/***********************************************************************
+ * Constants + Globals
+ **********************************************************************/
+static const bool debug = false;
+static const size_t out_buff_size = 2048;
+static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
+#define MAX_UDP_LISTENERS 10
+
+/***********************************************************************
+ * 16-bit one's complement sum
+ **********************************************************************/
+static uint32_t chksum_buffer(
+ uint16_t *buf, size_t nshorts,
+ uint32_t initial_chksum
+){
+ uint32_t chksum = initial_chksum;
+ for (size_t i = 0; i < nshorts; i++) chksum += buf[i];
+
+ while (chksum >> 16) chksum = (chksum & 0xffff) + (chksum >> 16);
+
+ return chksum;
+}
+
+/***********************************************************************
+ * Listener registry
+ **********************************************************************/
+static eth_mac_addr_t _local_mac_addr;
+static struct ip_addr _local_ip_addr;
+void register_addrs(const eth_mac_addr_t *mac_addr, const struct ip_addr *ip_addr){
+ _local_mac_addr = *mac_addr;
+ _local_ip_addr = *ip_addr;
+}
+
+struct listener_entry {
+ unsigned short port;
+ udp_receiver_t rcvr;
+};
+
+static struct listener_entry listeners[MAX_UDP_LISTENERS];
+
+void init_udp_listeners(void){
+ for (int i = 0; i < MAX_UDP_LISTENERS; i++){
+ listeners[i].rcvr = NULL;
+ }
+}
+
+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 == NULL)
+ 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;
+ }
+}
+
+/***********************************************************************
+ * Protocol framer
+ **********************************************************************/
+void setup_framer(
+ eth_mac_addr_t eth_dst,
+ eth_mac_addr_t eth_src,
+ struct socket_address sock_dst,
+ struct socket_address sock_src,
+ size_t which
+){
+ struct {
+ padded_eth_hdr_t eth;
+ struct ip_hdr ip;
+ struct udp_hdr udp;
+ } frame;
+
+ //-- load Ethernet header --//
+ frame.eth.dst = eth_dst;
+ frame.eth.src = eth_src;
+ frame.eth.ethertype = ETHERTYPE_IPV4;
+
+ //-- load IPv4 header --//
+ IPH_VHLTOS_SET(&frame.ip, 4, 5, 0);
+ IPH_LEN_SET(&frame.ip, 0);
+ IPH_ID_SET(&frame.ip, 0);
+ IPH_OFFSET_SET(&frame.ip, IP_DF); // don't fragment
+ IPH_TTL_SET(&frame.ip, 32);
+ IPH_PROTO_SET(&frame.ip, IP_PROTO_UDP);
+ IPH_CHKSUM_SET(&frame.ip, 0);
+ frame.ip.src = sock_src.addr;
+ frame.ip.dest = sock_dst.addr;
+ IPH_CHKSUM_SET(&frame.ip, chksum_buffer(
+ (unsigned short *) &frame.ip,
+ sizeof(frame.ip)/sizeof(short), 0
+ ));
+
+ //-- load UDP header --//
+ frame.udp.src = sock_src.port;
+ frame.udp.dest = sock_dst.port;
+ frame.udp.len = 0;
+ frame.udp.chksum = 0;
+
+ //copy into the framer table registers
+ memcpy_wa((void *)(sr_proto_framer_regs->table[which].entry + 1), &frame, sizeof(frame));
+}
+
+/***********************************************************************
+ * Slow-path packet framing and transmission
+ **********************************************************************/
+/*!
+ * 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
+){
+
+ //control word for framed data
+ uint32_t ctrl_word = 0x0;
+
+ //assemble the ethernet header
+ padded_eth_hdr_t ehdr;
+ ehdr.pad = 0;
+ ehdr.dst = dst;
+ ehdr.src = _local_mac_addr;
+ ehdr.ethertype = ethertype;
+
+ //grab an out buffer and pointer
+ uint8_t *buff = (uint8_t *)pkt_ctrl_claim_outgoing_buffer();
+ uint8_t *p = buff;
+ size_t total_len = 0;
+
+ //create a list of all buffers to copy
+ const void *buffs[] = {&ctrl_word, &ehdr, buf0, buf1, buf2};
+ size_t lens[] = {sizeof(ctrl_word), sizeof(ehdr), len0, len1, (len2 + 3) & ~3};
+
+ //copy each buffer into the out buffer
+ for (size_t i = 0; i < sizeof(buffs)/sizeof(buffs[0]); i++){
+ total_len += lens[i]; //use full length (not clipped)
+ size_t bytes_remaining = out_buff_size - (size_t)(p - buff);
+ if (lens[i] > bytes_remaining) lens[i] = bytes_remaining;
+ if (lens[i] && ((lens[i] & 0x3) || (intptr_t) buffs[i] & 0x3))
+ printf("send_pkt: bad alignment of len and/or buf\n");
+ memcpy_wa(p, buffs[i], lens[i]);
+ p += lens[i];
+ }
+
+ //ensure that minimum length requirements are met
+ if (total_len < 64) total_len = 64; //60 + ctrl word
+
+ pkt_ctrl_commit_outgoing_buffer(total_len/sizeof(uint32_t));
+ if (debug) printf("sent %d bytes\n", (int)total_len);
+}
+
+void
+send_ip_pkt(struct ip_addr dst, int protocol,
+ const void *buf0, size_t len0,
+ const void *buf1, size_t len1)
+{
+ 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 */
+ IPH_TTL_SET(&ip, 32);
+ IPH_PROTO_SET(&ip, protocol);
+ IPH_CHKSUM_SET(&ip, 0);
+ ip.src = _local_ip_addr;
+ ip.dest = dst;
+
+ IPH_CHKSUM_SET(&ip, ~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_addr(&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
+ if (icmp->code == ICMP_DUR_PORT){ // port unreachable
+ //handle destination port unreachable (the host ctrl+c'd the app):
+
+ //filter out non udp data response
+ struct ip_hdr *ip = (struct ip_hdr *)(((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr));
+ struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN);
+ if (IPH_PROTO(ip) != IP_PROTO_UDP) break;
+
+ struct listener_entry *lx = find_listener_by_port(udp->src);
+ if (lx){
+ struct socket_address src = make_socket_address(ip->src, udp->src);
+ struct socket_address dst = make_socket_address(ip->dest, udp->dest);
+ lx->rcvr(src, dst, NULL, 0);
+ }
+
+ putchar('i');
+ }
+ else {
+ //printf("icmp dst unr (code: %d)", icmp->code);
+ putchar('i');
+ }
+ break;
+
+ case ICMP_ECHO:{
+ const void *icmp_data_buff = ((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr);
+ size_t icmp_data_len = len - sizeof(struct icmp_echo_hdr);
+
+ 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( //data checksum
+ (unsigned short *)icmp_data_buff,
+ icmp_data_len/sizeof(short),
+ chksum_buffer( //header checksum
+ (unsigned short *)&echo_reply,
+ sizeof(echo_reply)/sizeof(short),
+ 0)
+ );
+
+ send_ip_pkt(
+ src, IP_PROTO_ICMP,
+ &echo_reply, sizeof(echo_reply),
+ icmp_data_buff, icmp_data_len
+ );
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+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);
+}
+
+void net_common_send_arp_request(const struct ip_addr *addr){
+ struct arp_eth_ipv4 req _AL4;
+ req.ar_hrd = ARPHRD_ETHER;
+ req.ar_pro = ETHERTYPE_IPV4;
+ req.ar_hln = sizeof(eth_mac_addr_t);
+ req.ar_pln = sizeof(struct ip_addr);
+ req.ar_op = ARPOP_REQUEST;
+ memcpy(req.ar_sha, ethernet_mac_addr(), sizeof(eth_mac_addr_t));
+ memcpy(req.ar_sip, get_ip_addr(), sizeof(struct ip_addr));
+ memset(req.ar_tha, 0x00, sizeof(eth_mac_addr_t));
+ memcpy(req.ar_tip, addr, sizeof(struct ip_addr));
+
+ //send the request with a broadcast ethernet mac address
+ send_pkt(BCAST_MAC_ADDR, ETHERTYPE_ARP, &req, sizeof(req), 0, 0, 0, 0);
+}
+
+void send_gratuitous_arp(void){
+ struct arp_eth_ipv4 req _AL4;
+ req.ar_hrd = ARPHRD_ETHER;
+ req.ar_pro = ETHERTYPE_IPV4;
+ req.ar_hln = sizeof(eth_mac_addr_t);
+ req.ar_pln = sizeof(struct ip_addr);
+ req.ar_op = ARPOP_REQUEST;
+ memcpy(req.ar_sha, ethernet_mac_addr(), sizeof(eth_mac_addr_t));
+ memcpy(req.ar_sip, get_ip_addr(), sizeof(struct ip_addr));
+ memset(req.ar_tha, 0x00, sizeof(eth_mac_addr_t));
+ memcpy(req.ar_tip, get_ip_addr(), sizeof(struct ip_addr));
+
+ //send the request with a broadcast ethernet mac address
+ send_pkt(BCAST_MAC_ADDR, ETHERTYPE_ARP, &req, sizeof(req), 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_ip_addr (p->ar_sip); newline();
+ printf("ar_tha = "); print_mac_addr(p->ar_tha); newline();
+ printf("ar_tip = "); print_ip_addr (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_REPLY){
+ struct ip_addr ip_addr;
+ memcpy(&ip_addr, p->ar_sip, sizeof(ip_addr));
+ eth_mac_addr_t mac_addr;
+ memcpy(&mac_addr, p->ar_sha, sizeof(mac_addr));
+ arp_cache_update(&ip_addr, &mac_addr);
+ }
+
+ 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 (memcmp(&tip, &_local_ip_addr, sizeof(_local_ip_addr)) == 0){ // They're looking for us...
+ send_arp_reply(p, _local_mac_addr);
+ }
+}
+
+void
+handle_eth_packet(uint32_t *p, size_t nlines)
+{
+ static size_t bcount = 0;
+ if (debug) printf("===> %d\n", (int)bcount++);
+ if (debug) print_buffer(p, nlines);
+
+ padded_eth_hdr_t *eth_hdr = (padded_eth_hdr_t *)p;
+
+ if (eth_hdr->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 (eth_hdr->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;
+
+ // filter on dest ip addr (should be broadcast or for us)
+ bool is_bcast = memcmp(&eth_hdr->dst, &BCAST_MAC_ADDR, sizeof(BCAST_MAC_ADDR)) == 0;
+ bool is_my_ip = memcmp(&ip->dest, &_local_ip_addr, sizeof(_local_ip_addr)) == 0;
+ if (!is_bcast && !is_my_ip) return;
+
+ 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
+}
diff --git a/firmware/zpu/lib/net_common.h b/firmware/zpu/lib/net_common.h
new file mode 100644
index 000000000..5e6daf689
--- /dev/null
+++ b/firmware/zpu/lib/net_common.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2009-2012 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 <net/socket_address.h>
+#include <net/eth_mac_addr.h>
+
+/*!
+ * Setup an entry in the protocol framer for a UDP socket.
+ *
+ * \param eth_dst ethernet destination mac addr
+ * \param eth_src ethernet source mac addr
+ * \param sock_dst udp/ip socket destination
+ * \param sock_src udp/ip socket source
+ * \param which the index into the table
+ */
+void setup_framer(
+ eth_mac_addr_t eth_dst,
+ eth_mac_addr_t eth_src,
+ struct socket_address sock_dst,
+ struct socket_address sock_src,
+ size_t which
+);
+
+typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst,
+ unsigned char *payload, int payload_len);
+
+void init_udp_listeners(void);
+
+void register_addrs(const eth_mac_addr_t *mac_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);
+
+void send_gratuitous_arp(void);
+
+//! Send an ARP request for the given IP address
+void net_common_send_arp_request(const struct ip_addr *addr);
+
+#endif /* INCLUDED_NET_COMMON_H */
diff --git a/firmware/zpu/lib/nonstdio.c b/firmware/zpu/lib/nonstdio.c
new file mode 100644
index 000000000..4b5fa4123
--- /dev/null
+++ b/firmware/zpu/lib/nonstdio.c
@@ -0,0 +1,123 @@
+/* -*- 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();
+}
+/*
+void reverse(char s[])
+{
+ int c, i, j;
+
+ for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
+ c = s[i];
+ s[i] = s[j];
+ s[j] = c;
+ }
+}
+
+int abs(signed long value) {
+ return (value >= 0) ? value : 0-value;
+}
+
+//we'll keep the puthex functions above because they're way more lightweight. but sometimes you just want to print in decimal, you know?
+char *itoa(signed long value, char *result, int base)
+{
+ // check that the base if valid
+ if (base < 2 || base > 16) { *result = 0; return result; }
+
+ char* out = result;
+ signed long quotient = value;
+
+ do {
+ *out = hex[ abs(quotient % base) ];
+ ++out;
+ quotient /= base;
+ } while ( quotient );
+
+ // Only apply negative sign for base 10
+ if ( value < 0 && base == 10) *out++ = '-';
+
+ *out = 0;
+ reverse( result );
+
+ return result;
+
+}
+*/
+
+
diff --git a/firmware/zpu/lib/nonstdio.h b/firmware/zpu/lib/nonstdio.h
new file mode 100644
index 000000000..a47a6df6e
--- /dev/null
+++ b/firmware/zpu/lib/nonstdio.h
@@ -0,0 +1,47 @@
+//
+// Copyright 2010-2011 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/>.
+ */
+
+#ifndef INCLUDED_NONSTDIO_H
+#define INCLUDED_NONSTDIO_H
+
+#include <stdio.h>
+#include <stdint.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 void *addr);
+
+void print_ip_addr(const void *addr);
+
+void print_buffer(uint32_t *buf, size_t n);
+
+#endif /* INCLUDED_NONSTDIO_H */
diff --git a/firmware/zpu/lib/pic.c b/firmware/zpu/lib/pic.c
new file mode 100644
index 000000000..bd627ce6b
--- /dev/null
+++ b/firmware/zpu/lib/pic.c
@@ -0,0 +1,89 @@
+/* -*- 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];
+
+void
+pic_init(void)
+{
+ // uP is level triggered
+
+ pic_regs->mask = ~0; // mask all interrupts
+ pic_regs->edge_enable = PIC_ONETIME_INT | PIC_UNDERRUN_INT | PIC_OVERRUN_INT | PIC_PPS_INT;
+ pic_regs->polarity = ~0 & ~PIC_PHY_INT; // rising edge
+ pic_regs->pending = ~0; // clear all pending ints
+
+ for (int i = 0; i < NVECTORS; i++){
+ pic_vector[i] = pic_nop_handler;
+ }
+}
+
+/*
+ * This magic gets pic_interrupt_handler wired into the
+ * system interrupt handler with the appropriate prologue and
+ * epilogue.
+ */
+//FIXME zpu-gcc does not install interrupt_handler like this
+//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
+pic_nop_handler(unsigned irq)
+{
+ // nop
+}
diff --git a/firmware/zpu/lib/pic.h b/firmware/zpu/lib/pic.h
new file mode 100644
index 000000000..cfdf721f4
--- /dev/null
+++ b/firmware/zpu/lib/pic.h
@@ -0,0 +1,36 @@
+/* -*- 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 pic_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);
+
+void pic_interrupt_handler();
+
+#endif /* INCLUDED_PIC_H */
diff --git a/firmware/zpu/lib/pkt_ctrl.c b/firmware/zpu/lib/pkt_ctrl.c
new file mode 100644
index 000000000..2bbe2f843
--- /dev/null
+++ b/firmware/zpu/lib/pkt_ctrl.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010-2011 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 "pkt_ctrl.h"
+#include "memory_map.h"
+#include <nonstdio.h>
+
+//status signals from WB into PR
+#define CPU_STAT_RD_DONE (1 << 0)
+#define CPU_STAT_RD_EROR (1 << 1)
+#define CPU_STAT_RD_IDLE (1 << 2)
+
+//status signals from PR into WB
+#define CPU_STAT_WR_DONE (1 << 4)
+#define CPU_STAT_WR_EROR (1 << 5)
+#define CPU_STAT_WR_IDLE (1 << 6)
+
+//control signals from WB into PR
+#define CPU_CTRL_RD_CLEAR (1 << 0)
+#define CPU_CTRL_RD_START (1 << 1)
+
+//control signals from PR into WB
+#define CPU_CTRL_WR_CLEAR (1 << 2)
+#define CPU_CTRL_WR_START (1 << 3)
+
+void pkt_ctrl_program_inspector(
+ const struct ip_addr *ip_addr, uint16_t data_port
+){
+ router_ctrl->ip_addr = ip_addr->addr;
+ router_ctrl->data_ports = data_port;
+}
+
+void pkt_ctrl_set_routing_mode(pkt_ctrl_routing_mode_t mode){
+ //About to change the mode; ensure that we are accepting packets.
+ //The plumbing will not switch if it cannot pass an end of packet.
+ pkt_ctrl_release_incoming_buffer();
+
+ //Change the mode; this switches the valves and crossbars.
+ router_ctrl->mode_ctrl = mode;
+}
+
+static inline void cpu_stat_wait_for(int bm){
+ while((router_status->status & bm) == 0){
+ /* NOP */
+ }
+}
+
+void *pkt_ctrl_claim_incoming_buffer(size_t *num_lines){
+ uint32_t status = router_status->status;
+
+ //if done: clear the read and return the buffer
+ if (status & CPU_STAT_RD_DONE){
+ *num_lines = (router_status->status >> 16) & 0xffff;
+ return ((uint32_t *) ROUTER_RAM_BASE);
+ }
+
+ //if error: drop the packet and start a new read
+ if (status & CPU_STAT_RD_EROR){
+ putstr("E");
+ pkt_ctrl_release_incoming_buffer();
+ }
+
+ //otherwise null for nothing ready
+ return NULL;
+}
+
+void pkt_ctrl_release_incoming_buffer(void){
+ //clear, wait for idle, and start a new read
+ router_ctrl->iface_ctrl = CPU_CTRL_RD_CLEAR;
+ cpu_stat_wait_for(CPU_STAT_RD_IDLE);
+ router_ctrl->iface_ctrl = CPU_CTRL_RD_START;
+}
+
+void *pkt_ctrl_claim_outgoing_buffer(void){
+ //wait for idle and return the buffer
+ cpu_stat_wait_for(CPU_STAT_WR_IDLE);
+ return ((uint32_t *) ROUTER_RAM_BASE);
+}
+
+void pkt_ctrl_commit_outgoing_buffer(size_t num_lines){
+ //start a new write with the given length
+ router_ctrl->iface_ctrl = ((num_lines & 0xffff) << 16) | CPU_CTRL_WR_START;
+ //wait for the write to become done
+ cpu_stat_wait_for(CPU_STAT_WR_DONE);
+ router_ctrl->iface_ctrl = CPU_CTRL_WR_CLEAR;
+}
diff --git a/firmware/zpu/lib/pkt_ctrl.h b/firmware/zpu/lib/pkt_ctrl.h
new file mode 100644
index 000000000..15e4b0c4d
--- /dev/null
+++ b/firmware/zpu/lib/pkt_ctrl.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010-2011 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_PKT_CTRL_H
+#define INCLUDED_PKT_CTRL_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <lwip/ip_addr.h>
+
+typedef enum {
+ PKT_CTRL_ROUTING_MODE_SLAVE = 0,
+ PKT_CTRL_ROUTING_MODE_MASTER = 1
+} pkt_ctrl_routing_mode_t;
+
+//! Program the decision values into the packet inspector
+void pkt_ctrl_program_inspector(
+ const struct ip_addr *ip_addr, uint16_t data_port
+);
+
+//! Set the routing mode for this device
+void pkt_ctrl_set_routing_mode(pkt_ctrl_routing_mode_t mode);
+
+/*!
+ * Try to claim an incomming buffer.
+ * \param num_lines filled with the buffer size
+ * \return a pointer to the buffer memory or NULL
+ */
+void *pkt_ctrl_claim_incoming_buffer(size_t *num_lines);
+
+/*!
+ * Release the incoming buffer. Call when done.
+ */
+void pkt_ctrl_release_incoming_buffer(void);
+
+/*!
+ * Claim an outgoing buffer.
+ * \return a pointer to the buffer
+ */
+void *pkt_ctrl_claim_outgoing_buffer(void);
+
+/*!
+ * Commit the outgoing buffer.
+ * \param num_lines how many lines written.
+ */
+void pkt_ctrl_commit_outgoing_buffer(size_t num_lines);
+
+#endif /* INCLUDED_PKT_CTRL_H */
diff --git a/firmware/zpu/lib/print_addrs.c b/firmware/zpu/lib/print_addrs.c
new file mode 100644
index 000000000..fa2a49fc3
--- /dev/null
+++ b/firmware/zpu/lib/print_addrs.c
@@ -0,0 +1,33 @@
+/* -*- 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 void *addr)
+{
+ uint8_t *p = (uint8_t *)addr;
+ for(size_t i = 0; i < 6; i++){
+ if(i) putchar(':');
+ puthex8(p[i]);
+ }
+}
+
+void print_ip_addr(const void *addr){
+ uint8_t *p = (uint8_t *)addr;
+ printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+}
diff --git a/firmware/zpu/lib/print_buffer.c b/firmware/zpu/lib/print_buffer.c
new file mode 100644
index 000000000..9f9104bb5
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/print_rmon_regs.c b/firmware/zpu/lib/print_rmon_regs.c
new file mode 100644
index 000000000..6d9986909
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/print_rmon_regs.h b/firmware/zpu/lib/print_rmon_regs.h
new file mode 100644
index 000000000..44e52da84
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/printf.c b/firmware/zpu/lib/printf.c
new file mode 100644
index 000000000..45bd57cb9
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/printf.c.smaller b/firmware/zpu/lib/printf.c.smaller
new file mode 100644
index 000000000..4d858648d
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/spi.c b/firmware/zpu/lib/spi.c
new file mode 100644
index 000000000..6f2f74899
--- /dev/null
+++ b/firmware/zpu/lib/spi.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2012 Ettus Research LLC
+ * 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"
+#include "nonstdio.h"
+
+void spi_init(void)
+{
+ spi_core->divider = 10;
+}
+
+void spi_wait(void)
+{
+ while ((readback_mux->irqs & SPI_READY_IRQ) == 0){
+ //NOP
+ }
+}
+
+uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags)
+{
+ uint32_t control_word = 0;
+ control_word |= (slave << SPI_CORE_SLAVE_SELECT_SHIFT);
+ control_word |= (length << SPI_CORE_NUM_BITS_SHIFT);
+ if ((flags & SPI_PUSH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_OUT_EDGE_SHIFT);
+ if ((flags & SPI_PUSH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_OUT_EDGE_SHIFT);
+ if ((flags & SPI_LATCH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_IN_EDGE_SHIFT);
+ if ((flags & SPI_LATCH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_IN_EDGE_SHIFT);
+
+ const uint32_t data_out = data << (32 - length);
+
+ spi_wait();
+ spi_core->control = control_word;
+ spi_core->data = data_out;
+
+ if (!readback) return 0;
+
+ spi_wait();
+ return readback_mux->spi;
+}
diff --git a/firmware/zpu/lib/spi.h b/firmware/zpu/lib/spi.h
new file mode 100644
index 000000000..125e1a502
--- /dev/null
+++ b/firmware/zpu/lib/spi.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Ettus Research LLC
+ * 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 <stdbool.h>
+#include <stdint.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 SPI_PUSH_RISE (1 << 0) // push tx data on rising edge of SCLK
+#define SPI_PUSH_FALL (1 << 1) // push tx data on falling edge of SCLK
+#define SPI_LATCH_RISE (1 << 2) // latch rx data on rising edge of SCLK
+#define SPI_LATCH_FALL (1 << 3) // 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/zpu/lib/stdint.h b/firmware/zpu/lib/stdint.h
new file mode 100644
index 000000000..b5a8611a9
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/stdio.h b/firmware/zpu/lib/stdio.h
new file mode 100644
index 000000000..12a7ed0bb
--- /dev/null
+++ b/firmware/zpu/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/zpu/lib/u2_init.c b/firmware/zpu/lib/u2_init.c
new file mode 100644
index 000000000..77c8c0722
--- /dev/null
+++ b/firmware/zpu/lib/u2_init.c
@@ -0,0 +1,84 @@
+/*
+ * 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 "hal_uart.h"
+#include "i2c.h"
+#include "mdelay.h"
+#include "clocks.h"
+#include "usrp2/fw_common.h"
+#include "nonstdio.h"
+
+/*
+ * 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)
+{
+ hal_disable_ints();
+ hal_io_init();
+
+ // init spi, so that we can switch over to the high-speed clock
+ spi_init();
+
+ // set up the default clocks
+ clocks_init();
+
+ hal_uart_init();
+
+ // init i2c so we can read our rev
+ pic_init(); // progammable interrupt controller
+ i2c_init();
+ hal_enable_ints();
+
+ // flash all leds to let us know board is alive
+#ifndef BOOTLOADER
+ hal_set_led_src(0x0, 0x1f); /* software ctrl */
+ hal_set_leds(0x0, 0x1f); mdelay(300);
+ hal_set_leds(LED_E, LED_E); mdelay(300);
+ hal_set_leds(LED_C, LED_C); mdelay(300);
+ hal_set_leds(LED_A, LED_A); mdelay(300);
+ for (int i = 0; i < 3; i++){ //blink all
+ static const int blinks = LED_E | LED_C | LED_A;
+ hal_set_leds(0x0, 0x1f); mdelay(100);
+ hal_set_leds(blinks, 0x1f); mdelay(100);
+ }
+#endif
+ hal_set_led_src(0x1f & ~LED_D, 0x1f); /* hardware ctrl */
+ hal_set_leds(LED_D, 0x1f); // Leave 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
+
+ output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN);
+
+ return true;
+}
diff --git a/firmware/zpu/lib/u2_init.h b/firmware/zpu/lib/u2_init.h
new file mode 100644
index 000000000..848bd88de
--- /dev/null
+++ b/firmware/zpu/lib/u2_init.h
@@ -0,0 +1,28 @@
+/* -*- 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>
+
+/*!
+ * one-time init
+ */
+bool u2_init(void);
+
+#endif /* INCLUDED_U2_INIT_H */
diff --git a/firmware/zpu/lib/udp_fw_update.h b/firmware/zpu/lib/udp_fw_update.h
new file mode 100644
index 000000000..d98447aef
--- /dev/null
+++ b/firmware/zpu/lib/udp_fw_update.h
@@ -0,0 +1,75 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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/>.
+ */
+
+#include "net_common.h"
+
+#define USRP2_UDP_UPDATE_PORT 49154
+
+typedef enum {
+ USRP2_FW_UPDATE_ID_WAT = ' ',
+
+ USRP2_FW_UPDATE_ID_OHAI_LOL = 'a',
+ USRP2_FW_UPDATE_ID_OHAI_OMG = 'A',
+
+ USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = 'f',
+ USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = 'F',
+
+ USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = 'e',
+ USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = 'E',
+
+ USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = 'd',
+ USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = 'D',
+ USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = 'B',
+
+ USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = 'w',
+ USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = 'W',
+
+ USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = 'r',
+ USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = 'R',
+
+ USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = 's',
+ USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = 'S',
+
+ USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL = 'v',
+ USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG = 'V',
+
+ USRP2_FW_UPDATE_ID_KTHXBAI = '~'
+
+} usrp2_fw_update_id_t;
+
+typedef struct {
+ uint32_t proto_ver;
+ uint32_t id;
+ uint32_t seq;
+ union {
+ uint32_t ip_addr;
+ uint32_t hw_rev;
+ struct {
+ uint32_t flash_addr;
+ uint32_t length;
+ uint8_t data[256];
+ } flash_args;
+ struct {
+ uint32_t sector_size_bytes;
+ uint32_t memory_size_bytes;
+ } flash_info_args;
+ } data;
+} usrp2_fw_update_data_t;
+
+void handle_udp_fw_update_packet(struct socket_address src, struct socket_address dst,
+ unsigned char *payload, int payload_len);
diff --git a/firmware/zpu/lib/udp_uart.c b/firmware/zpu/lib/udp_uart.c
new file mode 100644
index 000000000..a3940c05f
--- /dev/null
+++ b/firmware/zpu/lib/udp_uart.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011 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 "udp_uart.h"
+#include "hal_uart.h"
+#include "net_common.h"
+#include "compiler.h"
+#include <stdbool.h>
+
+/***********************************************************************
+ * Constants
+ **********************************************************************/
+#define MAX_NUM_UARTS 4
+#ifndef UDP_UART_MASK
+ #error missing definition for UDP_UART_MASK enable mask
+#endif
+static const size_t num_idle_cyc_b4_flush = 11; //small but lucky number
+
+/***********************************************************************
+ * Globals
+ **********************************************************************/
+static uint16_t _base_port;
+
+typedef struct{
+ struct socket_address dst;
+ _AL4 uint8_t buf[256];
+ size_t len; //length of buffer
+ size_t cyc; //idle cycle count
+} udp_uart_state_t;
+
+static udp_uart_state_t _states[MAX_NUM_UARTS];
+
+/***********************************************************************
+ * UDP handler for UARTs
+ **********************************************************************/
+static void handle_uart_data_packet(
+ struct socket_address src, struct socket_address dst,
+ unsigned char *payload, int payload_len
+){
+ //handle ICMP destination unreachable
+ if (payload == NULL){
+ const size_t which = src.port-_base_port;
+ if (which >= MAX_NUM_UARTS) return;
+ _states[which].dst.port = 0;
+ }
+
+ //handle a regular blocking UART write
+ else{
+ const size_t which = dst.port-_base_port;
+ if (which >= MAX_NUM_UARTS) return;
+ _states[which].dst = src;
+ for (size_t i = 0; i < payload_len; i++){
+ hal_uart_putc((hal_uart_name_t)which, (int)payload[i]);
+ }
+ }
+}
+
+/***********************************************************************
+ * Public init function
+ **********************************************************************/
+void udp_uart_init(const uint16_t base_port){
+ _base_port = base_port;
+ for(size_t i = 0; i < MAX_NUM_UARTS; i++){
+ _states[i].dst.port = 0; //reset to null port
+ _states[i].len = 0;
+ _states[i].cyc = 0;
+ register_udp_listener(_base_port+i, handle_uart_data_packet);
+ }
+}
+
+/***********************************************************************
+ * Public poll function
+ **********************************************************************/
+void udp_uart_poll(void){
+ for (size_t i = 0; i < MAX_NUM_UARTS; i++){
+ if (((UDP_UART_MASK) & (1 << i)) == 0) continue;
+
+ bool newline = false;
+ udp_uart_state_t *state = &_states[i];
+
+ //read all characters we can without blocking
+ for (size_t j = state->len; j < sizeof(_states[0].buf); j++){
+ int ret = hal_uart_getc_noblock((hal_uart_name_t)i);
+ if (ret == -1) break;
+ char ch = (char) ret;
+ if (ch == '\n' || ch == '\r') newline = true;
+ state->buf[j] = ch;
+ state->len++;
+ state->cyc = 0; //reset idle cycles
+ }
+
+ //nothing in buffer, continue to next uart
+ if (state->len == 0) continue;
+
+ //send out a message if newline or forced flush
+ if (newline || state->cyc++ > num_idle_cyc_b4_flush){
+ if (state->dst.port != 0) send_udp_pkt(_base_port+i, state->dst, state->buf, state->len);
+ state->len = 0;
+ state->cyc = 0;
+ }
+ }
+}
diff --git a/firmware/zpu/lib/udp_uart.h b/firmware/zpu/lib/udp_uart.h
new file mode 100644
index 000000000..d448e7611
--- /dev/null
+++ b/firmware/zpu/lib/udp_uart.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 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_UDP_UART_H
+#define INCLUDED_UDP_UART_H
+
+#include <stdint.h>
+
+/*!
+ * Initialize the UDP/UART module.
+ * Registers handler into the network.
+ * \param base_port the source port for UART0
+ */
+void udp_uart_init(const uint16_t base_port);
+
+/*!
+ * Polls the UART state machine,
+ * and sends messages over UDP.
+ */
+void udp_uart_poll(void);
+
+#endif /* INCLUDED_UDP_UART_H */