diff options
Diffstat (limited to 'firmware/microblaze/lib')
33 files changed, 1581 insertions, 1495 deletions
| diff --git a/firmware/microblaze/lib/.gitignore b/firmware/microblaze/lib/.gitignore deleted file mode 100644 index 5d838bf6c..000000000 --- a/firmware/microblaze/lib/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -*~ -/*-stamp -/*.a -/*.bin -/*.dump -/*.log -/*.rom -/.deps -/Makefile -/Makefile.in -/aclocal.m4 -/autom4te.cache -/blink_leds -/blink_leds2 -/build -/compile -/config.h -/config.h.in -/config.log -/config.status -/configure -/depcomp -/eth_test -/gen_eth_packets -/ibs_rx_test -/ibs_tx_test -/install-sh -/libtool -/ltmain.sh -/missing -/py-compile -/rcv_eth_packets -/run_tests.sh -/stamp-h1 -/test1 -/test_phy_comm -/timer_test -/buf_ram_test -/buf_ram_zero -/hello diff --git a/firmware/microblaze/lib/Makefile.am b/firmware/microblaze/lib/Makefile.am deleted file mode 100644 index b51d74463..000000000 --- a/firmware/microblaze/lib/Makefile.am +++ /dev/null @@ -1,87 +0,0 @@ -# -# Copyright 2010 Ettus Research LLC -# -# Copyright 2007 Free Software Foundation, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. -# - -include $(top_srcdir)/Makefile.common - -noinst_LIBRARIES = \ -	libu2fw.a - -libu2fw_a_SOURCES = \ -	abort.c \ -	ad9510.c \ -	bsm12.c \ -	buffer_pool.c \ -	clocks.c \ -	dbsm.c \ -	eeprom.c \ -	ethernet.c \ -	eth_mac.c \ -	_exit.c \ -	exit.c \ -	hal_io.c \ -	hal_uart.c \ -	i2c.c \ -	mdelay.c \ -	memcpy_wa.c \ -	memset_wa.c \ -	nonstdio.c \ -	pic.c \ -	print_mac_addr.c \ -	print_rmon_regs.c \ -	print_buffer.c \ -	printf.c \ -	sd.c \ -	spi.c \ -	u2_init.c \ -	net_common.c \ -	arp_cache.c \ -	banal.c - -noinst_HEADERS = \ -	ad9510.h \ -	bsm12.h \ -	buffer_pool.h \ -	clocks.h \ -	dbsm.h \ -	eth_mac.h \ -	eth_mac_regs.h \ -	eth_phy.h \ -	ethernet.h \ -	hal_io.h \ -	hal_uart.h \ -	i2c.h \ -	mdelay.h \ -	memcpy_wa.h \ -	memory_map.h \ -	memset_wa.h \ -	nonstdio.h \ -	pic.h \ -	print_rmon_regs.h \ -	sd.h \ -	spi.h \ -	stdint.h \ -	stdio.h \ -	u2_init.h \ -	usrp2_bytesex.h \ -	wb16550.h \ -	net_common.h \ -	if_arp.h \ -	arp_cache.h \ -	banal.h \ -	ethertype.h diff --git a/firmware/microblaze/lib/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.c b/firmware/microblaze/lib/clocks.c deleted file mode 100644 index ccc4a7cc7..000000000 --- a/firmware/microblaze/lib/clocks.c +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <clocks.h> - -#include "memory_map.h" -#include "ad9510.h" -#include "spi.h" -#include "u2_init.h" -#include "nonstdio.h" - -void  -clocks_init(void) -{ -  // Set up basic clocking functions in AD9510 -  ad9510_write_reg(0x45, 0x00); // CLK2 drives distribution - -  clocks_enable_fpga_clk(true, 1); - -  spi_wait(); - -  // Set up PLL for 10 MHz reference -  // Reg 4, A counter, Don't Care -  ad9510_write_reg(0x05, 0x00);  // Reg 5, B counter MSBs, 0 -  ad9510_write_reg(0x06, 0x05);  // Reg 6, B counter LSBs, 5 -  // Reg 7, Loss of reference detect, doesn't work yet, 0 -  ad9510_write_reg(0x5A, 0x01); // Update Regs - -  // Primary clock configuration -  clocks_mimo_config(MC_WE_DONT_LOCK); - -  // Set up other clocks -  //clocks_enable_test_clk(false, 0); -  //clocks_enable_tx_dboard(false, 0); -  //clocks_enable_rx_dboard(false, 0); -  clocks_enable_eth_phyclk(false, 0); - -  // Enable clock to ADCs and DACs -  //clocks_enable_dac_clk(true, 1); -  //clocks_enable_adc_clk(true, 1); -} - - -void -clocks_mimo_config(int flags) -{ -  if (flags & _MC_WE_LOCK){ -    // Reg 8, Charge pump on, dig lock det, positive PFD, 47 -    ad9510_write_reg(0x08, 0x47); -  } -  else { -    // Reg 8, Charge pump off, dig lock det, positive PFD -    ad9510_write_reg(0x08, 0x00); -  } -   -  // Reg 9, Charge pump current, 0x40=3mA, 0x00=650uA -  ad9510_write_reg(0x09, 0x00); -  // Reg A, Prescaler of 2, everything normal 04 -  ad9510_write_reg(0x0A, 0x04); -  // Reg B, R Div MSBs, 0 -  ad9510_write_reg(0x0B, 0x00); -  // Reg C, R Div LSBs, 1 -  ad9510_write_reg(0x0C, 0x01); -  // Reg D, Antibacklash, Digital lock det, 0 - -  ad9510_write_reg(0x5A, 0x01); // Update Regs - -  spi_wait(); -   -  // Allow for clock switchover -   -  if (flags & _MC_WE_LOCK){		// WE LOCK -    if (flags & _MC_MIMO_CLK_INPUT) { -      // Turn on ref output and choose the MIMO connector -      output_regs->clk_ctrl = 0x15;   -    } -    else { -      // turn on ref output and choose the SMA -      output_regs->clk_ctrl = 0x1C;  -    } -  } -  else {				// WE DONT LOCK -    // Disable both ext clk inputs -    output_regs->clk_ctrl = 0x10; -  } - -  // Do we drive a clock onto the MIMO connector? -  if (flags & MC_PROVIDE_CLK_TO_MIMO) -    clocks_enable_clkexp_out(true,10); -  else -    clocks_enable_clkexp_out(false,0);  -} - -bool  -clocks_lock_detect() -{ -  if(pic_regs->pending & PIC_CLKSTATUS) -    return true; -  return false; -} - -int inline -clocks_gen_div(int divisor) -{ -  int L,H; -  L = (divisor>>1)-1; -  H = divisor-L-2; -  return (L<<4)|H; -} - -#define CLOCK_OUT_EN 0x08 -#define CLOCK_OUT_DIS_CMOS 0x01 -#define CLOCK_OUT_DIS_PECL 0x02 -#define CLOCK_DIV_DIS 0x80 -#define CLOCK_DIV_EN 0x00 - -#define CLOCK_MODE_PECL 1 -#define CLOCK_MODE_LVDS 2 -#define CLOCK_MODE_CMOS 3 - -void  -clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mode) -{ -  int enable_word, div_word, div_en_word; - -  switch(mode) { -  case CLOCK_MODE_PECL : -    enable_word = enable ? 0x08 : 0x0A; -    break; -  case CLOCK_MODE_LVDS : -    enable_word = enable ? 0x02 : 0x03; -    break; -  case CLOCK_MODE_CMOS : -    enable_word = enable ? 0x08 : 0x09; -    break; -  } -  if(enable && (divisor>1)) { -    div_word = clocks_gen_div(divisor); -    div_en_word = CLOCK_DIV_EN; -  } -  else { -    div_word = 0; -    div_en_word = CLOCK_DIV_DIS; -  } - -  ad9510_write_reg(reg_en,enable_word); // Output en/dis -  ad9510_write_reg(reg_div,div_word); // Set divisor -  ad9510_write_reg(reg_div+1,div_en_word); // Enable or Bypass Divider -  ad9510_write_reg(0x5A, 0x01);  // Update Regs -} - -// Clock 0 -/*void -clocks_enable_test_clk(bool enable, int divisor) -{ -  clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL); -}*/ - -// Clock 1 -void -clocks_enable_fpga_clk(bool enable, int divisor) -{ -  clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL); -} - -// Clock 2 on Rev 3, Clock 5 on Rev 4 -void -clocks_enable_clkexp_out(bool enable, int divisor) -{ -  if(u2_hw_rev_major == 3) -    clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL); -  else if(u2_hw_rev_major == 4) { -    ad9510_write_reg(0x34,0x00);  // Turn on fine delay -    ad9510_write_reg(0x35,0x00);  // Set Full Scale to nearly 10ns -    ad9510_write_reg(0x36,0x1c);  // Set fine delay.  0x20 is midscale -    clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS); -     -  } -  else -    putstr("ERR: Invalid Rev\n"); -} - -// Clock 5 on Rev 3, none (was 2) on Rev 4 -void -clocks_enable_eth_phyclk(bool enable, int divisor) -{ -  if(u2_hw_rev_major == 3) -    clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS); -  else if(u2_hw_rev_major == 4) -    clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL); -  else -    putstr("ERR: Invalid Rev\n"); -} - -// Clock 3 -/*void -clocks_enable_dac_clk(bool enable, int divisor) -{ -  clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL); -}*/ - -// Clock 4 -/*void -clocks_enable_adc_clk(bool enable, int divisor) -{ -  clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS); -}*/ - -// Clock 6 -/*void -clocks_enable_tx_dboard(bool enable, int divisor) -{ -  clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS); -}*/ - -// Clock 7 -/*void -clocks_enable_rx_dboard(bool enable, int divisor) -{ -  clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS); -}*/ diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h 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/memory_map.h b/firmware/microblaze/lib/memory_map.h deleted file mode 100644 index cdf3dd338..000000000 --- a/firmware/microblaze/lib/memory_map.h +++ /dev/null @@ -1,792 +0,0 @@ -/* -*- c -*- */ -/* - * Copyright 2007,2008,2009 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -/* Overall Memory Map - *   0000-7FFF  32K   RAM space (16K on 1500, 24K on 2000, 32K on DSP) - *   8000-BFFF  16K   Buffer Pool - *   C000-FFFF  16K   Peripherals - */ - - -#ifndef INCLUDED_MEMORY_MAP_H -#define INCLUDED_MEMORY_MAP_H - -#include <stdint.h> - - -#define MASTER_CLK_RATE        100000000		// 100 MHz - - -//////////////////////////////////////////////////////////////// -// -//         Memory map for embedded wishbone bus -// -//////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////// -// Main RAM, Slave 0 - -#define RAM_BASE 0x0000 - -//////////////////////////////////////////////////////////////// -// Buffer Pool RAM, Slave 1 -// -// The buffers themselves are located in Slave 1, Buffer Pool RAM. -// The status registers are in Slave 5, Buffer Pool Status. -// The control register is in Slave 7, Settings Bus. - -#define BUFFER_POOL_RAM_BASE 0x8000 - -#define	NBUFFERS                8 -#define BP_NLINES	   0x0200	// number of 32-bit lines in a buffer -#define BP_LAST_LINE	(BP_NLINES - 1)	// last line in a buffer - -#define buffer_pool_ram \ -  ((uint32_t *) BUFFER_POOL_RAM_BASE) - -#define buffer_ram(n) (&buffer_pool_ram[(n) * BP_NLINES]) - - -///////////////////////////////////////////////////// -// SPI Core, Slave 2.  See core docs for more info -#define SPI_BASE 0xC000   // Base address (16-bit) - -typedef struct { -  volatile uint32_t	txrx0; -  volatile uint32_t	txrx1; -  volatile uint32_t	txrx2; -  volatile uint32_t	txrx3; -  volatile uint32_t	ctrl; -  volatile uint32_t	div; -  volatile uint32_t	ss; -} spi_regs_t; - -#define spi_regs ((spi_regs_t *) SPI_BASE) - - -// Masks for controlling different peripherals -#define SPI_SS_AD9510    1 -#define SPI_SS_AD9777    2 -#define SPI_SS_RX_DAC    4 -#define SPI_SS_RX_ADC    8 -#define SPI_SS_RX_DB    16 -#define SPI_SS_TX_DAC   32 -#define SPI_SS_TX_ADC   64 -#define SPI_SS_TX_DB   128 - -// Masks for different parts of CTRL reg -#define SPI_CTRL_ASS      (1<<13) -#define SPI_CTRL_IE       (1<<12) -#define SPI_CTRL_LSB      (1<<11) -#define SPI_CTRL_TXNEG    (1<<10) -#define SPI_CTRL_RXNEG    (1<< 9) -#define SPI_CTRL_GO_BSY   (1<< 8) -#define SPI_CTRL_CHAR_LEN_MASK 0x7F - -//////////////////////////////////////////////// -// I2C, Slave 3 -// See Wishbone I2C-Master Core Specification. - -#define I2C_BASE 0xC400 - -typedef struct { -  volatile uint32_t  prescaler_lo;	// r/w -  volatile uint32_t  prescaler_hi;	// r/w -  volatile uint32_t  ctrl;		// r/w -  volatile uint32_t  data;		// wr = transmit reg; rd = receive reg -  volatile uint32_t  cmd_status;	// wr = command reg;  rd = status reg -} i2c_regs_t; - -#define i2c_regs ((i2c_regs_t *) I2C_BASE) - -#define	I2C_CTRL_EN	(1 << 7)	// core enable -#define	I2C_CTRL_IE	(1 << 6)	// interrupt enable - -// -// STA, STO, RD, WR, and IACK bits are cleared automatically -// -#define	I2C_CMD_START	(1 << 7)	// generate (repeated) start condition -#define I2C_CMD_STOP	(1 << 6)	// generate stop condition -#define	I2C_CMD_RD	(1 << 5)	// read from slave -#define I2C_CMD_WR	(1 << 4)	// write to slave -#define	I2C_CMD_NACK	(1 << 3)	// when a rcvr, send ACK (ACK=0) or NACK (ACK=1) -#define I2C_CMD_RSVD_2	(1 << 2)	// reserved -#define	I2C_CMD_RSVD_1	(1 << 1)	// reserved -#define I2C_CMD_IACK	(1 << 0)	// set to clear pending interrupt - -#define I2C_ST_RXACK	(1 << 7)	// Received acknowledgement from slave (1 = NAK, 0 = ACK) -#define	I2C_ST_BUSY	(1 << 6)	// 1 after START signal detected; 0 after STOP signal detected -#define	I2C_ST_AL	(1 << 5)	// Arbitration lost.  1 when core lost arbitration -#define	I2C_ST_RSVD_4	(1 << 4)	// reserved -#define	I2C_ST_RSVD_3	(1 << 3)	// reserved -#define	I2C_ST_RSVD_2	(1 << 2)	// reserved -#define I2C_ST_TIP	(1 << 1)	// Transfer-in-progress -#define	I2C_ST_IP	(1 << 0)	// Interrupt pending - - -//////////////////////////////////////////////// -// GPIO, Slave 4 -// -// These go to the daughterboard i/o pins - -#define GPIO_BASE 0xC800 - -typedef struct { -  volatile uint32_t	io;	  // tx data in high 16, rx in low 16 -  volatile uint32_t     ddr;      // 32 bits, 1 means output. tx in high 16, rx in low 16 -  volatile uint32_t	tx_sel;   // 16 2-bit fields select which source goes to TX DB -  volatile uint32_t	rx_sel;   // 16 2-bit fields select which source goes to RX DB -} gpio_regs_t; - -// each 2-bit sel field is layed out this way -#define GPIO_SEL_SW	   0 // if pin is an output, set by software in the io reg -#define	GPIO_SEL_ATR	   1 // if pin is an output, set by ATR logic -#define	GPIO_SEL_DEBUG_0   2 // if pin is an output, debug lines from FPGA fabric -#define	GPIO_SEL_DEBUG_1   3 // if pin is an output, debug lines from FPGA fabric - -#define gpio_base ((gpio_regs_t *) GPIO_BASE) - -/////////////////////////////////////////////////// -// Buffer Pool Status, Slave 5 -// -// The buffers themselves are located in Slave 1, Buffer Pool RAM. -// The status registers are in Slave 5, Buffer Pool Status. -// The control register is in Slave 7, Settings Bus. - -#define BUFFER_POOL_STATUS_BASE 0xCC00 - -typedef struct { -  volatile uint32_t last_line[NBUFFERS]; // last line xfer'd in buffer -  volatile uint32_t status;	         // error and done flags -  volatile uint32_t hw_config;	         // see below -  volatile uint32_t dummy[3]; -  volatile uint32_t irqs; -  volatile uint32_t pri_enc_bp_status; -  volatile uint32_t cycle_count; -} buffer_pool_status_t; - -#define buffer_pool_status ((buffer_pool_status_t *) BUFFER_POOL_STATUS_BASE) - -/* - * Buffer n's xfer is done. - * Clear this bit by issuing bp_clear_buf(n) - */ -#define BPS_DONE(n)     (0x00000001 << (n)) -#define BPS_DONE_0	BPS_DONE(0) -#define BPS_DONE_1	BPS_DONE(1) -#define BPS_DONE_2	BPS_DONE(2) -#define BPS_DONE_3	BPS_DONE(3) -#define BPS_DONE_4	BPS_DONE(4) -#define BPS_DONE_5	BPS_DONE(5) -#define BPS_DONE_6	BPS_DONE(6) -#define BPS_DONE_7	BPS_DONE(7) - -/* - * Buffer n's xfer had an error. - * Clear this bit by issuing bp_clear_buf(n) - */ -#define BPS_ERROR(n)	(0x00000100 << (n)) -#define BPS_ERROR_0	BPS_ERROR(0) -#define BPS_ERROR_1	BPS_ERROR(1) -#define BPS_ERROR_2	BPS_ERROR(2) -#define BPS_ERROR_3	BPS_ERROR(3) -#define BPS_ERROR_4	BPS_ERROR(4) -#define BPS_ERROR_5	BPS_ERROR(5) -#define BPS_ERROR_6	BPS_ERROR(6) -#define BPS_ERROR_7	BPS_ERROR(7) - -/* - * Buffer n is idle.  A buffer is idle if it's not - * DONE, ERROR, or processing a transaction.  If it's - * IDLE, it's safe to start a new transaction. - * - * Clear this bit by starting a xfer with - * bp_send_from_buf or bp_receive_to_buf. - */ -#define BPS_IDLE(n)     (0x00010000 << (n)) -#define BPS_IDLE_0	BPS_IDLE(0) -#define BPS_IDLE_1	BPS_IDLE(1) -#define BPS_IDLE_2	BPS_IDLE(2) -#define BPS_IDLE_3	BPS_IDLE(3) -#define BPS_IDLE_4	BPS_IDLE(4) -#define BPS_IDLE_5	BPS_IDLE(5) -#define BPS_IDLE_6	BPS_IDLE(6) -#define BPS_IDLE_7	BPS_IDLE(7) - -/* - * Buffer n has a "slow path" packet in it. - * This bit is orthogonal to the bits above and indicates that - * the FPGA ethernet rx protocol engine has identified this packet - * as one requiring firmware intervention. - */ -#define BPS_SLOWPATH(n) (0x01000000 << (n)) -#define BPS_SLOWPATH_0	BPS_SLOWPATH(0) -#define BPS_SLOWPATH_1	BPS_SLOWPATH(1) -#define BPS_SLOWPATH_2	BPS_SLOWPATH(2) -#define BPS_SLOWPATH_3	BPS_SLOWPATH(3) -#define BPS_SLOWPATH_4	BPS_SLOWPATH(4) -#define BPS_SLOWPATH_5	BPS_SLOWPATH(5) -#define BPS_SLOWPATH_6	BPS_SLOWPATH(6) -#define BPS_SLOWPATH_7	BPS_SLOWPATH(7) - - -#define BPS_DONE_ALL	  0x000000ff	// mask of all dones -#define BPS_ERROR_ALL	  0x0000ff00	// mask of all errors -#define BPS_IDLE_ALL      0x00ff0000	// mask of all idles -#define BPS_SLOWPATH_ALL  0xff000000	// mask of all slowpaths - -// The hw_config register - -#define	HWC_SIMULATION		0x80000000 -#define	HWC_WB_CLK_DIV_MASK	0x0000000f - -/*! - * \brief return non-zero if we're running under the simulator - */ -inline static int -hwconfig_simulation_p(void) -{ -  return buffer_pool_status->hw_config & HWC_SIMULATION; -} - -/*! - * \brief Return Wishbone Clock divisor. - * The processor runs at the Wishbone Clock rate which is MASTER_CLK_RATE / divisor. - */ -inline static int -hwconfig_wishbone_divisor(void) -{ -  return buffer_pool_status->hw_config & HWC_WB_CLK_DIV_MASK; -} - -/////////////////////////////////////////////////// -// Ethernet Core, Slave 6 - -#define ETH_BASE 0xD000 - -#include "eth_mac_regs.h" - -#define eth_mac ((eth_mac_regs_t *) ETH_BASE) - -//////////////////////////////////////////////////// -// Settings Bus, Slave #7, Not Byte Addressable! -// -// Output-only from processor point-of-view. -// 1KB of address space (== 256 32-bit write-only regs) - - -#define MISC_OUTPUT_BASE        0xD400 -#define	TX_PROTOCOL_ENGINE_BASE 0xD480 -#define	RX_PROTOCOL_ENGINE_BASE 0xD4C0 -#define BUFFER_POOL_CTRL_BASE   0xD500 -#define LAST_SETTING_REG        0xD7FC	// last valid setting register - -#define SR_MISC 0 -#define SR_TX_PROT_ENG 32 -#define SR_RX_PROT_ENG 48 -#define SR_BUFFER_POOL_CTRL 64 -#define SR_UDP_SM 96 -#define SR_TX_DSP 208 -#define SR_TX_CTRL 224 -#define SR_RX_DSP 160 -#define SR_RX_CTRL 176 -#define SR_TIME64 192 -#define SR_SIMTIMER 198 -#define SR_LAST 255 - -#define	_SR_ADDR(sr)	(MISC_OUTPUT_BASE + (sr) * sizeof(uint32_t)) - -// --- buffer pool control regs --- - -typedef struct { -  volatile uint32_t ctrl; -} buffer_pool_ctrl_t; - -// buffer pool ports - -#define	PORT_SERDES	0	// serial/deserializer -#define	PORT_DSP	1	// DSP tx or rx pipeline -#define	PORT_ETH	2	// ethernet tx or rx -#define	PORT_RAM	3	// RAM tx or rx - -// the buffer pool ctrl register fields - -#define BPC_BUFFER(n) (((n) & 0xf) << 28) -#define   BPC_BUFFER_MASK      BPC_BUFFER(~0) -#define   BPC_BUFFER_0	       BPC_BUFFER(0) -#define   BPC_BUFFER_1	       BPC_BUFFER(1) -#define   BPC_BUFFER_2	       BPC_BUFFER(2) -#define   BPC_BUFFER_3	       BPC_BUFFER(3) -#define   BPC_BUFFER_4	       BPC_BUFFER(4) -#define   BPC_BUFFER_5	       BPC_BUFFER(5) -#define   BPC_BUFFER_6	       BPC_BUFFER(6) -#define   BPC_BUFFER_7	       BPC_BUFFER(7) -#define	  BPC_BUFFER_NIL       BPC_BUFFER(0x8)	// disable - -#define BPC_PORT(n) (((n) & 0x7) << 25) -#define   BPC_PORT_MASK        BPC_PORT(~0) -#define   BPC_PORT_SERDES      BPC_PORT(PORT_SERDES) -#define   BPC_PORT_DSP	       BPC_PORT(PORT_DSP) -#define   BPC_PORT_ETH         BPC_PORT(PORT_ETH) -#define   BPC_PORT_RAM         BPC_PORT(PORT_RAM) -#define   BPC_PORT_NIL	       BPC_PORT(0x4)   	// disable - -#define	BPC_CLR	       	       (1 << 24)  // mutually excl commands -#define	BPC_READ	       (1 << 23) -#define BPC_WRITE              (1 << 22) - -#define BPC_STEP(step) (((step) & 0xf) << 18) -#define   BPC_STEP_MASK	       BPC_STEP(~0) -#define BPC_LAST_LINE(line) (((line) & 0x1ff) << 9) -#define   BPC_LAST_LINE_MASK   BPC_LAST_LINE(~0) -#define BPC_FIRST_LINE(line) (((line) & 0x1ff) << 0) -#define   BPC_FIRST_LINE_MASK  BPC_FIRST_LINE(~0) - -#define buffer_pool_ctrl ((buffer_pool_ctrl_t *) BUFFER_POOL_CTRL_BASE) - -// --- misc outputs --- - -typedef struct { -  volatile uint32_t	clk_ctrl; -  volatile uint32_t	serdes_ctrl; -  volatile uint32_t	adc_ctrl; -  volatile uint32_t	leds; -  volatile uint32_t	phy_ctrl;	// LSB is reset line to eth phy -  volatile uint32_t	debug_mux_ctrl; -  volatile uint32_t     ram_page;       // FIXME should go somewhere else... -  volatile uint32_t     flush_icache;   // Flush the icache -  volatile uint32_t     led_src;        // HW or SW control for LEDs -} output_regs_t; - -#define SERDES_ENABLE 8 -#define SERDES_PRBSEN 4 -#define SERDES_LOOPEN 2 -#define SERDES_RXEN   1 - -#define	ADC_CTRL_ON	0x0F -#define	ADC_CTRL_OFF	0x00 - -// crazy order that matches the labels on the case - -#define	LED_A		(1 << 4) -#define	LED_B		(1 << 1) -#define	LED_C		(1 << 3) -#define	LED_D		(1 << 0) -#define	LED_E		(1 << 2) -//      LED_F		// controlled by CPLD -#define	LED_RJ45	(1 << 5) - -#define output_regs ((output_regs_t *) MISC_OUTPUT_BASE) - -// --- udp tx regs --- - -typedef struct { -  // Bits 19:16 are control info; bits 15:0 are data (see below) -  // First two words are unused. -  volatile uint32_t _nope[2]; -  //--- ethernet header - 14 bytes--- -  volatile struct{ -    uint32_t mac_dst_0_1; //word 2 -    uint32_t mac_dst_2_3; -    uint32_t mac_dst_4_5; -    uint32_t mac_src_0_1; -    uint32_t mac_src_2_3; -    uint32_t mac_src_4_5; -    uint32_t ether_type; //word 8 -  } eth_hdr; -  //--- ip header - 20 bytes --- -  volatile struct{ -    uint32_t ver_ihl_tos; //word 9 -    uint32_t total_length; -    uint32_t identification; -    uint32_t flags_frag_off; -    uint32_t ttl_proto; -    uint32_t checksum; -    uint32_t src_addr_high; -    uint32_t src_addr_low; -    uint32_t dst_addr_high; -    uint32_t dst_addr_low; //word 18 -  } ip_hdr; -  //--- udp header - 8 bytes --- -  volatile struct{ -    uint32_t src_port; //word 19 -    uint32_t dst_port; -    uint32_t length; -    uint32_t checksum; //word 22 -  } udp_hdr; -  volatile uint32_t _pad[32-23]; -} sr_udp_sm_t; - -// control bits (all expect UDP_SM_LAST_WORD are mutually exclusive) - -// This is the last word of the header -#define	UDP_SM_LAST_WORD		(1 << 19) - -// Insert IP header checksum here.  Data is the xor of 16'hFFFF and -// the values written into regs 9-13 and 15-18. -#define	UDP_SM_INS_IP_HDR_CHKSUM	(1 << 18) - -// Insert IP Length here (data ignored) -#define	UDP_SM_INS_IP_LEN		(1 << 17) - -// Insert UDP Length here (data ignore) -#define	UDP_SM_INS_UDP_LEN		(1 << 16) - -#define sr_udp_sm ((sr_udp_sm_t *) _SR_ADDR(SR_UDP_SM)) - -// --- dsp tx regs --- - -#define MIN_CIC_INTERP	1 -#define	MAX_CIC_INTERP  128 - -typedef struct { -  volatile uint32_t     num_chan; -  volatile uint32_t     clear_state;	// clears out state machine, fifos, -} sr_tx_ctrl_t; - -#define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL)) - -typedef struct { -  volatile int32_t	freq; -  volatile uint32_t	scale_iq;	// {scale_i,scale_q} -  volatile uint32_t     interp_rate; -  volatile uint32_t     _padding0;      // padding for the tx_mux -                                        //   NOT freq, scale, interp -  /*! -   * \brief output mux configuration. -   * -   * <pre> -   *     3                   2                   1                        -   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 -   *  +-------------------------------+-------+-------+-------+-------+ -   *  |                                               | DAC1  |  DAC0 | -   *  +-------------------------------+-------+-------+-------+-------+ -   *  -   *  There are N DUCs (1 now) with complex inputs and outputs. -   *  There are two DACs. -   *  -   *  Each 4-bit DACx field specifies the source for the DAC -   *  Each subfield is coded like this:  -   *  -   *     3 2 1 0 -   *    +-------+ -   *    |   N   | -   *    +-------+ -   *  -   *  N specifies which DUC output is connected to this DAC. -   *  -   *   N   which interp output -   *  ---  ------------------- -   *   0   DUC 0 I -   *   1   DUC 0 Q -   *   2   DUC 1 I -   *   3   DUC 1 Q -   *   F   All Zeros -   *    -   * The default value is 0x10 -   * </pre> -   */ -  volatile uint32_t	tx_mux; - -} dsp_tx_regs_t; -   -#define dsp_tx_regs ((dsp_tx_regs_t *) _SR_ADDR(SR_TX_DSP)) - -// --- VITA RX CTRL regs --- -typedef struct { -  // The following 3 are logically a single command register. -  // They are clocked into the underlying fifo when time_ticks is written. -  volatile uint32_t	cmd;		// {now, chain, num_samples(30) -  volatile uint32_t	time_secs; -  volatile uint32_t	time_ticks; - -  volatile uint32_t	clear_overrun;	// write anything to clear overrun -  volatile uint32_t	vrt_header;	// word 0 of packet.  FPGA fills in packet counter -  volatile uint32_t	vrt_stream_id;	// word 1 of packet.  -  volatile uint32_t	vrt_trailer; -  volatile uint32_t	nsamples_per_pkt; -  volatile uint32_t     nchannels;      // 1 in basic case, up to 4 for vector sources -  volatile uint32_t     pad[7];         // Make each structure 16 elements long -} sr_rx_ctrl_t; - -#define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL)) - -// --- dsp rx regs --- -#define	MIN_CIC_DECIM	1 -#define	MAX_CIC_DECIM   128 - -typedef struct { -  volatile int32_t	freq; -  volatile uint32_t	scale_iq;	// {scale_i,scale_q} -  volatile uint32_t     decim_rate; -  volatile uint32_t     dcoffset_i;     // Bit 31 high sets fixed offset mode, using lower 14 bits, -                                        // otherwise it is automatic  -  volatile uint32_t     dcoffset_q;     // Bit 31 high sets fixed offset mode, using lower 14 bits - -  /*! -   * \brief input mux configuration. -   * -   * This determines which ADC (or constant zero) is connected to  -   * each DDC input.  There are N DDCs (1 now).  Each has two inputs. -   * -   * <pre> -   * Mux value: -   * -   *    3                   2                   1                        -   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 -   * +-------+-------+-------+-------+-------+-------+-------+-------+ -   * |                                                       |Q0 |I0 | -   * +-------+-------+-------+-------+-------+-------+-------+-------+ -   * -   * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) -   * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) -   * -   * The default value is 0x4 -   * </pre> -   */ -  volatile uint32_t     rx_mux;        // called adc_mux in dsp_core_rx.v - -  /*! -   * \brief Streaming GPIO configuration -   * -   * This determines whether the LSBs of I and Q samples come from the DSP -   * pipeline or from the io_rx GPIO pins.  To stream GPIO, one must first -   * set the GPIO data direction register to have io_rx[15] and/or io_rx[14] -   * configured as inputs.  The GPIO pins will be sampled at the time the -   * remainder of the DSP sample is strobed into the RX sample FIFO.  There -   * will be a decimation-dependent fixed time offset between the GPIO -   * sample stream and the associated RF samples. -   * -   *    3                   2                   1                        -   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 -   * +-------+-------+-------+-------+-------+-------+-------+-------+ -   * |                           MBZ                             |Q|I| -   * +-------+-------+-------+-------+-------+-------+-------+-------+ -   * -   * I         0=LSB comes from DSP pipeline (default) -   *           1=LSB comes from io_rx[15] -   *  -   * Q         0=LSB comes from DSP pipeline (default) -   *           1=LSB comes from io_rx[14] -   */ -  volatile uint32_t gpio_stream_enable; - -} dsp_rx_regs_t; -   -#define dsp_rx_regs ((dsp_rx_regs_t *) _SR_ADDR(SR_RX_DSP)) - -// ---------------------------------------------------------------- -// VITA49 64 bit time (write only) -  /*! -   * \brief Time 64 flags -   * -   * <pre> -   * -   *    3                   2                   1                        -   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 -   * +-----------------------------------------------------------+-+-+ -   * |                                                           |S|P| -   * +-----------------------------------------------------------+-+-+ -   * -   * P - PPS edge selection (0=negedge, 1=posedge, default=0) -   * S - Source (0=sma, 1=mimo, 0=default) -   * -   * </pre> -   */ -typedef struct { -  volatile uint32_t	secs;	// value to set absolute secs to on next PPS -  volatile uint32_t	ticks;	// value to set absolute ticks to on next PPS -  volatile uint32_t flags;  // flags - see chart above -  volatile uint32_t imm;    // set immediate (0=latch on next pps, 1=latch immediate, default=0) -} sr_time64_t; - -#define sr_time64 ((sr_time64_t *) _SR_ADDR(SR_TIME64)) - - -/*  - * --- ethernet tx protocol engine regs (write only) --- - * - * These registers control the transmit portion of the ethernet - * protocol engine (out of USRP2).  The protocol engine handles fifo - * status and sequence number insertion in outgoing packets, and - * automagically generates status packets when required to inform the - * host of changes in fifo availability. - * - * All outgoing packets have their fifo_status field set to the number - * of 32-bit lines of fifo available in the ethernet Rx fifo (see - * usrp2_eth_packet.h).  Seqno's are set if FIXME, else 0. - * - * FIXME clean this up once we know how it's supposed to behave. - */ - -typedef struct { -  volatile uint32_t  flags;	     // not yet fully defined (channel?) -  volatile uint32_t  mac_dst0123;    // 4 bytes of destination mac addr -  volatile uint32_t  mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr -  volatile uint32_t  mac_src2345;    // 4 bytes of destination mac addr -  volatile uint32_t  seqno;	     // Write to init seqno.  It autoincs on match -} tx_proto_engine_regs_t; - -#define tx_proto_engine ((tx_proto_engine_regs_t *) TX_PROTOCOL_ENGINE_BASE) - -/* - * --- ethernet rx protocol engine regs (write only) --- - * - * These registers control the receive portion of the ethernet - * protocol engine (into USRP2).  The protocol engine offloads common - * packet inspection operations so that firmware has less to do on - * "fast path" packets. - * - * The registers define conditions which must be matched for a packet - * to be considered a "fast path" packet.  If a received packet - * matches the src and dst mac address, ethertype, flags field, and - * expected seqno number it is considered a "fast path" packet, and - * the expected seqno is updated.  If the packet fails to satisfy any - * of the above conditions it's a "slow path" packet, and the - * corresponding SLOWPATH flag will be set buffer_status register. - */ - -typedef struct { -  volatile uint32_t  flags;	     // not yet fully defined (channel?) -  volatile uint32_t  mac_dst0123;    // 4 bytes of destination mac addr -  volatile uint32_t  mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr -  volatile uint32_t  mac_src2345;    // 4 bytes of destination mac addr -  volatile uint32_t  ethertype_pad;  // ethertype in high 16-bits -} rx_proto_engine_regs_t; - -#define rx_proto_engine ((rx_proto_engine_regs_t *) RX_PROTOCOL_ENGINE_BASE) - - - -/////////////////////////////////////////////////// -// Simple Programmable Interrupt Controller, Slave 8 - -#define PIC_BASE  0xD800 - -// Interrupt request lines -// Bit numbers (LSB == 0) that correpond to interrupts into PIC - -#define	IRQ_BUFFER	0	// buffer manager -#define	IRQ_ONETIME	1 -#define	IRQ_SPI		2 -#define	IRQ_I2C		3 -#define	IRQ_PHY		4	// ethernet PHY -#define	IRQ_UNDERRUN	5 -#define	IRQ_OVERRUN	6 -#define	IRQ_PPS		7	// pulse per second -#define	IRQ_UART_RX	8 -#define	IRQ_UART_TX	9 -#define	IRQ_SERDES	10 -#define	IRQ_CLKSTATUS	11 -#define IRQ_PERIODIC    12 - -#define IRQ_TO_MASK(x) (1 << (x)) - -#define PIC_BUFFER_INT    IRQ_TO_MASK(IRQ_BUFFER) -#define PIC_ONETIME_INT   IRQ_TO_MASK(IRQ_ONETIME) -#define PIC_SPI_INT       IRQ_TO_MASK(IRQ_SPI) -#define PIC_I2C_INT       IRQ_TO_MASK(IRQ_I2C) -#define PIC_PHY_INT       IRQ_TO_MASK(IRQ_PHY) -#define PIC_UNDERRUN_INT  IRQ_TO_MASK(IRQ_UNDERRUN) -#define PIC_OVERRUN_INT   IRQ_TO_MASK(IRQ_OVERRUN) -#define PIC_PPS_INT   	  IRQ_TO_MASK(IRQ_PPS) -#define PIC_UART_RX_INT   IRQ_TO_MASK(IRQ_UART_RX) -#define PIC_UART_TX_INT   IRQ_TO_MASK(IRQ_UART_TX) -#define PIC_SERDES        IRQ_TO_MASK(IRQ_SERDES) -#define PIC_CLKSTATUS     IRQ_TO_MASK(IRQ_CLKSTATUS) - -typedef struct { -  volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level -  volatile uint32_t polarity;	 // mask: 1 -> rising edge -  volatile uint32_t mask;	 // mask: 1 -> disabled -  volatile uint32_t pending;	 // mask: 1 -> pending; write 1's to clear pending ints -} pic_regs_t; - -#define pic_regs ((pic_regs_t *) PIC_BASE) - -// ---------------------------------------------------------------- -// WB_CLK_RATE is the time base for this -typedef struct { -  volatile uint32_t	onetime;   // Number of wb clk cycles till the onetime interrupt -  volatile uint32_t	periodic;  // Repeat rate of periodic interrupt -} sr_simple_timer_t; - -#define sr_simple_timer ((sr_simple_timer_t *) _SR_ADDR(SR_SIMTIMER)) - -/////////////////////////////////////////////////// -// UART, Slave 10 - -#define UART_BASE  0xE000 - -typedef struct { -  //  All elements are 8 bits except for clkdiv (16), but we use uint32 to make  -  //    the hardware for decoding easier -  volatile uint32_t clkdiv;  // Set to 50e6 divided by baud rate (no x16 factor) -  volatile uint32_t txlevel; // Number of spaces in the FIFO for writes -  volatile uint32_t rxlevel; // Number of available elements in the FIFO for reads -  volatile uint32_t txchar;  // Write characters to be sent here -  volatile uint32_t rxchar;  // Read received characters here -} uart_regs_t; - -#define uart_regs ((uart_regs_t *) UART_BASE) - -/////////////////////////////////////////////////// -// ATR Controller, Slave 11 - -#define ATR_BASE  0xE400 - -typedef struct { -  volatile uint32_t	v[16]; -} atr_regs_t; - -#define	ATR_IDLE	0x0	// indicies into v -#define ATR_TX		0x1 -#define	ATR_RX		0x2 -#define	ATR_FULL	0x3 - -#define atr_regs ((atr_regs_t *) ATR_BASE) - -/////////////////////////////////////////////////// -// SD Card SPI interface, Slave 13 -//   All regs are 8 bits wide, but are accessed as if they are 32 bits - -#define SDSPI_BASE  0xEC00 - -typedef struct { -  volatile uint32_t status;  // Write a 1 or 0 for controlling CS -  volatile uint32_t clkdiv; -  volatile uint32_t send_dat; -  volatile uint32_t receive_dat; -} sdspi_regs_t; - -#define sdspi_regs ((sdspi_regs_t *) SDSPI_BASE) - -/////////////////////////////////////////////////// -// External RAM interface, Slave 14 -//   Pages are 1K.  Page is 10 bits, set by a control register -//    output_regs->ram_page - -#define EXTRAM_BASE 0xF000 -#define extram ((volatile uint32_t *) EXTRAM_BASE) - - -/////////////////////////////////////////////////// - -#endif - diff --git a/firmware/microblaze/lib/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/sd.c b/firmware/microblaze/lib/sd.c deleted file mode 100644 index d000b28ae..000000000 --- a/firmware/microblaze/lib/sd.c +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- c -*- */ -/* - * Copyright 2008 Ettus Research LLC - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#include "sd.h" -#include "memory_map.h" -#include "stdint.h" -#include "stdio.h" - -static inline void -sd_packarg(unsigned char *argument,unsigned int value) -{ -  argument[3] = (unsigned char)(value >> 24); -  argument[2] = (unsigned char)(value >> 16); -  argument[1] = (unsigned char)(value >> 8); -  argument[0] = (unsigned char)(value); -} - -int -sd_init(void) -{ -  unsigned char response[5]; -  unsigned char argument[4]; -  int i,j; - -  for(i=0;i<4;i++) -    argument[i] = 0; - -  // Set clock to less than 400 kHz to start out -  sdspi_regs->clkdiv = 128; - -  // Delay at least 74 cycles -  sd_assert_cs(); -  for(i = 0; i < 100; i++) -    sd_send_byte(SD_IDLE); -  sd_deassert_cs(); -   -  // Initialization Sequence -- CMD0 CMD55 ACMD41 CMD58 -  // Put card in idle state -  if(sd_send_command(SD_CMD0,SD_CMD0_R,response,argument)==0) -    return 0;  // Something went wrong in command - -  j = 0; -  do { -    j++; -    if(sd_send_command(SD_CMD55,SD_CMD55_R,response,argument)==1) -      sd_send_command(SD_ACMD41,SD_ACMD41_R,response,argument); -    else -      j = SD_IDLE_WAIT_MAX; -  } -  while(((response[0] & SD_MSK_IDLE) == SD_MSK_IDLE) && (j < SD_IDLE_WAIT_MAX)); - -  if(j>= SD_IDLE_WAIT_MAX)  // IDLE timeout exceeded, card asleep -    return 0; -   -  // CMD58 reads the SD card capabilities -  if(sd_send_command(SD_CMD58,SD_CMD58_R,response,argument)==0) -    return 0;  // CMD58 FAIL - -  if((response[2] & SD_MSK_OCR_33) != SD_MSK_OCR_33) -    return 0;  // Card doesn't do 3.3V - -  //printf("OCR = %x %x %x %x\n",response[0],response[1],response[2],response[3]); - -  // Set blocklen here -  sd_packarg(argument,SD_BLOCKLEN); -  if(sd_send_command(SD_CMD16,SD_CMD16_R,response,argument)==0) -    return 0;    // Set Blocklen failed -   -  // Reset back to high speed -  sdspi_regs->clkdiv = 4; -  //puts("finished init\n"); -  return 1; -} - -int sd_send_command(unsigned char cmd,unsigned char response_type, -		    unsigned char *response,unsigned char *argument) -{ -  int i; -  char response_length; -  unsigned char tmp; - -  sd_assert_cs(); -  sd_send_byte((cmd & 0x3F) | 0x40); -  for(i=3;i>=0;i--) -    sd_send_byte(argument[i]); -  sd_send_byte(SD_CRC);   // Always the same - -  response_length = 0; -  switch(response_type) -    { -    case SD_R1: -    case SD_R1B: -      response_length = 1; -      break; -    case SD_R2: -      response_length = 2; -      break; -    case SD_R3: -      response_length = 5; -      break; -    default: -      break; -    } - -  // Wait for a response, which will have a 0 start bit -  i = 0; -  do -    { -      tmp = sd_rcv_byte(); -      i++; -    } -  while(((tmp & 0x80) != 0) && i < SD_CMD_TIMEOUT); - -  if(i>= SD_CMD_TIMEOUT) -    { -      sd_deassert_cs(); -      //puts("cmd send timeout\n"); -      return 0; -    } - -  for(i=response_length-1; i>=0; i--) -    { -      response[i] = tmp; -      tmp = sd_rcv_byte(); -    } -  i = 0; -  if(response_type == SD_R1B) -    { -      do -	{ -	  i++; -	  tmp = sd_rcv_byte(); -	} -      while(tmp != SD_IDLE); -      sd_send_byte(SD_IDLE); -    } -   -  //puts("send cmd success\n"); -  sd_deassert_cs(); -  return 1; -} - -int -sd_read_block (unsigned int blockaddr, unsigned char *buf) -{ -  unsigned char response[5]; -  unsigned char argument[4]; -  unsigned int i = 0; -  unsigned char tmp; - -  blockaddr <<= SD_BLOCKLEN_NBITS; -  sd_packarg(argument,blockaddr); -  if(sd_send_command(SD_CMD17,SD_CMD17_R,response,argument)==0) -    return 0;    //Failed READ; -  if(response[0] != 0) -    return 0;    //Misaligned READ - -  sd_assert_cs(); -  i = 0; -  do -    { -      tmp = sd_rcv_byte(); -      i++; -    } -  while((tmp == 0xFF) && (i < SD_RD_TIMEOUT)); -  if((i>= SD_RD_TIMEOUT) ||((tmp & SD_MSK_TOK_DATAERROR) == 0)) -    { -      sd_send_byte(SD_IDLE);  // Send a dummy before quitting -      return 0;   // Data ERROR -    } -  for(i=0;i<SD_BLOCKLEN;i++) -    buf[i] = sd_rcv_byte(); -  return 1; - -} - -int -sd_write_block(unsigned int blockaddr, const unsigned char *buf) -{ -  // FIXME not implemented yet -  return 0; -} diff --git a/firmware/microblaze/lib/sd.h b/firmware/microblaze/lib/sd.h deleted file mode 100644 index e2d0ae38e..000000000 --- a/firmware/microblaze/lib/sd.h +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- c -*- */ -/* - * Copyright 2008 Ettus Research LLC - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef INCLUDED_SD_H -#define INCLUDED_SD_H - -#include "memory_map.h" - -#define SD_READY 1 -#define SD_IDLE_WAIT_MAX 100 -#define SD_CMD_TIMEOUT 100 -#define SD_RD_TIMEOUT 1000 - -#define SD_CMD0 0 -#define SD_CMD1 1 -#define SD_CMD9 9 -#define SD_CMD10 10 -#define SD_CMD12 12 -#define SD_CMD13 13 -#define SD_CMD16 16 -#define SD_CMD17 17  -#define SD_CMD18 18 -#define SD_CMD24 24 -#define SD_CMD25 25 -#define SD_CMD27 27 -#define SD_CMD28 28 -#define SD_CMD29 29 -#define SD_CMD30 30 -#define SD_CMD32 32 -#define SD_CMD33 33 -#define SD_CMD38 38 -#define SD_CMD55 55 -#define SD_CMD58 58 -#define SD_CMD59 59 -#define SD_ACMD41 41 -#define SD_IDLE 0xFF -#define SD_CRC 0x95 - -#define SD_R1 1 -#define SD_R1B 2 -#define SD_R2 3 -#define SD_R3 4 - -#define SD_CMD0_R SD_R1 -#define SD_CMD16_R SD_R1 -#define SD_CMD17_R SD_R1 -#define SD_CMD55_R SD_R1 -#define SD_ACMD41_R SD_R1 -#define SD_CMD58_R SD_R3 - -#define SD_BLOCKLEN 512 -#define SD_BLOCKLEN_NBITS 9 - -#define SD_MSK_IDLE 0x01 -#define SD_MSK_OCR_33 0xC0 -#define SD_MSK_TOK_DATAERROR 0xE0 - - -int sd_init(void); - -static inline void -sd_assert_cs(void) -{ -  // Wait for idle before doing anything -  while(sdspi_regs->status != SD_READY) -    ; -  sdspi_regs->status = 1; -} - -static inline void -sd_deassert_cs(void) -{ -  // Wait for idle before doing anything -  while(sdspi_regs->status != SD_READY) -    ; -  sdspi_regs->status = 0; -} - -static inline char -sd_rcv_byte(void) -{ -  // Wait for idle before doing anything -  while(sdspi_regs->status != SD_READY) -    ; -  sdspi_regs->send_dat = SD_IDLE; -  while(sdspi_regs->status != SD_READY) -    ; -  return sdspi_regs-> receive_dat; -} - -static inline void -sd_send_byte(char dat) -{ -  // Wait for idle before doing anything -  while(sdspi_regs->status != SD_READY) -    ;      // Wait for status = 1 (ready) -  sdspi_regs->send_dat = dat; -} - - -int sd_send_command(unsigned char cmd,unsigned char response_type, -		    unsigned char *response,unsigned char *argument); - -int sd_read_block (unsigned int blockaddr, unsigned char *buf); -int sd_write_block(unsigned int blockaddr, const unsigned char *buf); - -#endif /* INCLUDED_SD_H */ diff --git a/firmware/microblaze/lib/spi.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 + +} | 
