summaryrefslogtreecommitdiffstats
path: root/firmware/microblaze/lib
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/microblaze/lib')
-rw-r--r--firmware/microblaze/lib/Makefile.inc48
-rw-r--r--firmware/microblaze/lib/bootconfig.c101
-rw-r--r--firmware/microblaze/lib/clock_bits.h55
-rw-r--r--firmware/microblaze/lib/clocks.h2
-rw-r--r--firmware/microblaze/lib/compiler.h25
-rw-r--r--firmware/microblaze/lib/ethernet.c11
-rw-r--r--firmware/microblaze/lib/gdbstub2.c506
-rw-r--r--firmware/microblaze/lib/gdbstub2.h25
-rw-r--r--firmware/microblaze/lib/hal_io.c10
-rw-r--r--firmware/microblaze/lib/hal_io.h1
-rw-r--r--firmware/microblaze/lib/hal_uart.c13
-rw-r--r--firmware/microblaze/lib/hal_uart.h10
-rw-r--r--firmware/microblaze/lib/ihex.c57
-rw-r--r--firmware/microblaze/lib/ihex.h18
-rw-r--r--firmware/microblaze/lib/loader_parser.c324
-rw-r--r--firmware/microblaze/lib/loader_parser.h38
-rw-r--r--firmware/microblaze/lib/net/.gitignore2
-rw-r--r--firmware/microblaze/lib/net/eth_mac_addr.h29
-rw-r--r--firmware/microblaze/lib/net/padded_eth_hdr.h37
-rw-r--r--firmware/microblaze/lib/net/socket_address.h41
-rw-r--r--firmware/microblaze/lib/nonstdio.c43
-rw-r--r--firmware/microblaze/lib/nonstdio.h10
-rw-r--r--firmware/microblaze/lib/spi.h18
-rw-r--r--firmware/microblaze/lib/u2_init.c8
-rw-r--r--firmware/microblaze/lib/udp_burner_packet.c38
-rw-r--r--firmware/microblaze/lib/udp_burner_packet.h28
-rw-r--r--firmware/microblaze/lib/xilinx_s3_icap.c101
27 files changed, 1581 insertions, 18 deletions
diff --git a/firmware/microblaze/lib/Makefile.inc b/firmware/microblaze/lib/Makefile.inc
new file mode 100644
index 000000000..0e88298b8
--- /dev/null
+++ b/firmware/microblaze/lib/Makefile.inc
@@ -0,0 +1,48 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+# Copyright 2007 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+COMMON_SRCS = \
+ $(top_srcdir)/lib/u2_init.c \
+ $(top_srcdir)/lib/abort.c \
+ $(top_srcdir)/lib/ad9510.c \
+ $(top_srcdir)/lib/bsm12.c \
+ $(top_srcdir)/lib/buffer_pool.c \
+ $(top_srcdir)/lib/dbsm.c \
+ $(top_srcdir)/lib/eeprom.c \
+ $(top_srcdir)/lib/ethernet.c \
+ $(top_srcdir)/lib/eth_mac.c \
+ $(top_srcdir)/lib/_exit.c \
+ $(top_srcdir)/lib/exit.c \
+ $(top_srcdir)/lib/hal_io.c \
+ $(top_srcdir)/lib/hal_uart.c \
+ $(top_srcdir)/lib/i2c.c \
+ $(top_srcdir)/lib/mdelay.c \
+ $(top_srcdir)/lib/memcpy_wa.c \
+ $(top_srcdir)/lib/memset_wa.c \
+ $(top_srcdir)/lib/nonstdio.c \
+ $(top_srcdir)/lib/pic.c \
+ $(top_srcdir)/lib/print_mac_addr.c \
+ $(top_srcdir)/lib/print_rmon_regs.c \
+ $(top_srcdir)/lib/print_buffer.c \
+ $(top_srcdir)/lib/printf.c \
+ $(top_srcdir)/lib/ihex.c \
+ $(top_srcdir)/lib/spi.c \
+ $(top_srcdir)/lib/net_common.c \
+ $(top_srcdir)/lib/arp_cache.c \
+ $(top_srcdir)/lib/banal.c
diff --git a/firmware/microblaze/lib/bootconfig.c b/firmware/microblaze/lib/bootconfig.c
new file mode 100644
index 000000000..93adc05c2
--- /dev/null
+++ b/firmware/microblaze/lib/bootconfig.c
@@ -0,0 +1,101 @@
+/* -*- c -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "bootconfig.h"
+#include "bootconfig_private.h"
+#include <stdint.h>
+#include <stddef.h>
+#include <i2c.h>
+#include <quadradio/i2c_addr.h>
+#include <mdelay.h>
+#include <xilinx_v5_icap.h>
+#include <nonstdio.h>
+
+eeprom_boot_info_t eeprom_shadow;
+
+static eeprom_boot_info_t eeprom_default = {
+ .magic = EEPROM_BOOT_INFO_MAGIC,
+ .nattempts = 1,
+ .next_boot.fpga_image_number = 0,
+ .next_boot.firmware_image_number = 0,
+ .default_boot.fpga_image_number = 0,
+ .default_boot.firmware_image_number = 0
+};
+
+eeprom_boot_info_t *
+_bc_get_eeprom_shadow(void)
+{
+ return &eeprom_shadow;
+}
+
+
+bool
+_bc_write_eeprom_shadow(void)
+{
+ return eeprom_write(I2C_ADDR_MBOARD, BOOT_INFO_OFFSET, &eeprom_shadow, sizeof(eeprom_shadow));
+}
+
+void
+bootconfig_init(void)
+{
+ if (!eeprom_read(I2C_ADDR_MBOARD, BOOT_INFO_OFFSET, &eeprom_shadow, sizeof(eeprom_shadow))
+ || eeprom_shadow.magic != EEPROM_BOOT_INFO_MAGIC){
+ eeprom_shadow = eeprom_default;
+ _bc_write_eeprom_shadow();
+ }
+}
+
+bootconfig_t
+bootconfig_get_default(void)
+{
+ return eeprom_shadow.default_boot;
+}
+
+bool
+bootconfig_set_default(bootconfig_t bc)
+{
+ if (!validate_bootconfig(bc))
+ return false;
+
+ eeprom_shadow.default_boot = bc;
+ eeprom_shadow.next_boot = bc;
+ return _bc_write_eeprom_shadow();
+}
+
+void
+bootconfig_boot(bootconfig_t bc)
+{
+ if (!validate_bootconfig(bc))
+ return;
+
+ eeprom_shadow.next_boot = bc;
+ eeprom_shadow.nattempts = 1;
+ _bc_write_eeprom_shadow();
+
+ if (1){
+ puts("\nbootconfig: chaining to FPGA slot 0 bootloader");
+ mdelay(100);
+ }
+
+ while (1){
+ // Reload fpga with code from SPI flash address 0x0.
+ icap_reload_fpga(0x00000000);
+ }
+}
diff --git a/firmware/microblaze/lib/clock_bits.h b/firmware/microblaze/lib/clock_bits.h
new file mode 100644
index 000000000..d2052e941
--- /dev/null
+++ b/firmware/microblaze/lib/clock_bits.h
@@ -0,0 +1,55 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+/*
+ * 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.
+ */
+#ifndef INCLUDED_USRP2_CLOCK_BITS_H
+#define INCLUDED_USRP2_CLOCK_BITS_H
+
+#define _MC_WE_LOCK 0x0001
+#define _MC_MIMO_CLK_INPUT 0x0002 // else SMA input
+
+/*
+ * Derived masks (use these):
+ *
+ * We get our input from 1 of three places:
+ * Our free running oscilator, our SMA connector, or from the MIMO connector
+ */
+#define MC_WE_DONT_LOCK 0x0000
+#define MC_WE_LOCK_TO_SMA (_MC_WE_LOCK | 0)
+#define MC_WE_LOCK_TO_MIMO (_MC_WE_LOCK | _MC_MIMO_CLK_INPUT)
+
+/*
+ * Independent of the source of the clock, we may or may not drive our
+ * clock onto the mimo connector. Note that there are dedicated clock
+ * signals in each direction, so disaster doesn't occurs if we're
+ * unnecessarily providing clock.
+ */
+#define MC_PROVIDE_CLK_TO_MIMO 0x0004
+
+#define MC_REF_CLK_MASK 0x0f
+
+#define MC_PPS_SOURCE_SMA (0x00 << 4)
+#define MC_PPS_SOURCE_MIMO (0x01 << 4)
+
+#define MC_PPS_POLARITY_NEG (0x00 << 5)
+#define MC_PPS_POLARITY_POS (0x01 << 5)
+
+#endif /* INCLUDED_USRP2_CLOCK_BITS_H */
diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h
index 43d5a05c2..a285e03dd 100644
--- a/firmware/microblaze/lib/clocks.h
+++ b/firmware/microblaze/lib/clocks.h
@@ -26,7 +26,7 @@
*/
#include <stdbool.h>
-#include <usrp2_clock_bits.h>
+#include "clock_bits.h"
/*!
diff --git a/firmware/microblaze/lib/compiler.h b/firmware/microblaze/lib/compiler.h
new file mode 100644
index 000000000..4fa9b49f8
--- /dev/null
+++ b/firmware/microblaze/lib/compiler.h
@@ -0,0 +1,25 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_COMPILER_H
+#define INCLUDED_COMPILER_H
+
+// FIXME gcc specific.
+#define _AL4 __attribute__((aligned (4)))
+
+
+#endif /* INCLUDED_COMPILER_H */
diff --git a/firmware/microblaze/lib/ethernet.c b/firmware/microblaze/lib/ethernet.c
index 34a3ad7c1..2d7c4d7bd 100644
--- a/firmware/microblaze/lib/ethernet.c
+++ b/firmware/microblaze/lib/ethernet.c
@@ -25,8 +25,7 @@
#include "nonstdio.h"
#include <stdbool.h>
#include "i2c.h"
-#include "usrp2_i2c_addr.h"
-
+#include "usrp2/fw_common.h"
#define VERBOSE 0
@@ -302,7 +301,7 @@ ethernet_mac_addr(void)
return &src_mac_addr;
eth_mac_addr_t tmp;
- bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp, sizeof(tmp));
+ bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp));
if (!ok || unprogrammed(&tmp, sizeof(tmp))){
// use the default
}
@@ -316,7 +315,7 @@ ethernet_mac_addr(void)
bool
ethernet_set_mac_addr(const eth_mac_addr_t *t)
{
- bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t));
+ bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t));
if (ok){
src_mac_addr = *t;
src_mac_addr_initialized = true;
@@ -344,7 +343,7 @@ const struct ip_addr *get_ip_addr(void)
return &src_ip_addr;
struct ip_addr tmp;
- bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, &tmp, sizeof(tmp));
+ bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp));
if (!ok || unprogrammed(&tmp, sizeof(tmp))){
// use the default
}
@@ -356,7 +355,7 @@ const struct ip_addr *get_ip_addr(void)
}
bool set_ip_addr(const struct ip_addr *t){
- bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, t, sizeof(struct ip_addr));
+ bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr));
if (ok){
src_ip_addr = *t;
src_ip_addr_initialized = true;
diff --git a/firmware/microblaze/lib/gdbstub2.c b/firmware/microblaze/lib/gdbstub2.c
new file mode 100644
index 000000000..4c63dfce2
--- /dev/null
+++ b/firmware/microblaze/lib/gdbstub2.c
@@ -0,0 +1,506 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Implement a eensy weensy part of the GDB Remote Serial Protocol
+ *
+ * See Appendix D of the GDB manual
+ *
+ * m<addr>,<length> -- read <length> bytes of memory starting at <addr>
+ * Reply:
+ * XX... XX... is memory contents in hex
+ * ENN ENN NN is a hex error number
+ *
+ * M<addr>,<length>:XX... -- write memory, data in hex
+ * Reply:
+ * OK for success
+ * ENN for an error. NN is a hex error number
+ *
+ * X<addr>,<length>:XX... -- write memory, data in binary
+ * Reply:
+ * OK for success
+ * ENN for an error. NN is a hex error number
+ *
+ * c<addr> -- continue. <addr> is the address to resume (goto).
+ * Reply: <none>
+ *
+ * \x80 New Format...
+ */
+
+#include "gdbstub2.h"
+#include "loader_parser.h"
+#include "hal_uart.h"
+#include <stdbool.h>
+#include <stddef.h>
+
+#define MAX_PACKET 1024
+
+/*
+ * Get raw character from serial port, no echo.
+ */
+static inline int
+gdb_getc(void)
+{
+ return hal_uart_getc();
+}
+
+/*
+ * Put character to serial port. Raw output.
+ */
+static inline void
+gdb_putc(int ch)
+{
+ hal_uart_putc(ch);
+}
+
+// ------------------------------------------------------------------------
+
+#define GDB_ESCAPE 0x7d
+
+static unsigned char hex_table[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+static int
+put_hex8_checksum(int ch, int checksum)
+{
+ unsigned char t = hex_table[(ch >> 4) & 0xf];
+ checksum += t;
+ gdb_putc(t);
+
+ t = hex_table[ch & 0xf];
+ checksum += t;
+ gdb_putc(t);
+ return checksum;
+}
+
+static void
+put_hex8(int ch)
+{
+ put_hex8_checksum(ch, 0);
+}
+
+static bool
+hex4_to_bin(int ch, int *value)
+{
+ if ('0' <= ch && ch <= '9'){
+ *value = ch - '0';
+ return true;
+ }
+ if ('a' <= ch && ch <= 'f'){
+ *value = ch - 'a' + 10;
+ return true;
+ }
+ if ('A' <= ch && ch <= 'F'){
+ *value = ch - 'A' + 10;
+ return true;
+ }
+ *value = 0;
+ return false;
+}
+
+static bool
+hex8_to_bin(const unsigned char *s, int *value)
+{
+ int v0, v1;
+ if (hex4_to_bin(s[0], &v0) && hex4_to_bin(s[1], &v1)){
+ *value = (v0 << 4) | v1;
+ return true;
+ }
+ return false;
+}
+
+static bool
+hex_to_bin_array(unsigned char *binary_data, const unsigned char *hex_data, size_t nbytes)
+{
+ for (size_t i = 0; i < nbytes; i++){
+ int t;
+ if (!hex8_to_bin(&hex_data[2*i], &t))
+ return false;
+ binary_data[i] = t;
+ }
+ return true;
+}
+
+static bool
+needs_escaping(int ch)
+{
+ return ch == '$' || ch == '#' || ch == GDB_ESCAPE;
+}
+
+/*
+ * \brief Wait for a packet.
+ * \param[out] pkt_buf gets the received packet payload.
+ * \param[in] max_size is the maximum number of bytes to write into \p pkt_buf.
+ * \param[out] actual_size is the number of bytes written to \p pkt_buf.
+ *
+ * \returns true iff the payload fits and the checksum is OK.
+ *
+ * Packets have this format:
+ *
+ * $<packet-data>#<checksum>
+ *
+ * Where <packet-data> is anything and <checksum> is a two byte hex
+ * checksum. In <packet-data> '$', '#' and 0x7d are escaped with 0x7d.
+ * The checksum is computed as the modulo 256 sum of all characters
+ * btween the leading '$' and the trailing '#' (an 8-bit unsigned
+ * checksum).
+ */
+static bool
+get_packet(unsigned char *pkt_buf, size_t max_size, size_t *actual_size)
+{
+ typedef enum states {
+ LOOKING_FOR_DOLLAR,
+ LOOKING_FOR_HASH,
+ CSUM1,
+ CSUM2,
+ } state_t;
+
+ *actual_size = 0;
+ unsigned char csum[2] = {0, 0};
+ state_t state = LOOKING_FOR_DOLLAR;
+ size_t pi = 0;
+
+ while (1){
+ int ch = gdb_getc();
+
+ switch (state){
+ case LOOKING_FOR_DOLLAR:
+ if (ch == '$'){
+ pi = 0;
+ state = LOOKING_FOR_HASH;
+ }
+ else if (ch == '#'){ // most likely missed the $
+ return false;
+ }
+ break;
+
+ case LOOKING_FOR_HASH:
+ if (ch == '$'){
+ return false;
+ }
+ else if (ch == '#'){
+ state = CSUM1;
+ }
+ else {
+ if (pi >= max_size) // payload too big
+ return false;
+
+ if (ch == GDB_ESCAPE)
+ ch = gdb_getc();
+
+ pkt_buf[pi++] = ch;
+ }
+ break;
+
+ case CSUM1:
+ csum[0] = ch;
+ state = CSUM2;
+ break;
+
+ case CSUM2:
+ csum[1] = ch;
+ *actual_size = pi;
+
+ // accept .. as a correct checksum
+ if (csum[0] == '.' && csum[1] == '.')
+ return true;
+
+ int expected_checksum;
+ if (!hex8_to_bin(csum, &expected_checksum))
+ return false;
+
+ int checksum = 0;
+ for (size_t i = 0; i < pi; i++)
+ checksum += pkt_buf[i];
+
+ checksum &= 0xff;
+ return checksum == expected_checksum;
+ }
+ }
+}
+
+static void
+put_packet_trailer(int checksum)
+{
+ gdb_putc('#');
+ put_hex8(checksum & 0xff);
+ gdb_putc('\r');
+ gdb_putc('\n');
+}
+
+static void
+put_packet(const unsigned char *pkt_buf, size_t size)
+{
+ gdb_putc('$');
+
+ int checksum = 0;
+ for (size_t i = 0; i < size; i++){
+ int ch = pkt_buf[i];
+ if (needs_escaping(ch))
+ gdb_putc(GDB_ESCAPE);
+ gdb_putc(ch);
+ checksum += ch;
+ }
+ put_packet_trailer(checksum);
+}
+
+/*!
+ * Read a hex number
+ *
+ * \param[inout] bufptr - pointer to pointer to buffer (updated on return)
+ * \param[in] end - one past end of valid data in buf
+ * \param[out] value - the parsed value
+ *
+ * \returns true iff a valid hex number was read from bufptr
+ */
+static bool
+parse_number(const unsigned char **bufptr, const unsigned char *end, unsigned int *value)
+{
+ const unsigned char *buf = *bufptr;
+ unsigned int v = 0;
+ bool valid = false;
+ int nibble;
+
+ while (buf < end && hex4_to_bin(*buf, &nibble)){
+ valid = true;
+ v = (v << 4) | nibble;
+ buf++;
+ }
+
+ *value = v;
+ *bufptr = buf;
+ return valid;
+}
+
+static bool
+parse_char(const unsigned char **bufptr, const unsigned char *end, unsigned char *ch)
+{
+ const unsigned char *buf = *bufptr;
+ if (buf < end){
+ *ch = *buf++;
+ *bufptr = buf;
+ return true;
+ }
+ return false;
+}
+
+static bool
+expect_char(const unsigned char **bufptr, const unsigned char *end, unsigned char expected)
+{
+ unsigned char ch;
+ return parse_char(bufptr, end, &ch) && ch == expected;
+}
+
+static bool
+expect_end(const unsigned char **bufptr, const unsigned char *end)
+{
+ return *bufptr == end;
+}
+
+static bool
+parse_addr_length(const unsigned char **bufptr, const unsigned char *end,
+ unsigned int *addr, unsigned int *length)
+{
+ return (parse_number(bufptr, end, addr)
+ && expect_char(bufptr, end, ',')
+ && parse_number(bufptr, end, length));
+}
+
+static void
+put_error(int error)
+{
+ unsigned char buf[3];
+ buf[0] = 'E';
+ buf[1] = hex_table[(error >> 4) & 0xf];
+ buf[2] = hex_table[error & 0xf];
+
+ put_packet(buf, sizeof(buf));
+}
+
+static void
+put_ok(void)
+{
+ const unsigned char buf[2] = "OK";
+ put_packet(buf, sizeof(buf));
+}
+
+/*
+ * Read memory and send the reply.
+ * We do it on the fly so that our packet size is effectively unlimited
+ */
+static void
+read_memory(unsigned int addr, unsigned int nbytes)
+{
+ int checksum = 0;
+ gdb_putc('$');
+
+ if ((addr & 0x3) == 0 && (nbytes & 0x3) == 0){ // word aligned
+ union {
+ unsigned int i;
+ unsigned char c[4];
+ } u;
+
+ unsigned int *p = (unsigned int *) addr;
+ unsigned int length = nbytes / 4;
+
+ for (unsigned int i = 0; i < length; i++){
+ u.i = p[i]; // do a word read
+ checksum = put_hex8_checksum(u.c[0], checksum);
+ checksum = put_hex8_checksum(u.c[1], checksum);
+ checksum = put_hex8_checksum(u.c[2], checksum);
+ checksum = put_hex8_checksum(u.c[3], checksum);
+ }
+ }
+ else { // byte aligned
+ unsigned char *p = (unsigned char *) addr;
+ for (unsigned int i = 0; i < nbytes; i++)
+ checksum = put_hex8_checksum(p[i], checksum);
+ }
+
+ put_packet_trailer(checksum);
+}
+
+static unsigned int
+get_unaligned_int(const unsigned char *p)
+{
+ // we're bigendian
+ return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
+}
+
+static bool
+write_memory(unsigned int addr, size_t nbytes,
+ const unsigned char *data)
+{
+ if ((addr & 0x3) == 0 && (nbytes & 0x3) == 0){ // word-aligned dst
+ unsigned int *dst = (unsigned int *) addr;
+ size_t length = nbytes / 4;
+ for (size_t i = 0; i < length; i++){
+ unsigned int t = get_unaligned_int(&data[4*i]);
+ dst[i] = t; // word writes
+ }
+ }
+ else { // non-word-aligned dst
+ unsigned char *dst = (unsigned char *) addr;
+ for (size_t i = 0; i < nbytes; i++){
+ dst[i] = data[i];
+ }
+ }
+ return true;
+}
+
+void
+gdbstub2_main_loop(void)
+{
+ unsigned char inpkt[MAX_PACKET + 24];
+ unsigned char binary_data[MAX_PACKET/2] __attribute__((aligned (4)));
+
+ hal_uart_set_mode(UART_MODE_RAW); //tell UART HAL not to map \n to \r\n
+
+ while (1){
+ size_t inpkt_len;
+ bool ok = get_packet(inpkt, sizeof(inpkt), &inpkt_len);
+ if (!ok){
+ gdb_putc('-');
+ continue;
+ }
+ gdb_putc('+');
+
+ const unsigned char *buf = inpkt;
+ const unsigned char *end = inpkt + inpkt_len;
+ unsigned char ch;
+
+ if (!parse_char(&buf, end, &ch)){ // empty packet
+ put_packet(0, 0);
+ continue;
+ }
+
+ unsigned int addr;
+ unsigned int length;
+
+ switch(ch){
+ case 'm': // m<addr>,<length> -- read <length> bytes starting at <addr>
+ if (!(parse_addr_length(&buf, end, &addr, &length) && expect_end(&buf, end))){
+ put_error(1);
+ }
+ else {
+ read_memory(addr, length);
+ }
+ break;
+
+ case 'M': // M<addr>,<length>:XX... -- write <length> bytes starting at <addr>
+ // XX... is the data in hex
+ if (!(parse_addr_length(&buf, end, &addr, &length)
+ && expect_char(&buf, end, ':')
+ && (end - buf) == 2 * length)){
+ put_error(1);
+ }
+ else {
+ if (!hex_to_bin_array(binary_data, buf, length))
+ put_error(2);
+ else if (!write_memory(addr, length, binary_data))
+ put_error(3);
+ else
+ put_ok();
+ }
+ break;
+
+ case 'X': // X<addr>,<length>:XX... -- write <length> bytes starting at <addr>
+ // XX... is the data in binary
+ if (!(parse_addr_length(&buf, end, &addr, &length)
+ && expect_char(&buf, end, ':')
+ && (end - buf) == length)){
+ put_error(1);
+ }
+ else {
+ if (!write_memory(addr, length, buf))
+ put_error(3);
+ else
+ put_ok();
+ }
+ break;
+
+ case 'c': // c<addr> -- continue. <addr> is the address to resume (goto).
+ if (!(parse_number(&buf, end, &addr)
+ && expect_end(&buf, end))){
+ put_error(1);
+ }
+ else {
+ typedef void (*fptr_t)(void);
+ (*(fptr_t) addr)(); // most likely no return
+ }
+ break;
+/*
+ case 0x80:
+ {
+ unsigned char *output = binary_data; // reuse
+ size_t sizeof_output = sizeof(binary_data);
+ size_t actual_olen;
+ loader_parser(buf, end-buf,
+ output, sizeof_output, &actual_olen);
+ put_packet(output, actual_olen);
+ }
+ break;
+*/
+ default: // unknown packet type
+ put_packet(0, 0);
+ break;
+ }
+ }
+}
diff --git a/firmware/microblaze/lib/gdbstub2.h b/firmware/microblaze/lib/gdbstub2.h
new file mode 100644
index 000000000..15cdde939
--- /dev/null
+++ b/firmware/microblaze/lib/gdbstub2.h
@@ -0,0 +1,25 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_GDBSTUB_H
+#define INCLUDED_GDBSTUB_H
+
+void gdbstub2_main_loop(void);
+
+#endif /* INCLUDED_GDBSTUB_H */
+
diff --git a/firmware/microblaze/lib/hal_io.c b/firmware/microblaze/lib/hal_io.c
index 0afd6a2cc..58b1e681e 100644
--- a/firmware/microblaze/lib/hal_io.c
+++ b/firmware/microblaze/lib/hal_io.c
@@ -193,3 +193,13 @@ puts(const char *s)
putchar('\n');
return 0;
}
+
+char *
+gets(char * const s)
+{
+ char *x = s;
+ while((*x=(char)hal_uart_getc()) != '\n') x++;
+ *x = 0;
+ return s;
+}
+
diff --git a/firmware/microblaze/lib/hal_io.h b/firmware/microblaze/lib/hal_io.h
index d8967f063..c67d96c62 100644
--- a/firmware/microblaze/lib/hal_io.h
+++ b/firmware/microblaze/lib/hal_io.h
@@ -23,6 +23,7 @@
void hal_io_init(void);
void hal_finish();
+char *gets(char * const s);
/*
* ------------------------------------------------------------------------
diff --git a/firmware/microblaze/lib/hal_uart.c b/firmware/microblaze/lib/hal_uart.c
index 75b12b432..fe3b7515a 100644
--- a/firmware/microblaze/lib/hal_uart.c
+++ b/firmware/microblaze/lib/hal_uart.c
@@ -39,16 +39,25 @@ divisor_table[MAX_WB_DIV+1][NSPEEDS] = {
#define u uart_regs
+static char uart_mode = UART_MODE_ONLCR;
+
+void
+hal_uart_set_mode(int mode)
+{
+ uart_mode = mode;
+}
+
void
hal_uart_init(void)
{
+ hal_uart_set_mode(UART_MODE_ONLCR);
u->clkdiv = 217; // 230400 bps
}
void
hal_uart_putc(int ch)
{
- if (ch == '\n') // FIXME for now map \n -> \r\n
+ if (ch == '\n')// && (uart_mode == UART_MODE_ONLCR)) //map \n->\r\n if necessary
hal_uart_putc('\r');
while (u->txlevel == 0) // wait for fifo to have space
@@ -60,7 +69,7 @@ hal_uart_putc(int ch)
void
hal_uart_putc_nowait(int ch)
{
- if (ch == '\n') // FIXME for now map \n -> \r\n
+ if (ch == '\n')// && (uart_mode == UART_MODE_ONLCR)) //map \n->\r\n if necessary
hal_uart_putc('\r');
if(u->txlevel) // If fifo has space
diff --git a/firmware/microblaze/lib/hal_uart.h b/firmware/microblaze/lib/hal_uart.h
index 2ddfa6259..dfd73c323 100644
--- a/firmware/microblaze/lib/hal_uart.h
+++ b/firmware/microblaze/lib/hal_uart.h
@@ -19,6 +19,16 @@
#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)
+
+/*
+ * \brief Set uart mode
+ */
+void hal_uart_set_mode(int flags);
/*!
* \brief one-time call to init
diff --git a/firmware/microblaze/lib/ihex.c b/firmware/microblaze/lib/ihex.c
new file mode 100644
index 000000000..97ecf73b6
--- /dev/null
+++ b/firmware/microblaze/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/microblaze/lib/ihex.h b/firmware/microblaze/lib/ihex.h
new file mode 100644
index 000000000..9f471fbe2
--- /dev/null
+++ b/firmware/microblaze/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/microblaze/lib/loader_parser.c b/firmware/microblaze/lib/loader_parser.c
new file mode 100644
index 000000000..96457a164
--- /dev/null
+++ b/firmware/microblaze/lib/loader_parser.c
@@ -0,0 +1,324 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "loader_parser.h"
+#include <quadradio/loader_bits.h>
+#include <quadradio/flashdir.h>
+#include <quadradio/simple_binary_format.h>
+#include <spi_flash.h>
+#include <nonstdio.h>
+//#include <assert.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include "ethernet.h"
+#include "qr_settings.h"
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+static spi_flash_async_state_t async_state;
+
+
+static caldiv_eeprom_setter_t _caldiv_set_rev = NULL;
+static caldiv_eeprom_setter_t _caldiv_set_ser = NULL;
+static caldiv_eeprom_setter_t _caldiv_set_mod = NULL;
+
+void
+register_caldiv_eeprom_setters(caldiv_eeprom_setter_t set_rev,
+ caldiv_eeprom_setter_t set_ser,
+ caldiv_eeprom_setter_t set_mod)
+{
+ _caldiv_set_rev = set_rev;
+ _caldiv_set_ser = set_ser;
+ _caldiv_set_mod = set_mod;
+}
+
+
+// big-endian
+static uint32_t
+get32(const unsigned char *s)
+{
+ return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+}
+
+// big-endian
+static unsigned char *
+put32(unsigned char *s, uint32_t v)
+{
+ s[0] = (v >> 24) & 0xff;
+ s[1] = (v >> 16) & 0xff;
+ s[2] = (v >> 8) & 0xff;
+ s[3] = v & 0xff;
+ return s + 4;
+}
+
+static bool
+erased_p(uint32_t flash_addr, size_t nbytes)
+{
+ unsigned char buf[64];
+
+ size_t n;
+ for (size_t i = 0; i < nbytes; i += n, flash_addr += n){
+ n = min(nbytes - i, sizeof(buf));
+ spi_flash_read(flash_addr, n, buf);
+ for (size_t j = 0; j < n; j++)
+ if (buf[j] != 0xff)
+ return false;
+ }
+ return true;
+}
+
+static bool
+erase_flash(uint32_t addr, uint32_t len)
+{
+ if (addr % spi_flash_sector_size() != 0)
+ return false;
+
+ if (len % spi_flash_sector_size() != 0)
+ return false;
+
+ spi_flash_async_erase_start(&async_state, addr, len);
+ // FIXME? check to see if erase was successful
+ return true;
+}
+
+static bool
+map_slot(uint32_t slot, uint32_t *slot_start, uint32_t *slot_len, uint32_t *status)
+{
+ // This case doesn't require a valid flashdir, and in fact can be used as
+ // part of writing the intial flashdir.
+ if (QLD_SLOT_DOM(slot) == QLD_DOM_UNMAPPED){
+ int flash_size = get_flash_size();
+ if (flash_size == 0){
+ *status = QLDS_FAILED; // Can't find the flash. most likely a h/w problem.
+ return false;
+ }
+ *slot_start = 0;
+ *slot_len = flash_size;
+ return true;
+ }
+
+ const struct flashdir *fd = get_flashdir();
+ if (fd == 0)
+ return false;
+
+ uint32_t slot_num = QLD_SLOT_NUM(slot);
+
+ switch(QLD_SLOT_DOM(slot)){
+ case QLD_DOM_FPGA:
+ if (slot_num >= fd->fpga_nslots){
+ *status = QLDS_INVALID_ARG;
+ return false;
+ }
+ *slot_start = fd->slot[slot_num + fd->fpga_slot0].start << spi_flash_log2_sector_size();
+ *slot_len = fd->slot[slot_num + fd->fpga_slot0].len << spi_flash_log2_sector_size();
+ return true;
+
+ case QLD_DOM_FW:
+ if (slot_num >= fd->fw_nslots){
+ *status = QLDS_INVALID_ARG;
+ return false;
+ }
+ *slot_start = fd->slot[slot_num + fd->fw_slot0].start << spi_flash_log2_sector_size();
+ *slot_len = fd->slot[slot_num + fd->fw_slot0].len << spi_flash_log2_sector_size();
+ return true;
+
+ default:
+ *status = QLDS_INVALID_ARG;
+ return false;
+ }
+}
+
+
+static bool
+check_flashdir(void)
+{
+ return get_flashdir() != 0;
+}
+
+void
+loader_parser(const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t max_olen, size_t *actual_olen)
+{
+ //assert (max_olen >= 8);
+ if (!(max_olen >= 8))
+ abort();
+
+ *actual_olen = 0;
+ uint32_t status = QLDS_BAD_PKT;
+
+ uint32_t cmd = get32(input);
+ uint32_t nonce = get32(input+4);
+ uint32_t slot = 0;
+ uint32_t addr = 0;
+ uint32_t len = 0;
+
+ if (ilen < 8){
+ nonce = -1;
+ goto done;
+ }
+
+ uint32_t slot_start; // offset in flash
+ uint32_t slot_len; // length in bytes
+
+ if (ilen >= 5 * sizeof(uint32_t)){
+ slot = get32(input+8);
+ addr = get32(input+12);
+ len = get32(input+16);
+ }
+
+ switch (cmd){
+ case QLD_FLASH_ERASE_START:
+ // <QLD_FLASH_ERASE_START> <nonce> <slot> <addr> <len>
+ if (ilen != 5 * sizeof(uint32_t))
+ goto done;
+
+ if (!check_flashdir()){
+ status = QLDS_BAD_FLASHDIR;
+ goto done;
+ }
+ if (!map_slot(slot, &slot_start, &slot_len, &status))
+ goto done;
+
+ if (QLD_SLOT_DOM(slot) != QLD_DOM_UNMAPPED){
+ addr = slot_start;
+ len = slot_len;
+ }
+ //printf("flash_erase: addr = 0x%x, len=0x%x\n", addr, len);
+
+ if (0 && erased_p(addr, len)){ // already erased?
+ async_state.first = async_state.last = async_state.current = 0;
+ goto ok;
+ }
+
+ if (erase_flash(addr, len))
+ goto ok;
+
+ status = QLDS_FAILED;
+ goto done;
+
+
+ case QLD_FLASH_ERASE_POLL:
+ // <QLD_FLASH_ERASE_POLL> <nonce>
+ if (ilen != 2 * sizeof(uint32_t))
+ goto done;
+
+ if (spi_flash_async_erase_poll(&async_state))
+ goto ok;
+
+ status = QLDS_BUSY;
+ goto done;
+
+
+ case QLD_FLASH_WRITE:
+ // <QLD_FLASH_WRITE> <nonce> <slot> <addr> <len> <data ...>
+ if (ilen < 5 * sizeof(uint32_t))
+ goto done;
+
+ if (ilen != 5 * sizeof(uint32_t) + len)
+ goto done;
+
+ if (!check_flashdir()){
+ status = QLDS_BAD_FLASHDIR;
+ goto done;
+ }
+ if (!map_slot(slot, &slot_start, &slot_len, &status))
+ goto done;
+
+ addr += slot_start;
+ len = min(len, slot_len);
+
+ if (spi_flash_program(addr, len, &input[5*sizeof(uint32_t)]))
+ goto ok;
+
+ status = QLDS_FAILED;
+ goto done;
+
+
+ case QLD_FLASH_READ:
+ case QLD_MEM_READ:
+ case QLD_MEM_WRITE:
+ case QLD_GOTO:
+ status = QLDS_NOTIMPLEMENTED;
+ goto done;
+
+ case QLD_PING:
+ // <QLD_PING> <nonce>
+ if (ilen != 2 * sizeof(uint32_t))
+ goto done;
+ goto ok;
+
+#if 0
+ case QLD_EEPROM_SET_XXX:
+ // <QLD_EEPROM_SET_XXX> <nonce> <arg> <idlen> <idstr> <data ...>
+ {
+ uint32_t arg = get32(input+2*sizeof(uint32_t));
+ uint32_t idlen = get32(input+3*sizeof(uint32_t));
+ uint8_t *idstr = (uint8_t*)input+4*sizeof(uint32_t);
+ uint8_t *data_p = idstr+idlen;
+
+ //handle the ethernet cases
+ if (strncmp((char*)idstr, "ip", idlen) == 0){
+ struct ip_addr addr = {get32(data_p)};
+ ethernet_set_ip_addr(arg, addr);
+ }
+ else if (strncmp((char*)idstr, "mac", idlen) == 0){
+ eth_mac_addr_t addr;
+ memcpy(&addr, data_p, sizeof(addr));
+ ethernet_set_mac_addr(arg, &addr);
+ }
+ //handle the main board eeprom
+ else if (strncmp((char*)idstr, "qrrev", idlen) == 0){
+ qr_set_revision(get32(data_p));
+ }
+ else if (strncmp((char*)idstr, "qrser", idlen) == 0){
+ qr_set_serial(get32(data_p));
+ }
+ else if (strncmp((char*)idstr, "qrmod", idlen) == 0){
+ qr_set_model(get32(data_p));
+ }
+ //handle the caldiv eeprom
+ else if (strncmp((char*)idstr, "cdrev", idlen) == 0){
+ if (_caldiv_set_rev) _caldiv_set_rev(get32(data_p));
+ }
+ else if (strncmp((char*)idstr, "cdser", idlen) == 0){
+ if (_caldiv_set_ser) _caldiv_set_ser(get32(data_p));
+ }
+ else if (strncmp((char*)idstr, "cdmod", idlen) == 0){
+ if (_caldiv_set_ser) _caldiv_set_mod(get32(data_p));
+ }
+ else {
+ goto done;
+ }
+ }
+ goto ok;
+#endif
+
+ default:
+ status = QLDS_UNKNOWN_CMD;
+ goto done;
+ }
+
+ ok:
+ status = QLDS_OK;
+
+ done:
+ put32(output, nonce);
+ put32(output+4, status);
+ *actual_olen = 2*sizeof(uint32_t);
+}
diff --git a/firmware/microblaze/lib/loader_parser.h b/firmware/microblaze/lib/loader_parser.h
new file mode 100644
index 000000000..365317bd7
--- /dev/null
+++ b/firmware/microblaze/lib/loader_parser.h
@@ -0,0 +1,38 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * max_olen must be at least 8 bytes. 1KB is recommended.
+ */
+void
+loader_parser(const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t max_olen, size_t *actual_olen);
+
+/*
+ * Major kludge-master altert!
+ * This function registers functions for setting caldiv eeprom stuff.
+ * This way, the parser does not depend on the qpn apps at compile time.
+ */
+typedef void(*caldiv_eeprom_setter_t)(uint32_t);
+void register_caldiv_eeprom_setters(
+ caldiv_eeprom_setter_t set_rev,
+ caldiv_eeprom_setter_t set_ser,
+ caldiv_eeprom_setter_t set_mod);
diff --git a/firmware/microblaze/lib/net/.gitignore b/firmware/microblaze/lib/net/.gitignore
new file mode 100644
index 000000000..282522db0
--- /dev/null
+++ b/firmware/microblaze/lib/net/.gitignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/firmware/microblaze/lib/net/eth_mac_addr.h b/firmware/microblaze/lib/net/eth_mac_addr.h
new file mode 100644
index 000000000..b44fb68f7
--- /dev/null
+++ b/firmware/microblaze/lib/net/eth_mac_addr.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDED_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/microblaze/lib/net/padded_eth_hdr.h b/firmware/microblaze/lib/net/padded_eth_hdr.h
new file mode 100644
index 000000000..df816734f
--- /dev/null
+++ b/firmware/microblaze/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/microblaze/lib/net/socket_address.h b/firmware/microblaze/lib/net/socket_address.h
new file mode 100644
index 000000000..336f30a0c
--- /dev/null
+++ b/firmware/microblaze/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/microblaze/lib/nonstdio.c b/firmware/microblaze/lib/nonstdio.c
index 1c991afee..4b5fa4123 100644
--- a/firmware/microblaze/lib/nonstdio.c
+++ b/firmware/microblaze/lib/nonstdio.c
@@ -78,3 +78,46 @@ 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/microblaze/lib/nonstdio.h b/firmware/microblaze/lib/nonstdio.h
index 3fd9e39bb..62ebfa46d 100644
--- a/firmware/microblaze/lib/nonstdio.h
+++ b/firmware/microblaze/lib/nonstdio.h
@@ -1,4 +1,6 @@
-/* -*- c -*- */
+//
+// Copyright 2010 Ettus Research LLC
+//
/*
* Copyright 2007 Free Software Foundation, Inc.
*
@@ -20,7 +22,7 @@
#define INCLUDED_NONSTDIO_H
#include <stdio.h>
-#include <usrp2_types.h>
+#include <stdint.h>
#include <stddef.h>
void putstr(const char *s); // cf puts, no added newline
@@ -37,10 +39,10 @@ void puthex32_nl(unsigned long x);
void newline(); // putchar('\n')
void print_mac_addr(const unsigned char addr[6]);
-void print_fxpt_freq(u2_fxpt_freq_t v);
-void print_fxpt_gain(u2_fxpt_gain_t v);
void print_uint64(uint64_t v);
void print_buffer(uint32_t *buf, size_t n);
+//char *itoa(signed long value, char *result, int base);
+//void reverse(char s[]);
#endif /* INCLUDED_NONSTDIO_H */
diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h
index f5b69b270..01e4d26fd 100644
--- a/firmware/microblaze/lib/spi.h
+++ b/firmware/microblaze/lib/spi.h
@@ -48,5 +48,23 @@ void spi_wait(void);
uint32_t
spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags);
+// ----------------------------------------------------------------
+// Routines that manipulate the FLASH SPI BUS
+// ----------------------------------------------------------------
+
+/*!
+ * \brief One time call to initialize SPI
+ */
+void spif_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 spif_wait(void);
+
+uint32_t
+spif_transact(bool readback_, int slave, uint32_t data, int length, uint32_t flags);
+
#endif /* INCLUDED_SPI_H */
diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c
index 6809101c0..ff558d673 100644
--- a/firmware/microblaze/lib/u2_init.c
+++ b/firmware/microblaze/lib/u2_init.c
@@ -25,9 +25,7 @@
#include "i2c.h"
#include "mdelay.h"
#include "clocks.h"
-#include "usrp2_i2c_addr.h"
-
-//#include "nonstdio.h"
+#include "usrp2/fw_common.h"
unsigned char u2_hw_rev_major;
unsigned char u2_hw_rev_minor;
@@ -35,8 +33,8 @@ unsigned char u2_hw_rev_minor;
static inline void
get_hw_rev(void)
{
- bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &u2_hw_rev_minor, 1);
- ok &= eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &u2_hw_rev_major, 1);
+ bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, &u2_hw_rev_minor, 1);
+ ok &= eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, &u2_hw_rev_major, 1);
}
/*
diff --git a/firmware/microblaze/lib/udp_burner_packet.c b/firmware/microblaze/lib/udp_burner_packet.c
new file mode 100644
index 000000000..d86a4cf4a
--- /dev/null
+++ b/firmware/microblaze/lib/udp_burner_packet.c
@@ -0,0 +1,38 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "udp_burner_packet.h"
+#include "net_common.h"
+#include "loader_parser.h"
+#include <stdint.h>
+#include <compiler.h>
+#include <nonstdio.h>
+
+
+void
+handle_udp_burner_packet(struct socket_address src, struct socket_address dst,
+ unsigned char *payload, int payload_len)
+{
+ unsigned char reply[128] _AL4;
+ size_t actual_reply_len;
+ loader_parser(payload, payload_len, reply, sizeof(reply), &actual_reply_len);
+ send_udp_pkt(dst.port, src, reply, actual_reply_len);
+}
diff --git a/firmware/microblaze/lib/udp_burner_packet.h b/firmware/microblaze/lib/udp_burner_packet.h
new file mode 100644
index 000000000..0f4025712
--- /dev/null
+++ b/firmware/microblaze/lib/udp_burner_packet.h
@@ -0,0 +1,28 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_UDP_BURNER_PACKET_H
+#define INCLUDED_UDP_BURNER_PACKET_H
+
+#include <net/socket_address.h>
+
+void
+handle_udp_burner_packet(struct socket_address src, struct socket_address dst,
+ unsigned char *payload, int payload_len);
+
+
+#endif /* INCLUDED_UDP_BURNER_PACKET_H */
diff --git a/firmware/microblaze/lib/xilinx_s3_icap.c b/firmware/microblaze/lib/xilinx_s3_icap.c
new file mode 100644
index 000000000..8aa7fd297
--- /dev/null
+++ b/firmware/microblaze/lib/xilinx_s3_icap.c
@@ -0,0 +1,101 @@
+/* -*- c -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* Changes required to work for the Spartan-3A series:
+ * The ICAP interface on the 3A is 8 bits wide, instead of 32.
+ * Everything is Xilinx standard LSB-first.
+ * The operations are all different.
+ * Commands are 16 bits long, presented to the ICAP interface 8 bits at a time.
+*/
+
+#include <xilinx_s3_icap.h>
+#include <memory_map.h>
+#include <spi_flash_private.h> //for READ_CMD
+
+
+/* bit swap end-for-end */
+static unsigned char
+swap8(unsigned char x)
+{
+ unsigned char r = 0;
+ r |= (x >> 7) & 0x01;
+ r |= (x >> 5) & 0x02;
+ r |= (x >> 3) & 0x04;
+ r |= (x >> 1) & 0x08;
+
+ r |= (x << 1) & 0x10;
+ r |= (x << 3) & 0x20;
+ r |= (x << 5) & 0x40;
+ r |= (x << 7) & 0x80;
+
+ return r;
+}
+
+void
+wr_icap(uint8_t x)
+{
+ uint8_t t = swap8(x);
+
+ icap_regs->icap = t; //DEBUG: does not swap bits
+}
+
+uint8_t
+rd_icap(void)
+{
+ return swap8(icap_regs->icap);
+}
+
+
+void
+icap_reload_fpga(uint32_t flash_address)
+//this DOES NOT WORK right now. reboot is not getting executed correctly.
+{
+ union {
+ uint32_t i;
+ uint8_t c[4];
+ } t;
+ t.i = flash_address;
+
+ //note! t.c[0] MUST contain the byte-wide read command for the flash device used.
+ //for the 25P64, and most other flash devices, this is 0x03.
+ t.c[0] = READ_CMD; //legacy command, use FAST_READ_CMD 0x0B after testing
+
+ //TODO: look up the watchdog timer, ensure it won't fire too soon
+
+ //UG332 p279
+// wr_icap(0xff);
+// wr_icap(0xff); //dummy word, probably unnecessary
+ wr_icap(0xAA);
+ wr_icap(0x99); //sync word
+ wr_icap(0x32);
+ wr_icap(0x61); //Type 1 write General 1 (1 word)
+ wr_icap(t.c[2]); //bits 15-8
+ wr_icap(t.c[3]); //bits 7-0
+ wr_icap(0x32);
+ wr_icap(0x81); //Type 1 write General 2 (1 word)
+ wr_icap(t.c[0]); //C0-C8, the byte-wide read command
+ wr_icap(t.c[1]); //Upper 8 bits of 24-bit address
+ wr_icap(0x30);
+ wr_icap(0xA1); //Type 1 write CMD (1 word)
+ wr_icap(0x00);
+ wr_icap(0x0E); //REBOOT command
+ wr_icap(0x20);
+ wr_icap(0x00); //Type 1 NOP
+
+}