diff options
136 files changed, 5928 insertions, 864 deletions
diff --git a/firmware/microblaze/.gitignore b/firmware/microblaze/.gitignore index 068f01838..e867fe87c 100644 --- a/firmware/microblaze/.gitignore +++ b/firmware/microblaze/.gitignore @@ -5,6 +5,8 @@ /*.log /*.rom /.deps +/*.guess +/*.sub /Makefile /Makefile.in /aclocal.m4 diff --git a/firmware/microblaze/Makefile.am b/firmware/microblaze/Makefile.am index 676c4fe42..ffc59192d 100644 --- a/firmware/microblaze/Makefile.am +++ b/firmware/microblaze/Makefile.am @@ -22,6 +22,7 @@ include $(top_srcdir)/Makefile.common EXTRA_DIST = \ u2_flash_tool -SUBDIRS = include lib apps - - +SUBDIRS = \ + usrp2 \ + usrp2p \ + usrp2p/bootloader diff --git a/firmware/microblaze/Makefile.common b/firmware/microblaze/Makefile.common index 3d0f540d8..ceb6a553a 100644 --- a/firmware/microblaze/Makefile.common +++ b/firmware/microblaze/Makefile.common @@ -17,6 +17,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # +include $(top_srcdir)/lib/Makefile.inc + ######################################################################## # lwIP header include dirs ######################################################################## @@ -29,21 +31,12 @@ LWIP_INCLUDES = \ -I$(LWIPDIR)/src/include/ipv4 ######################################################################## -# local include dirs -######################################################################## -LOCAL_INCLUDES = \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/lib - -######################################################################## # misc flags for the mb-gcc compiler ######################################################################## MBGCC_CFLAGS = \ --std=gnu99 -Wall -Werror-implicit-function-declaration \ -mxl-soft-div -msoft-float -mxl-soft-mul -mxl-barrel-shift -MBGCC_LFLAGS = -Wl,-defsym -Wl,_STACK_SIZE=3072 - ######################################################################## # define for the hal io (FIXME move?) ######################################################################## @@ -51,31 +44,39 @@ MBGCC_LFLAGS = -Wl,-defsym -Wl,_STACK_SIZE=3072 HAL_IO = -DHAL_IO_USES_UART ######################################################################## -# set the cflags and ldflags +# common cflags and ldflags ######################################################################## -AM_CFLAGS = $(MBGCC_CFLAGS) $(LOCAL_INCLUDES) $(LWIP_INCLUDES) $(HAL_IO) +COMMON_CFLAGS = \ + -I$(top_srcdir)/../../host/lib/usrp \ + -I$(top_srcdir)/lib \ + $(MBGCC_CFLAGS) \ + $(LWIP_INCLUDES) \ + $(HAL_IO) -AM_LDFLAGS = $(MBGCC_LFLAGS) +COMMON_LFLAGS = \ + -Wl,-Map -Wl,$(@:.elf=.map) ######################################################################## # Common stuff for building top level microblaze images ######################################################################## -AM_LDFLAGS += -Wl,-Map -Wl,$(@:.elf=.map) - -%.bin : %.elf +.elf.bin: $(MB_OBJCOPY) -O binary $< $@ -%.dump : %.elf +.elf.dump: $(MB_OBJDUMP) -DSC $< > $@ -%.rom : %.bin +.bin.rom: $(HEXDUMP) -v -e'1/1 "%.2X\n"' $< > $@ +.elf.ihx: + $(MB_OBJCOPY) -O ihex $(COMMON_IHX_ARGS) $< $@ + _generated_from_elf = \ $(noinst_PROGRAMS:.elf=.map) \ $(noinst_PROGRAMS:.elf=.bin) \ $(noinst_PROGRAMS:.elf=.dump) \ - $(noinst_PROGRAMS:.elf=.rom) + $(noinst_PROGRAMS:.elf=.rom) \ + $(noinst_PROGRAMS:.elf=.ihx) noinst_DATA = $(_generated_from_elf) diff --git a/firmware/microblaze/apps/blinkenlights.c b/firmware/microblaze/apps/blinkenlights.c new file mode 100644 index 000000000..4cebe5c9d --- /dev/null +++ b/firmware/microblaze/apps/blinkenlights.c @@ -0,0 +1,26 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include "memory_map.h" +#include <nonstdio.h> + +int main(int argc, char *argv[]) { + + uint32_t c = 0; + uint8_t i = 0; + + while(1) { + //delay(5000000); + for(c=0;c<5000000;c++) asm("NOP"); + output_regs->leds = (i++ % 2) ? 0xFF : 0x00; //blink everything on that register + } + + return 0; +} + +//void delay(uint32_t t) { +// while(t-- != 0) asm("NOP"); +//} diff --git a/firmware/microblaze/apps/Makefile.am b/firmware/microblaze/apps/cruft/Makefile.am index a4f79935b..a4f79935b 100644 --- a/firmware/microblaze/apps/Makefile.am +++ b/firmware/microblaze/apps/cruft/Makefile.am diff --git a/firmware/microblaze/apps/app_passthru_v2.c b/firmware/microblaze/apps/cruft/app_passthru_v2.c index 406c56b3b..406c56b3b 100644 --- a/firmware/microblaze/apps/app_passthru_v2.c +++ b/firmware/microblaze/apps/cruft/app_passthru_v2.c diff --git a/firmware/microblaze/apps/app_passthru_v2.h b/firmware/microblaze/apps/cruft/app_passthru_v2.h index 3904c670f..3904c670f 100644 --- a/firmware/microblaze/apps/app_passthru_v2.h +++ b/firmware/microblaze/apps/cruft/app_passthru_v2.h diff --git a/firmware/microblaze/apps/blink_leds.c b/firmware/microblaze/apps/cruft/blink_leds.c index 682ca8db2..682ca8db2 100644 --- a/firmware/microblaze/apps/blink_leds.c +++ b/firmware/microblaze/apps/cruft/blink_leds.c diff --git a/firmware/microblaze/apps/blink_leds2.c b/firmware/microblaze/apps/cruft/blink_leds2.c index 13e78afb3..13e78afb3 100644 --- a/firmware/microblaze/apps/blink_leds2.c +++ b/firmware/microblaze/apps/cruft/blink_leds2.c diff --git a/firmware/microblaze/apps/buf_ram_test.c b/firmware/microblaze/apps/cruft/buf_ram_test.c index 1aca2aec5..1aca2aec5 100644 --- a/firmware/microblaze/apps/buf_ram_test.c +++ b/firmware/microblaze/apps/cruft/buf_ram_test.c diff --git a/firmware/microblaze/apps/burn_dbsrx_eeprom.c b/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c index 116d4d8d0..116d4d8d0 100644 --- a/firmware/microblaze/apps/burn_dbsrx_eeprom.c +++ b/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c diff --git a/firmware/microblaze/apps/burnrev30.c b/firmware/microblaze/apps/cruft/burnrev30.c index 40fa53e34..40fa53e34 100644 --- a/firmware/microblaze/apps/burnrev30.c +++ b/firmware/microblaze/apps/cruft/burnrev30.c diff --git a/firmware/microblaze/apps/burnrev31.c b/firmware/microblaze/apps/cruft/burnrev31.c index f6b08d187..f6b08d187 100644 --- a/firmware/microblaze/apps/burnrev31.c +++ b/firmware/microblaze/apps/cruft/burnrev31.c diff --git a/firmware/microblaze/apps/can_i_sub.c b/firmware/microblaze/apps/cruft/can_i_sub.c index ed49791f0..ed49791f0 100644 --- a/firmware/microblaze/apps/can_i_sub.c +++ b/firmware/microblaze/apps/cruft/can_i_sub.c diff --git a/firmware/microblaze/apps/double_buffer_fragment.c b/firmware/microblaze/apps/cruft/double_buffer_fragment.c index cfc061247..cfc061247 100644 --- a/firmware/microblaze/apps/double_buffer_fragment.c +++ b/firmware/microblaze/apps/cruft/double_buffer_fragment.c diff --git a/firmware/microblaze/apps/echo.c b/firmware/microblaze/apps/cruft/echo.c index 89108ee80..89108ee80 100644 --- a/firmware/microblaze/apps/echo.c +++ b/firmware/microblaze/apps/cruft/echo.c diff --git a/firmware/microblaze/apps/eth_serdes.c b/firmware/microblaze/apps/cruft/eth_serdes.c index 2d2ddc1ca..2d2ddc1ca 100644 --- a/firmware/microblaze/apps/eth_serdes.c +++ b/firmware/microblaze/apps/cruft/eth_serdes.c diff --git a/firmware/microblaze/apps/factory_test.c b/firmware/microblaze/apps/cruft/factory_test.c index e1fbb0e40..e1fbb0e40 100644 --- a/firmware/microblaze/apps/factory_test.c +++ b/firmware/microblaze/apps/cruft/factory_test.c diff --git a/firmware/microblaze/apps/gen_eth_packets.c b/firmware/microblaze/apps/cruft/gen_eth_packets.c index 4d521f6bf..4d521f6bf 100644 --- a/firmware/microblaze/apps/gen_eth_packets.c +++ b/firmware/microblaze/apps/cruft/gen_eth_packets.c diff --git a/firmware/microblaze/apps/gen_pause_frames.c b/firmware/microblaze/apps/cruft/gen_pause_frames.c index 0f81dafff..0f81dafff 100644 --- a/firmware/microblaze/apps/gen_pause_frames.c +++ b/firmware/microblaze/apps/cruft/gen_pause_frames.c diff --git a/firmware/microblaze/apps/hello.c b/firmware/microblaze/apps/cruft/hello.c index bce843093..bce843093 100644 --- a/firmware/microblaze/apps/hello.c +++ b/firmware/microblaze/apps/cruft/hello.c diff --git a/firmware/microblaze/apps/ibs_rx_test.c b/firmware/microblaze/apps/cruft/ibs_rx_test.c index bdc04747e..bdc04747e 100644 --- a/firmware/microblaze/apps/ibs_rx_test.c +++ b/firmware/microblaze/apps/cruft/ibs_rx_test.c diff --git a/firmware/microblaze/apps/ibs_tx_test.c b/firmware/microblaze/apps/cruft/ibs_tx_test.c index ff9446d92..ff9446d92 100644 --- a/firmware/microblaze/apps/ibs_tx_test.c +++ b/firmware/microblaze/apps/cruft/ibs_tx_test.c diff --git a/firmware/microblaze/apps/mimo_app_common_v2.c b/firmware/microblaze/apps/cruft/mimo_app_common_v2.c index 5dbecb0d0..5dbecb0d0 100644 --- a/firmware/microblaze/apps/mimo_app_common_v2.c +++ b/firmware/microblaze/apps/cruft/mimo_app_common_v2.c diff --git a/firmware/microblaze/apps/mimo_app_common_v2.h b/firmware/microblaze/apps/cruft/mimo_app_common_v2.h index 1e62ced37..1e62ced37 100644 --- a/firmware/microblaze/apps/mimo_app_common_v2.h +++ b/firmware/microblaze/apps/cruft/mimo_app_common_v2.h diff --git a/firmware/microblaze/apps/mimo_tx.c b/firmware/microblaze/apps/cruft/mimo_tx.c index e0f8aa6fa..e0f8aa6fa 100644 --- a/firmware/microblaze/apps/mimo_tx.c +++ b/firmware/microblaze/apps/cruft/mimo_tx.c diff --git a/firmware/microblaze/apps/mimo_tx_slave.c b/firmware/microblaze/apps/cruft/mimo_tx_slave.c index cdf9c03c2..cdf9c03c2 100644 --- a/firmware/microblaze/apps/mimo_tx_slave.c +++ b/firmware/microblaze/apps/cruft/mimo_tx_slave.c diff --git a/firmware/microblaze/apps/rcv_eth_packets.c b/firmware/microblaze/apps/cruft/rcv_eth_packets.c index 03fc94354..03fc94354 100644 --- a/firmware/microblaze/apps/rcv_eth_packets.c +++ b/firmware/microblaze/apps/cruft/rcv_eth_packets.c diff --git a/firmware/microblaze/apps/read_dbids.c b/firmware/microblaze/apps/cruft/read_dbids.c index 24c6d9ab4..24c6d9ab4 100644 --- a/firmware/microblaze/apps/read_dbids.c +++ b/firmware/microblaze/apps/cruft/read_dbids.c diff --git a/firmware/microblaze/apps/sd_bounce.c b/firmware/microblaze/apps/cruft/sd_bounce.c index c1b48f170..c1b48f170 100644 --- a/firmware/microblaze/apps/sd_bounce.c +++ b/firmware/microblaze/apps/cruft/sd_bounce.c diff --git a/firmware/microblaze/apps/sd_gentest.c b/firmware/microblaze/apps/cruft/sd_gentest.c index 35e912615..35e912615 100644 --- a/firmware/microblaze/apps/sd_gentest.c +++ b/firmware/microblaze/apps/cruft/sd_gentest.c diff --git a/firmware/microblaze/apps/serdes_to_dsp.c b/firmware/microblaze/apps/cruft/serdes_to_dsp.c index 4994e0a69..4994e0a69 100644 --- a/firmware/microblaze/apps/serdes_to_dsp.c +++ b/firmware/microblaze/apps/cruft/serdes_to_dsp.c diff --git a/firmware/microblaze/apps/serdes_txrx.c b/firmware/microblaze/apps/cruft/serdes_txrx.c index 2c47c9628..2c47c9628 100644 --- a/firmware/microblaze/apps/serdes_txrx.c +++ b/firmware/microblaze/apps/cruft/serdes_txrx.c diff --git a/firmware/microblaze/apps/set_hw_rev.c b/firmware/microblaze/apps/cruft/set_hw_rev.c index d4ac8ff81..d4ac8ff81 100644 --- a/firmware/microblaze/apps/set_hw_rev.c +++ b/firmware/microblaze/apps/cruft/set_hw_rev.c diff --git a/firmware/microblaze/apps/test1.c b/firmware/microblaze/apps/cruft/test1.c index c3cc3be56..c3cc3be56 100644 --- a/firmware/microblaze/apps/test1.c +++ b/firmware/microblaze/apps/cruft/test1.c diff --git a/firmware/microblaze/apps/test_db_spi.c b/firmware/microblaze/apps/cruft/test_db_spi.c index f4fa98ef1..f4fa98ef1 100644 --- a/firmware/microblaze/apps/test_db_spi.c +++ b/firmware/microblaze/apps/cruft/test_db_spi.c diff --git a/firmware/microblaze/apps/test_i2c.c b/firmware/microblaze/apps/cruft/test_i2c.c index f349ead88..f349ead88 100644 --- a/firmware/microblaze/apps/test_i2c.c +++ b/firmware/microblaze/apps/cruft/test_i2c.c diff --git a/firmware/microblaze/apps/test_lsadc.c b/firmware/microblaze/apps/cruft/test_lsadc.c index 5fda29cd7..5fda29cd7 100644 --- a/firmware/microblaze/apps/test_lsadc.c +++ b/firmware/microblaze/apps/cruft/test_lsadc.c diff --git a/firmware/microblaze/apps/test_lsdac.c b/firmware/microblaze/apps/cruft/test_lsdac.c index 8c1bf333b..8c1bf333b 100644 --- a/firmware/microblaze/apps/test_lsdac.c +++ b/firmware/microblaze/apps/cruft/test_lsdac.c diff --git a/firmware/microblaze/apps/test_phy_comm.c b/firmware/microblaze/apps/cruft/test_phy_comm.c index d312ca4cc..d312ca4cc 100644 --- a/firmware/microblaze/apps/test_phy_comm.c +++ b/firmware/microblaze/apps/cruft/test_phy_comm.c diff --git a/firmware/microblaze/apps/test_ram.c b/firmware/microblaze/apps/cruft/test_ram.c index 77ee693f6..77ee693f6 100644 --- a/firmware/microblaze/apps/test_ram.c +++ b/firmware/microblaze/apps/cruft/test_ram.c diff --git a/firmware/microblaze/apps/test_sd.c b/firmware/microblaze/apps/cruft/test_sd.c index 494432d7f..494432d7f 100644 --- a/firmware/microblaze/apps/test_sd.c +++ b/firmware/microblaze/apps/cruft/test_sd.c diff --git a/firmware/microblaze/apps/timer_test.c b/firmware/microblaze/apps/cruft/timer_test.c index 44e80b5f1..44e80b5f1 100644 --- a/firmware/microblaze/apps/timer_test.c +++ b/firmware/microblaze/apps/cruft/timer_test.c diff --git a/firmware/microblaze/apps/tx_standalone.c b/firmware/microblaze/apps/cruft/tx_standalone.c index 1645fa8ba..1645fa8ba 100644 --- a/firmware/microblaze/apps/tx_standalone.c +++ b/firmware/microblaze/apps/cruft/tx_standalone.c diff --git a/firmware/microblaze/apps/flash_test.c b/firmware/microblaze/apps/flash_test.c new file mode 100644 index 000000000..5b4569030 --- /dev/null +++ b/firmware/microblaze/apps/flash_test.c @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <memory_map.h> +#include <hal_io.h> +#include <hal_uart.h> +#include <xilinx_s3_icap.h> +#include <nonstdio.h> +#include <spi_flash.h> +#include <spi.h> +#include <clocks.h> +#include <string.h> + +//just a test to write to SPI flash and retrieve the same values. +//uses the MOBFLEET SPI flash library + +void delay(uint32_t t) { + while(t-- != 0) asm("NOP"); +} + +int main(int argc, char *argv[]) { + uint16_t i, t; + uint8_t buf[260]; + const uint8_t testdata[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}; + + hal_disable_ints(); // In case we got here via jmp 0x0 +// spi_init(); + hal_uart_init(); +// clocks_init(); //set up AD9510, enable FPGA clock @ 1x divisor + + puts("SPI Flash test\n"); + puts("Initializing SPI\n"); + + spif_init(); + delay(800000); + puts("Erasing sector 1\n"); + spi_flash_erase(0x00010000, 256); + delay(800000); + puts("Reading back data\n"); + spi_flash_read(0x00010000, 256, buf); + delay(800000); + + t=1; + for(i=4; i<250; i++) { + if(buf[i] != 0xFF) t=0; + } + + if(!t) puts("Data was not initialized to 0xFF. Unsuccessful erase or read\n"); + else puts("Data initialized to 0xFF, erase confirmed\n"); + + puts("Writing test buffer\n"); + spi_flash_program(0x00010000, 16, testdata); + //memset(buf, 0, 256); + + delay(800000); + puts("Wrote data, reading back\n"); + + spi_flash_read(0x00010000, 16, buf); + + if(memcmp(testdata, buf, 16)) puts("Data is not the same between read and write. Unsuccessful write or read\n"); + else puts("Successful write! Flash write correct\n"); + + return 0; +} diff --git a/firmware/microblaze/apps/hardware_testbed.c b/firmware/microblaze/apps/hardware_testbed.c new file mode 100644 index 000000000..e68e68ff7 --- /dev/null +++ b/firmware/microblaze/apps/hardware_testbed.c @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <memory_map.h> +#include <nonstdio.h> +#include <hal_io.h> +#include <xilinx_s3_icap.h> +#include <spi_flash.h> +//#include <spi_flash_private.h> +#include <clocks.h> +#include <ihex.h> +#include <bootloader_utils.h> +#include <string.h> +#include <hal_uart.h> +#include <spi.h> + +//so this is just an evolving file used to set up and test different bits of hardware (EEPROM, clock chip, A/D, D/A, PHY) +void delay(uint32_t t) { + while(t-- != 0) asm("NOP"); +} + +int main(int argc, char *argv[]) { + + hal_disable_ints(); + hal_uart_init(); + spi_init(); + + puts("Hardware testbed. Init clocks..."); + + clocks_init(); + + //now, hopefully, we should be running at 100MHz instead of 50MHz, meaning our UART is twice as fast and we're talking at 230400. + + while(1) { + delay(500000); + puts("Eat at Joe's."); + } + + + + + + return 0; +} diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index f7f140121..4e03bc869 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -41,7 +41,6 @@ #include <stdlib.h> #include <string.h> #include "clocks.h" -#include <vrt/bits.h> #include "usrp2/fw_common.h" #include <i2c.h> #include <ethertype.h> @@ -266,7 +265,7 @@ void handle_udp_ctrl_packet( * Peek and Poke Register ******************************************************************/ case USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO: - if (ctrl_data_in->data.poke_args.addr < 0xC000){ + if (0){//ctrl_data_in->data.poke_args.addr < 0xC000){ printf("error! tried to poke into 0x%x\n", ctrl_data_in->data.poke_args.addr); } else switch(ctrl_data_in->data.poke_args.num_bytes){ diff --git a/firmware/microblaze/apps/uart_flash_loader.c b/firmware/microblaze/apps/uart_flash_loader.c new file mode 100644 index 000000000..d67b84677 --- /dev/null +++ b/firmware/microblaze/apps/uart_flash_loader.c @@ -0,0 +1,169 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +//#include <stdio.h> +#include <stdlib.h> +#include <memory_map.h> +#include <nonstdio.h> +#include <hal_io.h> +#include <hal_uart.h> +#include <xilinx_s3_icap.h> +#include <spi_flash.h> +#include <spi_flash_private.h> +//#include <clocks.h> +#include <ihex.h> +#include <bootloader_utils.h> + +//uses UART to load files to Flash in Intel HEX 16-bit format. +//this is one example of a "safe" firmware image to be loaded by a bootloader into main RAM. +//this CANNOT write to main RAM, since it is resident there. + +//Sector 0-31: Safe FPGA bootloader image +//Sector 32-63: Production bootloader image +//Sector 64: Production firmware image +//Sector 127: Safe firmware image + + +void uart_flash_loader(void) { + + char buf[256]; //input data buffer + uint8_t ihx[32]; //ihex data buffer + uint32_t slot_offset = PROD_FW_IMAGE_LOCATION_ADDR; //initial slot offset to program to. + uint32_t extended_addr = 0x00000000; //extended Intel hex segment address + + size_t sector_size = spi_flash_log2_sector_size(); + ihex_record_t ihex_record; + ihex_record.data = ihx; + int i; + + + //not gonna win a turing prize for my C text parsing + while(1) { + gets(buf); + if(!strncmp(buf, "!SECTORSIZE", 7)) { //return the sector size in log format + putstr("OK "); + puthex8((uint32_t) sector_size); //err, this should probably be decimal for human readability. we do have itoa now... + putstr("\n"); + } + else if(!strncmp(buf, "!SETADDR", 7)) { //set start address for programming + slot_offset = atol(&buf[8]); + puts("OK"); +// puthex32(slot_offset); +// putstr("\n"); + } + else if(!strncmp(buf, "!ERASE", 6)) { //erase a sector + uint32_t sector = atol(&buf[6]); + uint32_t size = 2 << (sector_size-1); + uint32_t addr = sector << sector_size; + + spi_flash_erase(addr, size); //we DO NOT implement write protection here. it is up to the HOST PROGRAM to not issue an ERASE unless it means it. + //unfortunately the Flash cannot write-protect the segments that really matter, so we only use global write-protect + //as a means of avoiding accidental writes from runaway code / garbage on the SPI bus. + puts("OK"); + } +//can't exactly run firmware if you're already executing out of main RAM +/* else if(!strncmp(buf, "!RUNSFW", 7)) { + if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) { + puts("OK"); + spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE); + start_program(RAM_BASE); + } else { + puts("NOK"); + } + } + else if(!strncmp(buf, "!RUNPFW", 7)) { + if(is_valid_fw_image(PROD_FW_IMAGE_LOCATION_ADDR)) { + puts("OK"); + spi_flash_read(PROD_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES-1, (void *)RAM_BASE); + start_program(RAM_BASE); + } else { + puts("NOK"); + } + } +*/ + else if(!strncmp(buf, "!RUNPFPGA", 8)) { + if(is_valid_fpga_image(PROD_FPGA_IMAGE_LOCATION_ADDR)) { + puts("OK"); + //icap_reload_fpga(PROD_FPGA_IMAGE_LOCATION_ADDR); + } else { + puts("NOK"); + } + } + else if(!strncmp(buf, "!RUNSFPGA", 8)) { + if(is_valid_fpga_image(SAFE_FPGA_IMAGE_LOCATION_ADDR)) { + puts("OK"); + //icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); + } else { + puts("NOK"); + } + } + else if(!strncmp(buf, "!READ", 5)) { + uint32_t addr = atol(&buf[5]); + spi_flash_read(addr, 16, ihx); + for(i=0; i < 16; i++) { + puthex8(ihx[i]); + } + putstr("\n"); + } + + else if(!ihex_parse(buf, &ihex_record)) { //last, try to see if the input was a valid IHEX line + switch (ihex_record.type) { + case 0: + spi_flash_program(ihex_record.addr + slot_offset + extended_addr, ihex_record.length, ihex_record.data); + puts("OK"); + break; + case 1: + //here we would expect a CRC checking or something else to take place. for now we do nothing. + //well, we set the extended segment addr back to 0 + extended_addr = 0; + puts("DONE"); + break; + case 4: + //set the upper 16 bits of the address + extended_addr = ((ihex_record.data[0] << 8) + ihex_record.data[1]) << 16; + puts("OK"); + break; + default: + puts("NOK"); + } + } + else puts("NOK"); + } //while(1) +} + +void delay(uint32_t t) { + while(t-- != 0) asm("NOP"); +} + +int main(int argc, char *argv[]) { + uint8_t buf[32]; + int i = 0; + + hal_disable_ints(); // In case we got here via jmp 0x0 + +// delay(10000000); + + //before anything else you might want to blinkenlights just to indicate code startup to the user. + + hal_uart_init(); + spif_init(); +// i2c_init(); //for EEPROM + puts("USRP2+ UART firmware loader"); + +// puts("Debug: loading production image, 10 bytes."); + +// spi_flash_read(PROD_FW_IMAGE_LOCATION_ADDR, 10, buf); +// for(i=0; i < 10; i++) { +// puthex8(buf[i]); +// } + + uart_flash_loader(); + + //shouldn't get here. should reboot. + puts("shit happened.\n"); + + return 0; +} diff --git a/firmware/microblaze/bin/bin_to_mif.py b/firmware/microblaze/bin/bin_to_mif.py new file mode 100755 index 000000000..cefce4e92 --- /dev/null +++ b/firmware/microblaze/bin/bin_to_mif.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import struct +import sys + +hextab = ('0000', '0001', '0010', '0011', + '0100', '0101', '0110', '0111', + '1000', '1001', '1010', '1011', + '1100', '1101', '1110', '1111') + +def w_to_binary_ascii(w): + return ''.join([hextab[(w >> 4*i) & 0xf] for i in range(7,-1,-1)]) + +def bin_to_mif(bin_input_file, mif_output_file): + ifile = open(bin_input_file, 'rb') + ofile = open(mif_output_file, 'w') + idata = ifile.read() + fmt = ">%dI" % ((len(idata) / 4),) + words = struct.unpack(fmt, idata) + for w in words: + ofile.write(w_to_binary_ascii(w)) + ofile.write('\n') + +if __name__ == '__main__': + if len(sys.argv) != 3: + sys.stderr.write("usage: bin_to_mif bin_input_file mif_output_file\n") + raise SystemExit, 1 + + bin_to_mif(sys.argv[1], sys.argv[2]) diff --git a/firmware/microblaze/bin/bin_to_ram_macro_init.py b/firmware/microblaze/bin/bin_to_ram_macro_init.py new file mode 100755 index 000000000..65cf2dbdf --- /dev/null +++ b/firmware/microblaze/bin/bin_to_ram_macro_init.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +import struct +import sys + +def do_8_words(ofile, which_ram, row, words): + ofile.write("defparam bootram.RAM%d.INIT_%02X=256'h" % (which_ram, row)) + ofile.write("%08x_%08x_%08x_%08x_%08x_%08x_%08x_%08x;\n" % ( + words[7], words[6], words[5], words[4], words[3], words[2], words[1], words[0])) + +def bin_to_ram_macro_init(bin_input_file, ram_init_output_file): + ifile = open(bin_input_file, 'rb') + ofile = open(ram_init_output_file, 'w') + idata = ifile.read() + fmt = ">%dI" % ((len(idata) / 4),) + words = struct.unpack(fmt, idata) + + # pad to a multiple of 8 words + r = len(words) % 8 + if r != 0: + words += (8 - r) * (0,) + + if len(words) > 2048: + sys.stderr.write("bin_to_macro_init: error: input file %s is > 8KiB\n" % (bin_input_file,)) + sys.exit(1) + + # first 2KB + for i in range(0, min(512, len(words)), 8): + do_8_words(ofile, 0, i/8, words[i:i+8]) + + # second 2KB + for i in range(512, min(1024, len(words)), 8): + do_8_words(ofile, 1, (i/8) % 64, words[i:i+8]) + + # third 2KB + for i in range(1024, min(1536, len(words)), 8): + do_8_words(ofile, 2, (i/8) % 64, words[i:i+8]) + + # last 2KB + for i in range(1536, len(words), 8): + do_8_words(ofile, 3, (i/8) % 64, words[i:i+8]) + +if __name__ == '__main__': + if len(sys.argv) != 3: + sys.stderr.write("usage: bin_to_ram_macro_init bin_input_file ram_init_output_file\n") + sys.exit(1) + + bin_to_ram_macro_init(sys.argv[1], sys.argv[2]) diff --git a/firmware/microblaze/bin/elf_to_sbf b/firmware/microblaze/bin/elf_to_sbf new file mode 100755 index 000000000..d1be10c0d --- /dev/null +++ b/firmware/microblaze/bin/elf_to_sbf @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import sys +import struct +from optparse import OptionParser +from pprint import pprint + +import sbf + +# see /usr/include/elf.h for the various magic values + + +_ehdr_fmt = ">16sHH5I6H" +_ehdr_fmt_size = struct.calcsize(_ehdr_fmt) +_phdr_fmt = ">8I" +_phdr_fmt_size = struct.calcsize(_phdr_fmt) + +class elf32_ehdr(object): + def __init__(self, s): + (self.ident, self.type, self.machine, self.version, self.entry, + self.phoff, self.shoff, self.flags, self.ehsize, + self.phentsize, self.phnum, self.shentsize, self.shnum, + self.shstrndx) = struct.unpack(_ehdr_fmt, s) + +class elf32_phdr(object): + def __init__(self, s): + (self.type, self.offset, self.vaddr, self.paddr, + self.filesz, self.memsz, + self.flags, self.align) = struct.unpack(_phdr_fmt, s) + + def __repr__(self): + return "<elf32_phdr %s offset=%d paddr=0x%x, filesz=%d>" % ( + p_type_str(self.type), self.offset, self.paddr, self.filesz) + + +def p_type_str(t): + if t <= 8: + return ('NULL', 'LOAD', 'DYNAMIC', 'INTERP', 'NOTE', 'SHLIB', 'PHDR', 'TLS', 'NUM')[t] + return "0x%x" % (t,) + + + +def _get_ehdr(f): + if len(f) < _ehdr_fmt_size: + return False + ehdr = elf32_ehdr(f[0:_ehdr_fmt_size]) + return ehdr + + +def elf32_big_endian_exec_p(f): + ehdr = _get_ehdr(f) + if not ehdr: + return False + + #pprint(ehdr, sys.stderr) + e_ident = ehdr.ident + if not e_ident.startswith('\177ELF'): + return False + if (ord(e_ident[4]) != 1 # EI_CLASS == CLASS32 + or ord(e_ident[5]) != 2 # EI_DATA == DATA2MSB + or ord(e_ident[6]) != 1 # EI_VERSION == EV_CURRENT + ): + return False + + if ehdr.type != 2: # e_type == ET_EXEC + return False + + return True + + + +# return (entry, (phdr, ...)) + +def get_elf32_prog_headers(f): + ehdr = _get_ehdr(f) + entry = ehdr.entry + phoff = ehdr.phoff + phentsize = ehdr.phentsize + phnum = ehdr.phnum + + def extract(i): + start = phoff + i * phentsize + end = start + phentsize + return f[start:end] + + return (entry, [elf32_phdr(extract(i)) for i in range(phnum)]) + + +def main(): + usage = "%prog: [options] elf_file" + parser = OptionParser() + parser.add_option("-o", "--output", default=None, + help="specify output filename [default=stdout]") + (options, args) = parser.parse_args() + if len(args) != 1: + parser.print_help() + sys.exit(1) + + elf_file = open(args[0], 'rb') + + elf_contents = elf_file.read() + if not elf32_big_endian_exec_p(elf_contents): + sys.stderr.write("%s: not a big-endian 32-bit ELF executable\n" % (args[0],)) + sys.exit(1) + + if options.output is None: + sbf_file = sys.stdout + else: + sbf_file = open(options.output, 'wb') + + (entry, phdrs) = get_elf32_prog_headers(elf_contents) + #pprint(phdrs, sys.stderr) + + def phdr_to_sec_desc(phdr): + target_addr = phdr.paddr + data = elf_contents[phdr.offset:phdr.offset+phdr.filesz] + #print >>sys.stderr, "pdhr_to_sec_desc:", (target_addr, data) + return sbf.sec_desc(target_addr, data) + + sections = map(phdr_to_sec_desc, phdrs) + # pprint(sections, sys.stderr) + sbf.write_sbf(sbf_file, sbf.header(entry, sections)) + + +if __name__ == '__main__': + main() diff --git a/firmware/microblaze/bin/sbf.py b/firmware/microblaze/bin/sbf.py new file mode 100644 index 000000000..8e2c868a5 --- /dev/null +++ b/firmware/microblaze/bin/sbf.py @@ -0,0 +1,134 @@ +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +_SBF_MAGIC = 'SBF!' +_SBF_DONT_EXECUTE = 0x1 +_SBF_MAX_SECTIONS = 14 +_SBF_HEADER_LEN = 128 + +import struct +import sys +from pprint import pprint + +def dump_data(f, offset, data): + L = len(data) // 4 + for i in range(L): + f.write('%08x: %08x\n' % (offset + 4 * i, struct.unpack('>I', data[4*i:4*(i+1)])[0])) + remainder = len(data) - L * 4 + if remainder != 0: + f.write('%08x: ' % (offset + L*4,)) + i = 0 + while i < remainder: + f.write('%02x' % ((ord(data[L*4 + i]),))) + i += 1 + f.write('\n') + + + +class sec_desc(object): + def __init__(self, target_addr, data): + self.target_addr = target_addr + self.data = data + + def __repr__(self): + #print >>sys.stderr, "target_addr:", self.target_addr + #print >>sys.stderr, "data:", self.data + return "<sec_desc target_addr=0x%x len=%d>" % ( + self.target_addr, len(self.data)) + + +class header(object): + def __init__(self, entry, sections): + self.entry = entry + self.section = sections + + def dump(self, f): + if self.entry == _SBF_DONT_EXECUTE: + f.write("Entry: DONT_EXECUTE\n") + else: + f.write("Entry: 0x%x\n" % (self.entry,)) + for i in range(len(self.section)): + s = self.section[i] + f.write("Section[%d]: target_addr = 0x%x length = %d\n" % (i, + s.target_addr, + len(s.data))) + dump_data(f, s.target_addr, s.data) + + # + # Returns an iterator. Each yield returns (target_addr, data) + # + def iterator(self, max_piece=512): + for s in self.section: + offset = 0 + L = len(s.data) + while offset < L: + n = min(max_piece, L - offset) + yield (s.target_addr + offset, + s.data[offset:offset+n]) + offset += n + + + +def read_sbf(input_file): + """Parse an SBF file""" + + f = input_file.read(_SBF_HEADER_LEN) + #if len(f) < _SBF_HEADER_LEN or not f.startswith(_SBF_MAGIC): + #raise ValueError, '%s: not an SBF file' % (input_file.name,) + + def extract(i): + start = 16+8*i + stop = start+8 + return struct.unpack('>2I', f[start:stop]) + + def get_data(ss): + L = ss[1] + s = input_file.read(L) + #if len(s) != L: + #raise ValueError, '%s: file is too short' % (input_file.name(),) + return s + + (magic, entry, nsections, reserved) = struct.unpack('>4s3I', f[0:16]) + assert nsections <= _SBF_MAX_SECTIONS + descs = [extract(i) for i in range(nsections)] + #pprint(descs, sys.stderr) + data = map(get_data, descs) + secs = map(lambda ss, data: sec_desc(ss[0], data), descs, data) + return header(entry, secs) + + +def write_sbf(output_file, sbf_header): + assert(len(sbf_header.section) <= _SBF_MAX_SECTIONS) + sbf_header.nsections = len(sbf_header.section) + f = output_file + + # write the file header + f.write(struct.pack('>4s3I', _SBF_MAGIC, sbf_header.entry, sbf_header.nsections, 0)) + + # write the section headers + for i in range(sbf_header.nsections): + f.write(struct.pack('>2I', + sbf_header.section[i].target_addr, + len(sbf_header.section[i].data))) + for i in range(_SBF_MAX_SECTIONS - sbf_header.nsections): + f.write(struct.pack('>2I', 0, 0)) + + # write the section data + for i in range(sbf_header.nsections): + f.write(sbf_header.section[i].data) + + return True diff --git a/firmware/microblaze/bin/serial_loader b/firmware/microblaze/bin/serial_loader new file mode 100755 index 000000000..9bd5aada7 --- /dev/null +++ b/firmware/microblaze/bin/serial_loader @@ -0,0 +1,363 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import termios +import tty +import os +import sys +import threading +import Queue +from optparse import OptionParser +import time + +import sbf + +GDB_ESCAPE = chr(0x7d) + +# Indexes for termios list. +IFLAG = 0 +OFLAG = 1 +CFLAG = 2 +LFLAG = 3 +ISPEED = 4 +OSPEED = 5 +CC = 6 + +class terminal(object): + def __init__(self, device, speed_bits): + fd = os.open(device, os.O_RDWR) + if not os.isatty(fd): + raise ValueError(device + " is not a tty") + + self.read_file = os.fdopen(fd, "rb", 0) + self.write_file = os.fdopen(os.dup(fd), "wb", 0) + self.old_attrs = termios.tcgetattr(self.write_file.fileno()) + #print "old_attrs: ", self.old_attrs + attrs = list(self.old_attrs) # copy of attributes + attrs[ISPEED] = speed_bits # set input and output speed + attrs[OSPEED] = speed_bits + termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, attrs) + tty.setraw(self.write_file.fileno()) # enable raw mode + attrs = termios.tcgetattr(self.write_file.fileno()) + attrs[CC][termios.VMIN] = 1 # minimim of 1 char + attrs[CC][termios.VTIME] = 1 # wait no longer than 1/10 + termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, attrs) + + def __del__(self): + termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, self.old_attrs) + self.read_file.close() + self.write_file.close() + + def read(self, n): + """Read at most n bytes from tty""" + return self.read_file.read(n) + + def write(self, str): + """Write str to tty.""" + return self.write_file.write(str) + + +def hexnibble(i): + return "0123456789abcdef"[i & 0xf] + +def build_pkt(payload): + s = ['$'] + checksum = 0 + + for p in payload: + if p in ('$', '#', GDB_ESCAPE): + s.append(GDB_ESCAPE) + s.append(p) + checksum += ord(p) + + checksum &= 0xff + s.append('#') + s.append(hexnibble(checksum >> 4)) + s.append(hexnibble(checksum)) + + return ''.join(s) + + +def build_memory_read_pkt(addr, len): + return build_pkt(('m%x,%x' % (addr, len))) + +def build_memory_write_hex_pkt(addr, s): + hexdata = ''.join(["%02x" % (ord(c),) for c in s]) + return build_pkt(('M%x,%x:' % (addr, len(s))) + hexdata) + +def build_memory_write_pkt(addr, s): + return build_pkt(('X%x,%x:' % (addr, len(s))) + s) + +def build_goto_pkt(addr): + return build_pkt(('c%x' % (addr,))) + + +def get_packet(f): + """Return a valid packet, or None on EOF or timeout""" + LOOKING_FOR_DOLLAR = 0 + LOOKING_FOR_HASH = 1 + CSUM1 = 2 + CSUM2 = 3 + + fd = f.fileno() + + state = LOOKING_FOR_DOLLAR + buf = [] + + while True: + ch = os.read(fd, 1) + sys.stdout.write(ch) + if len(ch) == 0: + print("Returning None") + return(None) + + if state == LOOKING_FOR_DOLLAR: + if ch == '$': + buf = [] + state = LOOKING_FOR_HASH + elif ch == '#': + state = LOOKING_FOR_DOLLAR + + elif state == LOOKING_FOR_HASH: + if ch == '$': + state = LOOKING_FOR_DOLLAR + elif ch == '#': + state = CSUM1 + else: + if ch == GDB_ESCAPE: + ch = getc() + buf.append(ch) + + elif state == CSUM1: + chksum1 = ch + state = CSUM2 + + elif state == CSUM2: + chksum2 = ch + r = ''.join(buf) + if chksum1 == '.' and chksum2 == '.': + return r + + expected_checksum = int(chksum1 + chksum2, 16) + checksum = 0 + for c in buf: + checksum += ord(c) + + checksum &= 0xff + if checksum == expected_checksum: + return r + + state = LOOKING_FOR_DOLLAR + + else: + raise ValueError( "Invalid state") + + +class packet_reader_thread(threading.Thread): + def __init__(self, tty_in, q): + threading.Thread.__init__(self) + self.setDaemon(1) + self.tty_in = tty_in + self.q = q + self._keep_running = True + self.start() + + def run(self): + while self._keep_running == True: + p = get_packet(self.tty_in) + if p is not None: + self.q.put(('pkt', p)) + + +def _make_tr_table(): + table = [] + for c in range(256): + if c < ord(' ') or c > ord('~'): + table.append('.') + else: + table.append(chr(c)) + return ''.join(table) + + +class controller(object): + def __init__(self, tty): + self.tty = tty + self.q = Queue.Queue(0) + self.timers = {} + self.next_tid = 1 + self.current_tid = 0 + self.ntimeouts = 0 + self.packet_reader = packet_reader_thread(tty.read_file, self.q) + self.state = None + self.debug = False + self.tt = _make_tr_table() + + self.done = False + self.addr = None + self.bits = None + + def shutdown(self): + self.packet_reader._keep_running = False + + def start_timeout(self, timeout_in_secs): + def callback(tid): + if self.timers.has_key(tid): + del self.timers[tid] + self.q.put(('timeout', tid)) + self.next_tid += 1 + tid = self.next_tid + timer = threading.Timer(timeout_in_secs, callback, (tid,)) + self.timers[tid] = timer + timer.start() + return tid + + def cancel_timeout(self, tid): + if self.timers.has_key(tid): + self.timers[tid].cancel() + del self.timers[tid] + + def send_packet(self, pkt): + if self.debug: + if len(pkt) > 64: + s = pkt[0:64] + '...' + else: + s = pkt + sys.stdout.write('-> ' + s.translate(self.tt) + '\n') + self.tty.write(pkt); + + def send_packet_start_timeout(self, pkt, secs): + self.send_packet(pkt) + self.current_tid = self.start_timeout(secs) + + def upload_code(self, sbf): + MAX_PIECE = 512 # biggest piece to send + MWRITE_TIMEOUT = 0.1 + + IDLE = 0 + WAIT_FOR_ACK = 1 + UPLOAD_DONE = 2 + DONE = 3 + FAILED = 4 + + self.done = False + it = sbf.iterator(MAX_PIECE) + entry_addr = sbf.entry + + def get_next_bits(): + try: + (self.addr, self.bits) = it.next() + except StopIteration: + self.done = True + + def is_done(): + return self.done + + def send_piece(): + pkt = build_memory_write_pkt(self.addr, self.bits) + #pkt = build_memory_write_hex_pkt(self.addr, self.bits) + self.send_packet_start_timeout(pkt, MWRITE_TIMEOUT) + state = WAIT_FOR_ACK + + def advance(): + get_next_bits() + if is_done(): + self.state = DONE + self.send_packet(build_goto_pkt(entry_addr)) + + else: + self.ntimeouts = 0 + send_piece() + + get_next_bits() + if is_done(): # empty file + return True + + send_piece() # initial transition + + while 1: + (event, value) = self.q.get() + + if event == 'timeout' and value == self.current_tid: + self.ntimeouts += 1 + if self.ntimeouts >= 5: + return False # say we failed + send_piece() # resend + + + elif event == 'pkt': + if value == 'OK': + self.cancel_timeout(self.current_tid) + advance() + if self.state == DONE: + return True + else: + print("Error returned from firmware: " + value) + return False + + else: + print("Unknown event:", (event, value)) + +def main(): + usage="%prog: [options] filename" + parser = OptionParser(usage=usage) + parser.add_option("-t", "--tty", type="string", default="/dev/ttyS0", + help="select serial port [default=%default]") + + (options, args) = parser.parse_args() + if len(args) != 1: + parser.print_help() + raise SystemExit(1) + + + filename = args[0] + f = open(filename, "rb") + try: + # Try to open the file as an SBF file + sbf_header = sbf.read_sbf(f) + except: + # If that fails, build an SBF from the binary, assuming default + # load address and entry point + f.seek(0) + t = f.read() + if t.startswith('\177ELF'): + sys.stderr.write("Can't load an ELF file. Please use an SBF file instead.\n") + raise SystemExit( 1) + sbf_header = sbf.header(0x8000, [sbf.sec_desc(0x8000, t)]) + + + tty = terminal(options.tty, termios.B115200) + ctrl = controller(tty) + ok = ctrl.upload_code(sbf_header) + + if ok: + print("OK") + try: + raw_input("Press Enter to exit: ") + except KeyboardInterrupt: + pass + ctrl.shutdown() + time.sleep(0.2) + + else: + print("Upload failed") + ctrl.shutdown() + + + +if __name__ == "__main__": + main() diff --git a/firmware/microblaze/bin/uart_ihex_flash_loader.py b/firmware/microblaze/bin/uart_ihex_flash_loader.py new file mode 100755 index 000000000..5a3300f34 --- /dev/null +++ b/firmware/microblaze/bin/uart_ihex_flash_loader.py @@ -0,0 +1,138 @@ +#!/usr/bin/python + +import serial +from optparse import OptionParser +import os, sys + +#TODO: pull everything but parser out of main() and put it in a separate function we can call from another script. lets us automate loading RAM+FLASH to produce a fully-loaded image. +#TODO: make it fail gracefully -- if it gets a NOK or times out, do at least one retry. +#TODO: put hooks in (eventually) to allow verifying a firmware image so the user can more safely update the "safe" image +#TODO: how about a progress indicator? FPGA images take FOREVER. you can use wc -l to get the number of lines, or do it with file i/o. + +def main(): + usage="%prog: [options] filename" + parser = OptionParser(usage=usage) + parser.add_option("-t", "--tty", type="string", default="/dev/ttyUSB0", + help="select serial port [default=%default]") + parser.add_option("-b", "--baudrate", type=int, default=115200, + help="set baudrate [default=%default]") + parser.add_option("-F", "--write-safe-firmware", action="store_const", const=1, dest="image", + help="write to safe firmware image") + parser.add_option("-f", "--write-production-firmware", action="store_const", const=2, dest="image", + help="write to production firmware image") + parser.add_option("-P", "--write-safe-fpga", action="store_const", const=3, dest="image", + help="write to safe FPGA image") + parser.add_option("-p", "--write-production-fpga", action="store_const", const=4, dest="image", + help="write to production FPGA image") + + (options, args) = parser.parse_args() + + if(options.image is None): + print("At least one of -f, -F, -p, -P must be specified.\n") + parser.print_help() + raise SystemExit(1) + + if len(args) != 1: + parser.print_help() + raise SystemExit(1) + + if(options.image == 3): + print "Are you *really* sure you want to write to the failsafe FPGA image? If you mess this up your USRP2+ will become a brick. Press 'y' to continue, any other key to abort." + if(raw_input().rstrip() is not "y"): + print "Good choice." + raise SystemExit(0) + + elif(options.image == 1): + print "Are you *really* sure you want to write to the failsafe firmware image? If you mess this up your USRP2+ will only be able to be reprogrammed via the UART RAM loader.\nPress 'y' to continue, any other key to abort." + if(raw_input().rstrip() is not "y"): + print "Good choice." + raise SystemExit(0) + + filename = args[0] + f = open(filename, "r") + + #now we start doing things... + if(os.path.exists(options.tty) is False): + sys.stderr.write("No serial port found at %s\n" % options.tty) + raise SystemExit(1) + + try: + ser = serial.Serial(port=options.tty, timeout=1, baudrate=options.baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, rtscts=0, xonxoff=0) + except serial.SerialException: + sys.stderr.write("Unable to open serial port\n") + raise SystemExit(1) + + ser.open() + +#test to see if a valid USRP2+ in flash load mode is connected + ser.write("garbage\n") + ser.readline() + ser.write("!SECTORSIZE\n") + reply = ser.readline().rstrip() + if("NOK" in reply): + sys.stderr.write("Error writing to USRP2+. Try again.\n") + raise SystemExit(1) + elif("OK" in reply): + sectorsize = int(reply[3:5], 16) + print("USRP2+ found with sector size %i. Erasing old image." % 2**sectorsize) + else: + sys.stderr.write("Invalid response or no USRP2+ connected.\n") + raise SystemExit(1) + + if(options.image == 1): + sectors = range(127, 128) + runcmd = "!RUNSFD\n" + elif(options.image == 2): + sectors = range(64, 65) + runcmd = "!RUNPFD\n" + elif(options.image == 3): + sectors = range(0,32) + runcmd = "!RUNSFPGA\n" + elif(options.image == 4): + sectors = range(32,64) + runcmd = "!RUNPFPGA\n" + + writeaddr = sectors[0] << sectorsize + if(options.image < 3): + writeaddr -= 0x8000 #i know this is awkward, but we subtract 0x8000 from the address for firmware loads. the reason we do this is that the IHX files are located at 0x8000 (RAM_BASE), and + #doing this here allows us to use the same IHX files for RAM load as for Flash load, without relocating in objcopy or relinking with another ld script. + #this limits us to writing above 32K for our firmware images. since the safe FPGA image located at 0x00000000 takes up 2MB of space this isn't really a worry. + #FPGA images (.mcs) always start at 0x00000000 so they don't need this relocation. + + for sector in sectors: + print "Erasing sector %i" % sector + ser.write("!ERASE %i\n" % sector) + reply = ser.readline() + if("NOK" in reply): + sys.stderr.write("Error erasing sector %i" % sector) + raise SystemExit(1) + + print "Setting start address to %i" % writeaddr + ser.write("!SETADDR %i\n" % writeaddr) + if("NOK" in reply): + sys.stderr.write("Error setting address\n") + raise SystemExit(1) + else: + print reply + + + for line in f: + ser.write(line.rstrip()+'\n') + reply = ser.readline() + if("NOK" in reply): #TODO: simplify this logic, use (reply.rstrip() is "NOK") + print("Received NOK reply during data write") + raise SystemExit(1) + elif("DONE" in reply): + print("Finished writing program. Loading...\n") + ser.write(runcmd) + elif("OK" not in reply): + print("Received invalid reply %s during data write" % reply) + raise SystemExit(1) + else: + print reply.rstrip() + '\t' + line.rstrip() + + print ser.readline() + + +if __name__ == '__main__': + main() diff --git a/firmware/microblaze/bin/uart_ihex_ram_loader.py b/firmware/microblaze/bin/uart_ihex_ram_loader.py new file mode 100755 index 000000000..c90fbe1d8 --- /dev/null +++ b/firmware/microblaze/bin/uart_ihex_ram_loader.py @@ -0,0 +1,70 @@ +#!/usr/bin/python + +import serial +from optparse import OptionParser +import os, sys + +def main(): + usage="%prog: [options] filename" + parser = OptionParser(usage=usage) + parser.add_option("-t", "--tty", type="string", default="/dev/ttyUSB0", + help="select serial port [default=%default]") + parser.add_option("-b", "--baudrate", type=int, default=115200, + help="set baudrate [default=%default]") + + (options, args) = parser.parse_args() + if len(args) != 1: + parser.print_help() + raise SystemExit(1) + + filename = args[0] + f = open(filename, "r") + + #all we have to do is load the IHX file and attempt to spit it out to the serial port. + if(os.path.exists(options.tty) is False): + sys.stderr.write("No serial port found at %s\n" % options.tty) + raise SystemExit(1) + + try: + ser = serial.Serial(port=options.tty, timeout=1, baudrate=options.baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, rtscts=0, xonxoff=0) + except serial.SerialException: + sys.stderr.write("Unable to open serial port\n") + raise SystemExit(1) + + ser.open() + +#test to see if a valid USRP2+ in RAM load mode is connected + + ser.write("WOOOOO\n"); + reply = ser.readline() + if("NOK" not in reply): + sys.stderr.write("Valid USRP2+ not connected or no response received\n") + raise SystemExit(1) + else: + print("USRP2+ found.") + + for line in f: + ser.write(line.rstrip() + '\n') + reply = ser.readline() + if("NOK" in reply): #blocks to wait for response + print("Received NOK reply from USRP2+") + raise SystemExit(1) + elif("OK" not in reply): + print("Received invalid reply!") + raise SystemExit(1) +# else: +# print("OK received") + + print "USRP2+ RAM programmed.\nLoading program." + + #at this point it should have sent the end line of the file, which starts the program! + #we'll just act like a dumb terminal now +# ser.timeout = 0 +# try: +# while 1: +# print ser.readline() +# except KeyboardInterrupt: +# raise SystemExit(0) + +if __name__ == '__main__': + main() diff --git a/firmware/microblaze/bootstrap b/firmware/microblaze/bootstrap index 2343025cc..26987b0ec 100755 --- a/firmware/microblaze/bootstrap +++ b/firmware/microblaze/bootstrap @@ -17,6 +17,8 @@ # rm -rf *.cache +rm -rf libusrp2/.deps +rm -rf libusrp2p/.deps aclocal autoconf diff --git a/firmware/microblaze/configure.ac b/firmware/microblaze/configure.ac index 46968b7fb..f6986f2dd 100644 --- a/firmware/microblaze/configure.ac +++ b/firmware/microblaze/configure.ac @@ -32,6 +32,7 @@ m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.64], [m4_define([_AC_LANG_IO_PROGRAM(]_GCC_LANG[)], m4_defn([AC_LANG_PROGRAM(]_GCC_LANG[)]))])]) AC_PROG_CC([mb-gcc]) +AM_PROG_CC_C_O LT_INIT ################################################## @@ -46,9 +47,8 @@ AC_PATH_PROG([HEXDUMP], [hexdump]) ################################################## AC_CONFIG_FILES([ \ Makefile \ - apps/Makefile \ - include/Makefile \ - include/net/Makefile \ - lib/Makefile \ + usrp2p/bootloader/Makefile \ + usrp2/Makefile \ + usrp2p/Makefile \ ]) AC_OUTPUT diff --git a/firmware/microblaze/include/.gitignore b/firmware/microblaze/include/.gitignore deleted file mode 100644 index b336cc7ce..000000000 --- a/firmware/microblaze/include/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Makefile -/Makefile.in diff --git a/firmware/microblaze/include/usrp2_fpga_regs.h b/firmware/microblaze/include/usrp2_fpga_regs.h deleted file mode 100644 index b0f83df60..000000000 --- a/firmware/microblaze/include/usrp2_fpga_regs.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef INCLUDED_USRP2_FPGA_REGS_H -#define INCLUDED_USSRP2_FPGA_REGS_H - -#include "usrp2_cdefs.h" - -__U2_BEGIN_DECLS - -// ---------------------------------------------------------------- - -#define DSP_CORE_TX_BASE 128 - -// DUC center frequency tuning word (phase increment) -#define FR_TX_FREQ_0 (0 + DSP_CORE_TX_BASE) - -// I & Q output scaling, 16.0 format ((I_SCALE << 16) | Q_SCALE) -#define FR_TX_SCALE_0 (1 + DSP_CORE_TX_BASE) - -// Tx interpolation rate (set to 1 less than desired rate) -#define FR_TX_INTERP_RATE_0 (2 + DSP_CORE_TX_BASE) - -// Write 1 (actually anything) to clear tx state -#define FR_TX_CLEAR_STATE_0 (3 + DSP_CORE_TX_BASE) - -// ---------------------------------------------------------------- - -#define DSP_CORE_RX_BASE 160 - -// DDC center frequency tuning word (phase increment) -#define FR_RX_FREQ_0 (0 + DSP_CORE_RX_BASE) - -// I & Q input scaling, 16.0 format ((I_SCALE << 16) | Q_SCALE) -#define FR_RX_SCALE_0 (1 + DSP_CORE_RX_BASE) - -// Rx decimation rate (set to 1 less than desired rate) -#define FR_RX_DECIM_RATE_0 (2 + DSP_CORE_RX_BASE) - -// The next two registers concatenated are the Rx command register. -// -// Writing FR_RX_TIME_TO_RX_0 writes the concatenated value into the -// cmd queue. Thus, if you're writing both, be sure to write -// FR_RX_QTY_0 first. -// -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Timestamp | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -#define FR_RX_TIME_TO_RX (3 + DSP_CORE_RX_BASE) - -// 23-bits 9-bits -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | number_of_lines | lines_per_frame | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -#define FR_RX_QTY_0 (4 + DSP_CORE_RX_BASE) - -// write a 1 (anything actually) to clear the overrun -#define FR_RX_CLR_OVERRUN_0 (5 + DSP_CORE_RX_BASE) - - -__U2_END_DECLS - -#endif /* INCLUDED_USRP2_FPGA_REGS_H */ diff --git a/firmware/microblaze/include/usrp2_i2c_addr.h b/firmware/microblaze/include/usrp2_i2c_addr.h deleted file mode 100644 index 46f5a7556..000000000 --- a/firmware/microblaze/include/usrp2_i2c_addr.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2007 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef INCLUDED_USRP2_I2C_ADDR_H -#define INCLUDED_USRP2_I2C_ADDR_H - -// I2C addresses - -#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx - -#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) -#define I2C_ADDR_TX_A (I2C_DEV_EEPROM | 0x4) -#define I2C_ADDR_RX_A (I2C_DEV_EEPROM | 0x5) - - -// format of USRP2 motherboard rom -// 00: 0x00 h/w rev (LSB) -// 01: 0x00 h/w rev (MSB) -// 02: 0x00 MAC addr 0 -// 03: 0x50 MAC addr 1 -// 04: 0xC2 MAC addr 2 -// 05: 0x85 MAC addr 3 -// 06: 0x3. MAC addr 4 -// 07: 0x.. MAC addr 5 - -#define MBOARD_REV_LSB 0x00 -#define MBOARD_REV_MSB 0x01 -#define MBOARD_MAC_ADDR 0x02 -#define MBOARD_IP_ADDR 0x0C - - -// format of daughterboard EEPROM -// 00: 0xDB code for ``I'm a daughterboard'' -// 01: .. Daughterboard ID (LSB) -// 02: .. Daughterboard ID (MSB) -// 03: .. io bits 7-0 direction (bit set if it's an output from m'board) -// 04: .. io bits 15-8 direction (bit set if it's an output from m'board) -// 05: .. ADC0 DC offset correction (LSB) -// 06: .. ADC0 DC offset correction (MSB) -// 07: .. ADC1 DC offset correction (LSB) -// 08: .. ADC1 DC offset correction (MSB) -// ... -// 1f: .. negative of the sum of bytes [0x00, 0x1e] - -#define DB_EEPROM_MAGIC 0x00 -#define DB_EEPROM_MAGIC_VALUE 0xDB -#define DB_EEPROM_ID_LSB 0x01 -#define DB_EEPROM_ID_MSB 0x02 -#define DB_EEPROM_OE_LSB 0x03 -#define DB_EEPROM_OE_MSB 0x04 -#define DB_EEPROM_OFFSET_0_LSB 0x05 // offset correction for ADC or DAC 0 -#define DB_EEPROM_OFFSET_0_MSB 0x06 -#define DB_EEPROM_OFFSET_1_LSB 0x07 // offset correction for ADC or DAC 1 -#define DB_EEPROM_OFFSET_1_MSB 0x08 -#define DB_EEPROM_CHKSUM 0x1f - -#define DB_EEPROM_CLEN 0x20 // length of common portion of eeprom - -#define DB_EEPROM_CUSTOM_BASE DB_EEPROM_CLEN // first avail offset for - // daughterboard specific use - -#endif /* INCLUDED_USRP2_I2C_ADDR_H */ - diff --git a/firmware/microblaze/include/usrp2_types.h b/firmware/microblaze/include/usrp2_types.h deleted file mode 100644 index fe45936f0..000000000 --- a/firmware/microblaze/include/usrp2_types.h +++ /dev/null @@ -1,105 +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/>. - */ -#ifndef INCLUDED_USRP2_TYPES_H -#define INCLUDED_USRP2_TYPES_H - -#include <stdint.h> - -/*! - * \brief Fixed point representation of a frequency in Hertz (VITA-49 compatible) - * - * 64-bit two's complement, with the radix point 20 bits up from the bottom. - * Q44.20 format (20 bits to the right of the radix point) - * - * Values range from +/- 8.79 terahertz with a resolution of 0.95 microhertz. - */ -typedef int64_t u2_fxpt_freq_t; - -#define U2_FPF_RP 20 // location of radix point in u2_fxpt_freq_t - -// macro so we can init structs at compile time -#define U2_DOUBLE_TO_FXPT_FREQ(f) (int64_t)((f) * (1LL << U2_FPF_RP)) - -static inline u2_fxpt_freq_t -u2_double_to_fxpt_freq(double f) -{ - return U2_DOUBLE_TO_FXPT_FREQ(f); -} - -static inline int -u2_fxpt_freq_round_to_int(u2_fxpt_freq_t fx) -{ - return (int)((fx+(1<<(U2_FPF_RP-1)))>>U2_FPF_RP); -} - -static inline double -u2_fxpt_freq_to_double(u2_fxpt_freq_t fx) -{ - return ((double) fx) * 1.0/(1 << U2_FPF_RP); -} - -static inline uint32_t -u2_fxpt_freq_hi(u2_fxpt_freq_t f) -{ - return ((f >> 32) & 0xffffffff); -} - -static inline uint32_t -u2_fxpt_freq_lo(u2_fxpt_freq_t f) -{ - return (f & 0xffffffff); -} - -static inline u2_fxpt_freq_t -u2_fxpt_freq_from_hilo(uint32_t hi, uint32_t lo) -{ - return (((u2_fxpt_freq_t) hi) << 32) | lo; -} - -/*! - * \brief Fixed point representation of a gain in dB (VITA-49 compatible) - * - * 16-bit two's complement, with the radix point 7 bits up from the bottom. - * Q9.7 format (7 bits to the right of the radix point) - */ -typedef int16_t u2_fxpt_gain_t; - -#define U2_FPG_RP 7 // location of radix point in u2_fxpt_gain_t - -// macro so we can init structs at compile time -#define U2_DOUBLE_TO_FXPT_GAIN(g) (int16_t)((g) * (1 << U2_FPG_RP)) - -static inline u2_fxpt_gain_t -u2_double_to_fxpt_gain(double g) -{ - return U2_DOUBLE_TO_FXPT_GAIN(g); -} - -static inline float -u2_fxpt_gain_to_double(u2_fxpt_gain_t fx) -{ - return ((double) fx) * 1.0/(1 << U2_FPG_RP); -} - -static inline int -u2_fxpt_gain_round_to_int(u2_fxpt_gain_t fx) -{ - return (int)((fx+(1<<(U2_FPG_RP-1)))>>U2_FPG_RP); -} - -#endif /* INCLUDED_USRP2_TYPES_H */ diff --git a/firmware/microblaze/include/vrt/bits.h b/firmware/microblaze/include/vrt/bits.h deleted file mode 100644 index 54eeec7b4..000000000 --- a/firmware/microblaze/include/vrt/bits.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef INCLUDED_VRT_BITS_H -#define INCLUDED_VRT_BITS_H - -#include <stdint.h> - - -/* VRT Header bits */ - -#define VRTH_PT_MASK (0xf << 28) -#define VRTH_PT_IF_DATA_NO_SID (0x0 << 28) // IF-Data, no stream id -#define VRTH_PT_IF_DATA_WITH_SID (0x1 << 28) // IF-Data, w/ stream id -#define VRTH_PT_EXT_DATA_NO_SID (0x2 << 28) -#define VRTH_PT_EXT_DATA_WITH_SID (0x3 << 28) -#define VRTH_PT_IF_CONTEXT (0x4 << 28) -#define VRTH_PT_EXT_CONTEXT (0x5 << 28) - -#define VRTH_HAS_CLASSID (1 << 27) -#define VRTH_HAS_TRAILER (1 << 26) // Data pkts only -#define VRTH_START_OF_BURST (1 << 25) // Data (Tx) pkts only -#define VRTH_END_OF_BURST (1 << 24) // Data (Tx) pkts only -#define VRTH_TSM (1 << 24) // Context pkts only - -#define VRTH_TSI_MASK (0x3 << 22) -#define VRTH_TSI_NONE (0x0 << 22) -#define VRTH_TSI_UTC (0x1 << 22) -#define VRTH_TSI_GPS (0x2 << 22) -#define VRTH_TSI_OTHER (0x3 << 22) - -#define VRTH_TSF_MASK (0x3 << 20) -#define VRTH_TSF_NONE (0x0 << 20) -#define VRTH_TSF_SAMPLE_CNT (0x1 << 20) -#define VRTH_TSF_REAL_TIME_PS (0x2 << 20) -#define VRTH_TSF_FREE_RUNNING (0x3 << 20) - -#define VRTH_PKT_CNT_SHIFT 16 -#define VRTH_PKT_CNT_MASK (0xf << 16) - -#define VRTH_PKT_SIZE_MASK 0xffff - - -static inline int -vrth_pkt_cnt(uint32_t h) -{ - return (h & VRTH_PKT_CNT_MASK) >> 16; -} - -static inline int -vrth_pkt_size(uint32_t h) -{ - return h & VRTH_PKT_SIZE_MASK; -} - -/* - * Trailer bits - */ -#define TR_E (1 << 8) - -#define TR_ENABLE(x) ((x) << 20) -#define TR_STATE(x) ((x) << 8) - -// Use these with TR_ENABLE and TR_STATE -#define TR_CAL_TIME (1 << 11) -#define TR_VALID_DATA (1 << 10) -#define TR_REF_LOCK (1 << 9) -#define TR_AGC (1 << 8) -#define TR_DETECTED_SIG (1 << 7) -#define TR_SPECTRAL_INVERSION (1 << 6) -#define TR_OVER_RANGE (1 << 5) -#define TR_SAMPLE_LOSS (1 << 4) -#define TR_USER_3 (1 << 3) -#define TR_USER_2 (1 << 2) -#define TR_USER_1 (1 << 1) -#define TR_USER_0 (1 << 0) - -#endif /* INCLUDED_VRT_BITS_H */ diff --git a/firmware/microblaze/include/vrt/types.h b/firmware/microblaze/include/vrt/types.h deleted file mode 100644 index edfa4ec37..000000000 --- a/firmware/microblaze/include/vrt/types.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009 Free Software Foundation, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef INCLUDED_VRT_TYPES_H -#define INCLUDED_VRT_TYPES_H - -#include <stdint.h> - -/* macros for dealing with fixed point numbers */ -#define _FXPT_C(_type, _x, _rp) ((_type)((_x)*(1ll << _rp))) -#define _FXPT_TO_INT(_x, _one) (((_x) + ((_one)/2))/(_one)) -#define _FXPT_TO_DOUBLE(_x, _one) ((double)(_x) * (1.0/(_one))) - -/*********************************************************************** - * The VRT Altitude Type (meters) - **********************************************************************/ -typedef int32_t vrt_altitude_t; -#define VRT_ALTITUDE_RP 5 -#define VRT_ALTITUDE_C(_x) _FXPT_C(vrt_altitude_t, _x, VRT_ALTITUDE_RP) - -static inline vrt_altitude_t -double_to_vrt_altitude(double num){ - return VRT_ALTITUDE_C(num); -} - -static inline int32_t -vrt_altitude_round_to_int(vrt_altitude_t fx){ - return _FXPT_TO_INT(fx, VRT_ALTITUDE_C(1)); -} - -static inline double -vrt_altitude_to_double(vrt_altitude_t fx){ - return _FXPT_TO_DOUBLE(fx, VRT_ALTITUDE_C(1)); -} - -/*********************************************************************** - * The VRT Geolocation Angle Type (degrees) - **********************************************************************/ -typedef int32_t vrt_geo_angle_t; -#define VRT_GEO_ANGLE_RP 22 -#define VRT_GEO_ANGLE_C(_x) _FXPT_C(vrt_geo_angle_t, _x, VRT_GEO_ANGLE_RP) - -static inline vrt_geo_angle_t -double_to_vrt_geo_angle(double num){ - return VRT_GEO_ANGLE_C(num); -} - -static inline int16_t -vrt_geo_angle_round_to_int(vrt_geo_angle_t fx){ - return _FXPT_TO_INT(fx, VRT_GEO_ANGLE_C(1)); -} - -static inline double -vrt_geo_angle_to_double(vrt_geo_angle_t fx){ - return _FXPT_TO_DOUBLE(fx, VRT_GEO_ANGLE_C(1)); -} - -/*********************************************************************** - * The VRT Frequency Type (Hz) - **********************************************************************/ -typedef int64_t vrt_freq_t; -#define VRT_FREQ_RP 20 -#define VRT_FREQ_C(_x) _FXPT_C(vrt_freq_t, _x, VRT_FREQ_RP) - -static inline vrt_freq_t -double_to_vrt_freq(double num){ - return VRT_FREQ_C(num); -} - -static inline int64_t -vrt_freq_round_to_int(vrt_freq_t fx){ - return _FXPT_TO_INT(fx, VRT_FREQ_C(1)); -} - -static inline double -vrt_freq_to_double(vrt_freq_t fx){ - return _FXPT_TO_DOUBLE(fx, VRT_FREQ_C(1)); -} - -/*********************************************************************** - * The VRT Gain Type (dB) - **********************************************************************/ -typedef int16_t vrt_gain_t; -#define VRT_GAIN_RP 7 -#define VRT_GAIN_C(_x) _FXPT_C(vrt_gain_t, _x, VRT_GAIN_RP) - -static inline vrt_gain_t -double_to_vrt_gain(double num){ - return VRT_GAIN_C(num); -} - -static inline int16_t -vrt_gain_round_to_int(vrt_gain_t fx){ - return _FXPT_TO_INT(fx, VRT_GAIN_C(1)); -} - -static inline double -vrt_gain_to_double(vrt_gain_t fx){ - return _FXPT_TO_DOUBLE(fx, VRT_GAIN_C(1)); -} - -/*********************************************************************** - * The VRT Temperature Type (Celcius) - **********************************************************************/ -typedef int16_t vrt_temp_t; -#define VRT_TEMP_RP 6 -#define VRT_TEMP_C(_x) _FXPT_C(vrt_temp_t, _x, VRT_TEMP_RP) - -static inline vrt_temp_t -double_to_vrt_temp(double num){ - return VRT_TEMP_C(num); -} - -static inline int16_t -vrt_temp_round_to_int(vrt_temp_t fx){ - return _FXPT_TO_INT(fx, VRT_TEMP_C(1)); -} - -static inline double -vrt_temp_to_double(vrt_temp_t fx){ - return _FXPT_TO_DOUBLE(fx, VRT_TEMP_C(1)); -} - -#endif /* INCLUDED_VRT_TYPES_H */ 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/include/usrp2_clock_bits.h b/firmware/microblaze/lib/clock_bits.h index d2052e941..d2052e941 100644 --- a/firmware/microblaze/include/usrp2_clock_bits.h +++ b/firmware/microblaze/lib/clock_bits.h diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h index 43d5a05c2..a285e03dd 100644 --- a/firmware/microblaze/lib/clocks.h +++ b/firmware/microblaze/lib/clocks.h @@ -26,7 +26,7 @@ */ #include <stdbool.h> -#include <usrp2_clock_bits.h> +#include "clock_bits.h" /*! diff --git a/firmware/microblaze/include/compiler.h b/firmware/microblaze/lib/compiler.h index 4fa9b49f8..4fa9b49f8 100644 --- a/firmware/microblaze/include/compiler.h +++ b/firmware/microblaze/lib/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/include/net/.gitignore b/firmware/microblaze/lib/net/.gitignore index 282522db0..282522db0 100644 --- a/firmware/microblaze/include/net/.gitignore +++ b/firmware/microblaze/lib/net/.gitignore diff --git a/firmware/microblaze/include/net/eth_mac_addr.h b/firmware/microblaze/lib/net/eth_mac_addr.h index b44fb68f7..b44fb68f7 100644 --- a/firmware/microblaze/include/net/eth_mac_addr.h +++ b/firmware/microblaze/lib/net/eth_mac_addr.h diff --git a/firmware/microblaze/include/net/padded_eth_hdr.h b/firmware/microblaze/lib/net/padded_eth_hdr.h index df816734f..df816734f 100644 --- a/firmware/microblaze/include/net/padded_eth_hdr.h +++ b/firmware/microblaze/lib/net/padded_eth_hdr.h diff --git a/firmware/microblaze/include/net/socket_address.h b/firmware/microblaze/lib/net/socket_address.h index 336f30a0c..336f30a0c 100644 --- a/firmware/microblaze/include/net/socket_address.h +++ b/firmware/microblaze/lib/net/socket_address.h diff --git a/firmware/microblaze/lib/nonstdio.c b/firmware/microblaze/lib/nonstdio.c index 1c991afee..4b5fa4123 100644 --- a/firmware/microblaze/lib/nonstdio.c +++ b/firmware/microblaze/lib/nonstdio.c @@ -78,3 +78,46 @@ puthex32_nl(unsigned long x) puthex32(x); newline(); } +/* +void reverse(char s[]) +{ + int c, i, j; + + for (i = 0, j = strlen(s)-1; i<j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} + +int abs(signed long value) { + return (value >= 0) ? value : 0-value; +} + +//we'll keep the puthex functions above because they're way more lightweight. but sometimes you just want to print in decimal, you know? +char *itoa(signed long value, char *result, int base) +{ + // check that the base if valid + if (base < 2 || base > 16) { *result = 0; return result; } + + char* out = result; + signed long quotient = value; + + do { + *out = hex[ abs(quotient % base) ]; + ++out; + quotient /= base; + } while ( quotient ); + + // Only apply negative sign for base 10 + if ( value < 0 && base == 10) *out++ = '-'; + + *out = 0; + reverse( result ); + + return result; + +} +*/ + + diff --git a/firmware/microblaze/lib/nonstdio.h b/firmware/microblaze/lib/nonstdio.h index 3fd9e39bb..62ebfa46d 100644 --- a/firmware/microblaze/lib/nonstdio.h +++ b/firmware/microblaze/lib/nonstdio.h @@ -1,4 +1,6 @@ -/* -*- c -*- */ +// +// Copyright 2010 Ettus Research LLC +// /* * Copyright 2007 Free Software Foundation, Inc. * @@ -20,7 +22,7 @@ #define INCLUDED_NONSTDIO_H #include <stdio.h> -#include <usrp2_types.h> +#include <stdint.h> #include <stddef.h> void putstr(const char *s); // cf puts, no added newline @@ -37,10 +39,10 @@ void puthex32_nl(unsigned long x); void newline(); // putchar('\n') void print_mac_addr(const unsigned char addr[6]); -void print_fxpt_freq(u2_fxpt_freq_t v); -void print_fxpt_gain(u2_fxpt_gain_t v); void print_uint64(uint64_t v); void print_buffer(uint32_t *buf, size_t n); +//char *itoa(signed long value, char *result, int base); +//void reverse(char s[]); #endif /* INCLUDED_NONSTDIO_H */ diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h index f5b69b270..01e4d26fd 100644 --- a/firmware/microblaze/lib/spi.h +++ b/firmware/microblaze/lib/spi.h @@ -48,5 +48,23 @@ void spi_wait(void); uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); +// ---------------------------------------------------------------- +// Routines that manipulate the FLASH SPI BUS +// ---------------------------------------------------------------- + +/*! + * \brief One time call to initialize SPI + */ +void spif_init(void); + +/*! + * \brief Wait for last SPI transaction to complete. + * Unless you need to know it completed, it's not necessary to call this. + */ +void spif_wait(void); + +uint32_t +spif_transact(bool readback_, int slave, uint32_t data, int length, uint32_t flags); + #endif /* INCLUDED_SPI_H */ diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index 6809101c0..ff558d673 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -25,9 +25,7 @@ #include "i2c.h" #include "mdelay.h" #include "clocks.h" -#include "usrp2_i2c_addr.h" - -//#include "nonstdio.h" +#include "usrp2/fw_common.h" unsigned char u2_hw_rev_major; unsigned char u2_hw_rev_minor; @@ -35,8 +33,8 @@ unsigned char u2_hw_rev_minor; static inline void get_hw_rev(void) { - bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &u2_hw_rev_minor, 1); - ok &= eeprom_read(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &u2_hw_rev_major, 1); + bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, &u2_hw_rev_minor, 1); + ok &= eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, &u2_hw_rev_major, 1); } /* diff --git a/firmware/microblaze/lib/udp_burner_packet.c b/firmware/microblaze/lib/udp_burner_packet.c new file mode 100644 index 000000000..d86a4cf4a --- /dev/null +++ b/firmware/microblaze/lib/udp_burner_packet.c @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "udp_burner_packet.h" +#include "net_common.h" +#include "loader_parser.h" +#include <stdint.h> +#include <compiler.h> +#include <nonstdio.h> + + +void +handle_udp_burner_packet(struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len) +{ + unsigned char reply[128] _AL4; + size_t actual_reply_len; + loader_parser(payload, payload_len, reply, sizeof(reply), &actual_reply_len); + send_udp_pkt(dst.port, src, reply, actual_reply_len); +} diff --git a/firmware/microblaze/lib/udp_burner_packet.h b/firmware/microblaze/lib/udp_burner_packet.h new file mode 100644 index 000000000..0f4025712 --- /dev/null +++ b/firmware/microblaze/lib/udp_burner_packet.h @@ -0,0 +1,28 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_UDP_BURNER_PACKET_H +#define INCLUDED_UDP_BURNER_PACKET_H + +#include <net/socket_address.h> + +void +handle_udp_burner_packet(struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len); + + +#endif /* INCLUDED_UDP_BURNER_PACKET_H */ diff --git a/firmware/microblaze/lib/xilinx_s3_icap.c b/firmware/microblaze/lib/xilinx_s3_icap.c new file mode 100644 index 000000000..8aa7fd297 --- /dev/null +++ b/firmware/microblaze/lib/xilinx_s3_icap.c @@ -0,0 +1,101 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +/* Changes required to work for the Spartan-3A series: + * The ICAP interface on the 3A is 8 bits wide, instead of 32. + * Everything is Xilinx standard LSB-first. + * The operations are all different. + * Commands are 16 bits long, presented to the ICAP interface 8 bits at a time. +*/ + +#include <xilinx_s3_icap.h> +#include <memory_map.h> +#include <spi_flash_private.h> //for READ_CMD + + +/* bit swap end-for-end */ +static unsigned char +swap8(unsigned char x) +{ + unsigned char r = 0; + r |= (x >> 7) & 0x01; + r |= (x >> 5) & 0x02; + r |= (x >> 3) & 0x04; + r |= (x >> 1) & 0x08; + + r |= (x << 1) & 0x10; + r |= (x << 3) & 0x20; + r |= (x << 5) & 0x40; + r |= (x << 7) & 0x80; + + return r; +} + +void +wr_icap(uint8_t x) +{ + uint8_t t = swap8(x); + + icap_regs->icap = t; //DEBUG: does not swap bits +} + +uint8_t +rd_icap(void) +{ + return swap8(icap_regs->icap); +} + + +void +icap_reload_fpga(uint32_t flash_address) +//this DOES NOT WORK right now. reboot is not getting executed correctly. +{ + union { + uint32_t i; + uint8_t c[4]; + } t; + t.i = flash_address; + + //note! t.c[0] MUST contain the byte-wide read command for the flash device used. + //for the 25P64, and most other flash devices, this is 0x03. + t.c[0] = READ_CMD; //legacy command, use FAST_READ_CMD 0x0B after testing + + //TODO: look up the watchdog timer, ensure it won't fire too soon + + //UG332 p279 +// wr_icap(0xff); +// wr_icap(0xff); //dummy word, probably unnecessary + wr_icap(0xAA); + wr_icap(0x99); //sync word + wr_icap(0x32); + wr_icap(0x61); //Type 1 write General 1 (1 word) + wr_icap(t.c[2]); //bits 15-8 + wr_icap(t.c[3]); //bits 7-0 + wr_icap(0x32); + wr_icap(0x81); //Type 1 write General 2 (1 word) + wr_icap(t.c[0]); //C0-C8, the byte-wide read command + wr_icap(t.c[1]); //Upper 8 bits of 24-bit address + wr_icap(0x30); + wr_icap(0xA1); //Type 1 write CMD (1 word) + wr_icap(0x00); + wr_icap(0x0E); //REBOOT command + wr_icap(0x20); + wr_icap(0x00); //Type 1 NOP + +} diff --git a/firmware/microblaze/apps/.gitignore b/firmware/microblaze/usrp2/.gitignore index 968b04cd7..18f715618 100644 --- a/firmware/microblaze/apps/.gitignore +++ b/firmware/microblaze/usrp2/.gitignore @@ -1,8 +1,9 @@ -/*.elf +/Makefile +/Makefile.in +/*.a /*.bin /*.dump -/*.log +/*.ihx +/*.elf /*.rom /*.map -/Makefile -/Makefile.in diff --git a/firmware/microblaze/include/Makefile.am b/firmware/microblaze/usrp2/Makefile.am index 6afbbcd12..859ded9e5 100644 --- a/firmware/microblaze/include/Makefile.am +++ b/firmware/microblaze/usrp2/Makefile.am @@ -1,8 +1,6 @@ # # Copyright 2010 Ettus Research LLC # -# Copyright 2008 Free Software Foundation, Inc. -# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or @@ -19,12 +17,27 @@ include $(top_srcdir)/Makefile.common -SUBDIRS = net +AM_CFLAGS = \ + $(COMMON_CFLAGS) + +AM_LDFLAGS = \ + $(COMMON_LFLAGS) \ + libusrp2.a \ + -Wl,-defsym -Wl,_TEXT_START_ADDR=0x0050 \ + -Wl,-defsym -Wl,_STACK_SIZE=3072 + +######################################################################## +# USRP2 specific library and programs +######################################################################## +noinst_LIBRARIES = libusrp2.a + +libusrp2_a_SOURCES = \ + $(COMMON_SRCS) \ + clocks.c \ + sd.c + +noinst_PROGRAMS = \ + usrp2_txrx_uhd.elf -noinst_HEADERS = \ - usrp2_fpga_regs.h \ - usrp2_i2c_addr.h \ - usrp2_clock_bits.h \ - usrp2_types.h \ - vrt/bits.h \ - vrt/types.h +usrp2_txrx_uhd_elf_SOURCES = \ + $(top_srcdir)/apps/txrx_uhd.c diff --git a/firmware/microblaze/lib/clocks.c b/firmware/microblaze/usrp2/clocks.c index ccc4a7cc7..ccc4a7cc7 100644 --- a/firmware/microblaze/lib/clocks.c +++ b/firmware/microblaze/usrp2/clocks.c diff --git a/firmware/microblaze/lib/memory_map.h b/firmware/microblaze/usrp2/memory_map.h index cdf3dd338..4c9ead615 100644 --- a/firmware/microblaze/lib/memory_map.h +++ b/firmware/microblaze/usrp2/memory_map.h @@ -89,6 +89,7 @@ typedef struct { #define SPI_SS_TX_DAC 32 #define SPI_SS_TX_ADC 64 #define SPI_SS_TX_DB 128 +#define SPI_SS_ADS64P44 256 // Masks for different parts of CTRL reg #define SPI_CTRL_ASS (1<<13) diff --git a/firmware/microblaze/lib/sd.c b/firmware/microblaze/usrp2/sd.c index d000b28ae..d000b28ae 100644 --- a/firmware/microblaze/lib/sd.c +++ b/firmware/microblaze/usrp2/sd.c diff --git a/firmware/microblaze/lib/sd.h b/firmware/microblaze/usrp2/sd.h index e2d0ae38e..e2d0ae38e 100644 --- a/firmware/microblaze/lib/sd.h +++ b/firmware/microblaze/usrp2/sd.h diff --git a/firmware/microblaze/usrp2p/.gitignore b/firmware/microblaze/usrp2p/.gitignore new file mode 100644 index 000000000..18f715618 --- /dev/null +++ b/firmware/microblaze/usrp2p/.gitignore @@ -0,0 +1,9 @@ +/Makefile +/Makefile.in +/*.a +/*.bin +/*.dump +/*.ihx +/*.elf +/*.rom +/*.map diff --git a/firmware/microblaze/usrp2p/Makefile.am b/firmware/microblaze/usrp2p/Makefile.am new file mode 100644 index 000000000..eff544294 --- /dev/null +++ b/firmware/microblaze/usrp2p/Makefile.am @@ -0,0 +1,66 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +AM_CFLAGS = \ + $(COMMON_CFLAGS) + +AM_LDFLAGS = \ + $(COMMON_LFLAGS) \ + libusrp2p.a \ + -Wl,-defsym -Wl,_TEXT_START_ADDR=0x8050 \ + -Wl,-defsym -Wl,_STACK_SIZE=3072 + +#all of this here is to relocate the hardware vectors to somewhere normal. +COMMON_IHX_ARGS = \ + --change-section-address .vectors.sw_exception+0x8000 \ + --change-section-address .vectors.hw_exception+0x8000 \ + --change-section-address .vectors.interrupt+0x8000 \ + --change-section-address .vectors.reset+0x8000 +# $(MB_OBJCOPY) -O ihex $< $@ +# the below would work if objcopy weren't written by apes +# $(MB_OBJCOPY) -O ihex -w --change-section-address .vectors*+0x8000 $< $@ +# using the below will throw away the interrupt vectors when they get relocated below 0x0000. +# $(MB_OBJCOPY) -O ihex --change-addresses -0x8000 $< $@ + +######################################################################## +# USRP2P specific library and programs +######################################################################## +noinst_LIBRARIES = libusrp2p.a + +libusrp2p_a_SOURCES = \ + $(COMMON_SRCS) \ + clocks.c \ + spif.c \ + spi_flash.c \ + spi_flash_read.c \ + bootloader_utils.c + +noinst_PROGRAMS = \ + usrp2p_txrx_uhd.elf \ + usrp2p_blinkenlights.elf \ + usrp2p_uart_flash_loader.elf + +usrp2p_txrx_uhd_elf_SOURCES = \ + $(top_srcdir)/apps/txrx_uhd.c + +usrp2p_blinkenlights_elf_SOURCES = \ + $(top_srcdir)/apps/blinkenlights.c + +usrp2p_uart_flash_loader_elf_SOURCES = \ + $(top_srcdir)/apps/uart_flash_loader.c diff --git a/firmware/microblaze/usrp2p/bootconfig.h b/firmware/microblaze/usrp2p/bootconfig.h new file mode 100644 index 000000000..35c2726ed --- /dev/null +++ b/firmware/microblaze/usrp2p/bootconfig.h @@ -0,0 +1,61 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * 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_BOOTCONFIG_H +#define INCLUDED_BOOTCONFIG_H + +#include <stdbool.h> + +typedef struct { + unsigned char fpga_image_number; + unsigned char firmware_image_number; +} bootconfig_t; + +static inline bootconfig_t +make_bootconfig(unsigned char fpga_image_number, unsigned char firmware_image_number) +{ + bootconfig_t r; + r.fpga_image_number = fpga_image_number; + r.firmware_image_number = firmware_image_number; + return r; +} + +void bootconfig_init(void); /* One time call to initialize */ + +/*! + * \return default boot configuration + */ +bootconfig_t bootconfig_get_default(void); + +/*! + * \brief Set the default boot configuration. + */ +bool bootconfig_set_default(bootconfig_t bc); + +/*! + * \brief attempt to boot the given fpga and software image. + * + * If successful, this routine does not return. + * If it fail for some reason, it returns. + */ +void bootconfig_boot(bootconfig_t bc); + +#endif /* INCLUDED_BOOTCONFIG_H */ diff --git a/firmware/microblaze/usrp2p/bootloader/.gitignore b/firmware/microblaze/usrp2p/bootloader/.gitignore new file mode 100644 index 000000000..17b0f82f3 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/.gitignore @@ -0,0 +1,11 @@ +/*.ihx +/*.rmi +/*_rom +/*.elf +/*.bin +/*.dump +/*.log +/*.rom +/*.map +/Makefile +/Makefile.in diff --git a/firmware/microblaze/include/net/Makefile.am b/firmware/microblaze/usrp2p/bootloader/Makefile.am index 32b0bf9dc..1fc5daf9c 100644 --- a/firmware/microblaze/include/net/Makefile.am +++ b/firmware/microblaze/usrp2p/bootloader/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2010 Ettus Research LLC +# Copyright 2007,2008,2009 Free Software Foundation, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,7 +17,23 @@ include $(top_srcdir)/Makefile.common -noinst_HEADERS = \ - eth_mac_addr.h \ - padded_eth_hdr.h \ - socket_address.h +ROM_LINKER_SCRIPT = u2p2-rom.ld + +# loads into 8K boot ram located at 0x0000_0000 +AM_CFLAGS = $(COMMON_CFLAGS) -I$(top_srcdir)/usrp2p +AM_LDFLAGS = -Wl,-T,$(ROM_LINKER_SCRIPT) $(COMMON_LFLAGS) -Wl,-defsym -Wl,_STACK_SIZE=1024 + +EXTRA_DIST = $(ROM_LINKER_SCRIPT) + +LDADD = $(top_srcdir)/usrp2p/libusrp2p.a + +noinst_PROGRAMS = \ + init_bootloader.elf + +init_bootloader_elf_SOURCES = init_bootloader.c + +.bin.rmi: + $(top_srcdir)/bin/bin_to_ram_macro_init.py $< $@ + +_generated_from_elf += \ + $(noinst_PROGRAMS:.elf=.rmi) diff --git a/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c b/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c new file mode 100644 index 000000000..9feff6ecd --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c @@ -0,0 +1,202 @@ +/* -*- 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/>. + */ + +/* + * This code is bootloader f/w for the slot 0 fpga image. It's job is + * to figure out which fpga image should be loaded, and then to load + * that image from the SPI flash. (FIXME handle retries, errors, + * etc.) + * + * If the center button is down during boot, it loads firwmare + * from 0:0 instead of its normal action. + */ + +#include <stdlib.h> +#include <hal_io.h> +#include <nonstdio.h> +#include <mdelay.h> +#include <quadradio/flashdir.h> +#include <xilinx_v5_icap.h> +#include <bootconfig.h> +#include <bootconfig_private.h> +#include <spi_flash.h> +#include <string.h> +#include <bootloader_utils.h> +#include <hal_interrupts.h> + +#define VERBOSE 1 + +#define OUR_FPGA_IMAGE_NUMBER 0 // this code only runs in slot 0 + +void hal_uart_init(void); +void spif_init(void); +void i2c_init(void); +void bootconfig_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +static int +flash_addr_of_fpga_slot(unsigned int fpga_slot) +{ + const struct flashdir *fd = get_flashdir(); + return fd->slot[fpga_slot + fd->fpga_slot0].start << spi_flash_log2_sector_size(); +} + + +/* + * If the first 256 bytes of the image contain the string of bytes, + * ff ff ff ff aa 99 55 66, we consider it a likely bitstream. + */ +static bool +looks_like_a_bitstream(unsigned int fpga_slot) +{ + unsigned char buf[256]; + static const unsigned char pattern[] = { + 0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 + }; + + // Read the first 256 bytes of the bitstream + spi_flash_read(flash_addr_of_fpga_slot(fpga_slot), sizeof(buf), buf); + + for (int i = 0; i <= sizeof(buf) - sizeof(pattern); i++) + if (memcmp(pattern, &buf[i], sizeof(pattern)) == 0) + return true; + + return false; +} + +static bool +plausible_bootconfig(bootconfig_t bc) +{ + // Are the fields in range? + if (!validate_bootconfig(bc)) + return false; + + if (!looks_like_a_bitstream(map_fpga_image_number_to_fpga_slot(bc.fpga_image_number))) + return false; + + return true; +} + +// Attempt to boot the fpga image specified in next_boot +static void +initial_boot_attempt(eeprom_boot_info_t *ee) +{ + if (ee->next_boot.fpga_image_number == OUR_FPGA_IMAGE_NUMBER){ + load_firmware(); + return; + } + + ee->nattempts = 1; + _bc_write_eeprom_shadow(); + + unsigned int target_slot = + map_fpga_image_number_to_fpga_slot(ee->next_boot.fpga_image_number); + int flash_addr = flash_addr_of_fpga_slot(target_slot); + + putstr("fpga_bootloader: chaining to "); + puthex4(ee->next_boot.fpga_image_number); + putchar(':'); + puthex4(ee->next_boot.firmware_image_number); + newline(); + mdelay(100); + + while (1){ + icap_reload_fpga(flash_addr); + } +} + +int +main(int argc, char **argv) +{ + hal_disable_ints(); // In case we got here via jmp 0x0 + hal_uart_init(); + i2c_init(); + bootconfig_init(); // Must come after i2c_init. + spif_init(); // Needed for get_flashdir. + + sr_leds->leds = 0xAAAA; + + putstr("\n\n>>> fpga_bootloader <<<\n"); + + putstr("\nBOOTSTS "); + int bootsts = icap_read_config_reg(rBOOTSTS); + puthex32_nl(bootsts); + putstr("STAT "); + int stat = icap_read_config_reg(rSTAT); + puthex32_nl(stat); + + bool fallback = + ((bootsts & (BOOTSTS_VALID_0 | BOOTSTS_FALLBACK_0)) + == (BOOTSTS_VALID_0 | BOOTSTS_FALLBACK_0)); + + if (fallback){ + puts("FALLBACK_0 is set"); + // FIXME handle fallback condition. + } + + const struct flashdir *fd = get_flashdir(); + if (fd == 0) + abort(); + + eeprom_boot_info_t *ee = _bc_get_eeprom_shadow(); + + if (VERBOSE){ + putstr("nattempts: "); + puthex8_nl(ee->nattempts); + } + + mdelay(500); // wait for low-pass on switches + putstr("switches: "); puthex32_nl(readback->switches); + + bool center_btn_down = (readback->switches & BTN_CENTER) != 0; + if (center_btn_down){ + putstr("Center button is down!\n"); + // Force boot of image 0:0 + ee->next_boot = make_bootconfig(0, 0); + } + + // if next_boot is valid, try it + if (plausible_bootconfig(ee->next_boot)) + initial_boot_attempt(ee); // no return + + // if default_boot is valid, try it + if (plausible_bootconfig(ee->default_boot)){ + ee->next_boot = ee->default_boot; + initial_boot_attempt(ee); // no return + } + + // If we're here, we're in trouble. Try all of them... + for (int i = 0; i < 4; i++){ + bootconfig_t bc = make_bootconfig(i, 0); + if (plausible_bootconfig(bc)){ + ee->next_boot = bc; + initial_boot_attempt(ee); // no return + } + } + + // FIXME, try to find something we can load + puts("\n!!! Failed to find a valid FPGA bitstream!\n\n"); + + return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c b/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c new file mode 100644 index 000000000..a2c32bf8e --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c @@ -0,0 +1,50 @@ +/* -*- 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 <memory_map.h> +#include <nonstdio.h> +#include <stdlib.h> +#include <bootconfig.h> +#include <bootconfig_private.h> +#include <bootloader_utils.h> +#include <hal_interrupts.h> + + +void hal_uart_init(void); +void spif_init(void); +void i2c_init(void); +void bootconfig_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +int +main(int argc, char **argv) +{ + hal_disable_ints(); // In case we got here via jmp 0x0 + hal_uart_init(); + i2c_init(); + bootconfig_init(); // Must come after i2c_init. + spif_init(); // Needed for get_flashdir. + + load_firmware(); +} diff --git a/firmware/microblaze/usrp2p/bootloader/icap_test.c b/firmware/microblaze/usrp2p/bootloader/icap_test.c new file mode 100644 index 000000000..5feb9d014 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/icap_test.c @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <memory_map.h> +#include <hal_io.h> +#include <xilinx_s3_icap.h> +#include <nonstdio.h> + +void delay(uint32_t t) { + while(t-- != 0) asm("NOP"); +} + + +int main(int argc, char *argv[]) { + pic_init(); + hal_uart_init(); + puts("\nStarting delay...\n"); + + output_regs->leds = 0xFF; + delay(4000000); + output_regs->leds = 0x00; + delay(4000000); + + puts("Rebooting FPGA to 0x00000000\n"); + icap_reload_fpga((uint32_t)0x00000000); + + return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c new file mode 100644 index 000000000..15d719d73 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c @@ -0,0 +1,108 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <memory_map.h> +#include <nonstdio.h> +#include <hal_io.h> +#include <xilinx_s3_icap.h> +#include <spi_flash.h> +#include <spi_flash_private.h> +//#include <clocks.h> +#include <ihex.h> +#include <bootloader_utils.h> +#include <string.h> +#include <hal_uart.h> + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +void load_ihex(void) { //simple IHEX parser to load proper records into RAM. loads program when it receives end of record. + char buf[128]; //input data buffer + uint8_t ihx[32]; //ihex data buffer + + ihex_record_t ihex_record; + ihex_record.data = ihx; + + while(1) { + gets(buf); + + if(!ihex_parse(buf, &ihex_record)) { //RAM data record is valid + if(ihex_record.addr >= RAM_BASE) { //it's expecting to see FULLY RELOCATED IHX RECORDS. every address referenced to 0x8000, including vectors. + memcpy((void *) (ihex_record.addr), ihex_record.data, ihex_record.length); + puts("OK"); + } else if(ihex_record.type == 1) { //end of record + puts("OK"); + //load main firmware + start_program(RAM_BASE); + puts("ERROR: main image returned! Back in IHEX load mode."); + } else puts("NOK"); //RAM loads do not support extended segment address records (04) -- upper 16 bits are always "0". + } else puts("NOK"); + } +} + +void delay(uint32_t t) { + while(t-- != 0) asm("NOP"); +} + +//let's clean up this logic. state machine? no, you only have to go through it once. + +//don't need else cases since all these are terminal cases + +int main(int argc, char *argv[]) { + hal_disable_ints(); // In case we got here via jmp 0x0 + output_regs->leds = 0xFF; + delay(500000); + output_regs->leds = 0x00; + hal_uart_init(); + spif_init(); +// i2c_init(); //for EEPROM + puts("USRP2+ bootloader\n"); + + if(BUTTON_PUSHED) { //see memory_map.h + puts("Starting USRP2+ in safe mode."); + if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) { + spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE); + start_program(RAM_BASE); + puts("ERROR: return from main program! This should never happen!"); + //icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); + } else { + puts("ERROR: no safe firmware image available. I am a brick. Feel free to load IHEX to RAM."); + load_ihex(); + } + } + + puts("Checking for valid production FPGA image..."); + if(is_valid_fpga_image(PROD_FPGA_IMAGE_LOCATION_ADDR)) { + puts("Valid production FPGA image found. Attempting to boot."); + //icap_reload_fpga(PROD_FPGA_IMAGE_LOCATION_ADDR); + } + puts("No valid production FPGA image found.\nAttempting to load production firmware..."); + if(is_valid_fw_image(PROD_FW_IMAGE_LOCATION_ADDR)) { + puts("Valid production firmware found. Loading..."); + spi_flash_read(PROD_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE); + start_program(RAM_BASE); + puts("ERROR: Return from main program! This should never happen!"); + //if this happens, though, the safest thing to do is reboot the whole FPGA and start over. + //icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); + return 1; + } + puts("No valid production firmware found. Trying safe firmware..."); + if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) { + spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE); + start_program(RAM_BASE); + puts("ERROR: return from main program! This should never happen!"); + //icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); + return 1; //_exit will trap in loop + } + puts("ERROR: no safe firmware image available. I am a brick. Feel free to load IHEX to RAM."); + load_ihex(); + + return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c b/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c new file mode 100644 index 000000000..4ac4df454 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <hal_io.h> +#include <nonstdio.h> +#include <mdelay.h> +#include <gdbstub2.h> + +void hal_uart_init(void); +void spif_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +int +main(int argc, char **argv) +{ + hal_uart_init(); + spif_init(); + + sr_leds->leds = 0; + mdelay(100); + sr_leds->leds = ~0; + mdelay(100); + sr_leds->leds = 0; + + puts("\n\n>>> stage1: serial_loader_burner <<<"); + + gdbstub2_main_loop(); +} diff --git a/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c b/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c new file mode 100644 index 000000000..678e66cf7 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c @@ -0,0 +1,134 @@ +/* -*- 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 <hal_io.h> +#include <nonstdio.h> +#include <mdelay.h> +#include <spi_flash.h> +#include <quadradio/flashdir.h> +#include <quadradio/simple_binary_format.h> +#include <stdlib.h> + + +void hal_uart_init(void); +void spif_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +static void +error(int e) +{ + putstr("ERR"); + puthex8(e); + newline(); +} + +static void +load(uint32_t flash_addr, uint32_t ram_addr, uint32_t size) +{ + spi_flash_read(flash_addr, size, (void *) ram_addr); +} + +static bool +load_from_slot(const struct flashdir *fd, int fw_slot) +{ + putstr("Loading f/w image "); + putchar('0' + fw_slot); + putstr("... "); + + if (fw_slot >= fd->fw_nslots){ + error(1); + return false; + } + + int slot = fw_slot + fd->fw_slot0; + if (fd->slot[slot].start == 0 || fd->slot[slot].start == 0xffff + || fd->slot[slot].len == 0 || fd->slot[slot].len == 0xffff){ + error(2); + return false; + } + + uint32_t sbf_base = fd->slot[slot].start << spi_flash_log2_sector_size(); + uint32_t sbf_len = fd->slot[slot].len << spi_flash_log2_sector_size(); + uint32_t sbf_offset = 0; + + struct sbf_header sbf; + spi_flash_read(sbf_base, sizeof(struct sbf_header), &sbf); + if (sbf.magic != SBF_MAGIC || sbf.nsections > SBF_MAX_SECTIONS){ + error(3); + return false; + } + sbf_offset += sizeof(struct sbf_header); + + unsigned int i; + for (i = 0; i < sbf.nsections; i++){ + if (sbf_offset + sbf.sec_desc[i].length > sbf_len){ + error(4); + return false; + } + load(sbf_offset + sbf_base, + sbf.sec_desc[i].target_addr, + sbf.sec_desc[i].length); + sbf_offset += sbf.sec_desc[i].length; + } + putstr("Done!"); + + typedef void (*fptr_t)(void); + (*(fptr_t) sbf.entry)(); // almost certainly no return + + return true; +} + +int +main(int argc, char **argv) +{ + hal_uart_init(); + spif_init(); + + sr_leds->leds = 0; + mdelay(100); + sr_leds->leds = ~0; + mdelay(100); + sr_leds->leds = 0; + + putstr("\n>>> spi_bootloader <<<\n"); + + const struct flashdir *fd = get_flashdir(); + if (fd == 0) + abort(); + + while(1){ + int sw; + int fw_slot; + + sw = readback->switches; + fw_slot = sw & 0x7; + + if (!load_from_slot(fd, fw_slot)){ + if (fw_slot != 0){ + putstr("Falling back to slot 0\n"); + load_from_slot(fd, 0); + } + } + } +} diff --git a/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld b/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld new file mode 100644 index 000000000..4c9eaa8e5 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld @@ -0,0 +1,190 @@ +/* + * Same as default, but with bss and stack moved to top 2K of main ram + * Copied from qr-rom.ld + */ + +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-microblaze", "", "") +/*SEARCH_DIR("/home/eb/build/Xilinx_EDK_GNU_10.1i/mb/release/lin/mb/microblaze-xilinx-elf/lib");*/ + + +ENTRY(_start) +_TEXT_START_ADDR = DEFINED(_TEXT_START_ADDR) ? _TEXT_START_ADDR : 0x50; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x0; +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x400; +_BSS_START_ADDR = DEFINED(_BSS_START_ADDR) ? _BSS_START_ADDR : 0xF800; +SECTIONS +{ + .vectors.reset 0x0 : { KEEP (*(.vectors.reset)) } = 0 + .vectors.sw_exception 0x8 : { KEEP (*(.vectors.sw_exception)) } = 0 + .vectors.interrupt 0x10 : { KEEP (*(.vectors.interrupt)) } = 0 + .vectors.debug_sw_break 0x18 : { KEEP (*(.vectors.debug_sw_break)) } = 0 + .vectors.hw_exception 0x20 : { KEEP (*(.vectors.hw_exception)) } = 0 + . = _TEXT_START_ADDR; + _ftext = .; + .text : { + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + _etext = .; + .init : { KEEP (*(.init)) } =0 + .fini : { KEEP (*(.fini)) } =0 + PROVIDE (__CTOR_LIST__ = .); + PROVIDE (___CTOR_LIST__ = .); + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + PROVIDE (__CTOR_END__ = .); + PROVIDE (___CTOR_END__ = .); + PROVIDE (__DTOR_LIST__ = .); + PROVIDE (___DTOR_LIST__ = .); + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + PROVIDE (__DTOR_END__ = .); + PROVIDE (___DTOR_END__ = .); + . = ALIGN(4); + _frodata = . ; + .rodata : { + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + CONSTRUCTORS; /* Is this needed? */ + } + _erodata = .; + /* Alignments by 8 to ensure that _SDA2_BASE_ on a word boundary */ + /* Note that .sdata2 and .sbss2 must be contiguous */ + . = ALIGN(8); + _ssrw = .; + .sdata2 : { + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + } + . = ALIGN(4); + .sbss2 : { + PROVIDE (__sbss2_start = .); + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + PROVIDE (__sbss2_end = .); + } + . = ALIGN(8); + _essrw = .; + _ssrw_size = _essrw - _ssrw; + PROVIDE (_SDA2_BASE_ = _ssrw + (_ssrw_size / 2 )); + . = ALIGN(4); + _fdata = .; + .data : { + *(.data) + *(.gnu.linkonce.d.*) + CONSTRUCTORS; /* Is this needed? */ + } + _edata = . ; + /* Added to handle pic code */ + .got : { + *(.got) + } + .got1 : { + *(.got1) + } + .got2 : { + *(.got2) + } + /* Added by Sathya to handle C++ exceptions */ + .eh_frame : { + *(.eh_frame) + } + .jcr : { + *(.jcr) + } + .gcc_except_table : { + *(.gcc_except_table) + } + /* Alignments by 8 to ensure that _SDA_BASE_ on a word boundary */ + /* Note that .sdata and .sbss must be contiguous */ + . = ALIGN(8); + _ssro = .; + .sdata : { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + } + . = ALIGN(4); + .sbss : { + PROVIDE (__sbss_start = .); + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + PROVIDE (__sbss_end = .); + } + . = ALIGN(8); + _essro = .; + _ssro_size = _essro - _ssro; + PROVIDE (_SDA_BASE_ = _ssro + (_ssro_size / 2 )); + . = _BSS_START_ADDR; + . = ALIGN(4); + _fbss = .; + .bss : { + PROVIDE (__bss_start = .); + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + PROVIDE (__bss_end = .); + } + . = ALIGN(4); + .heap : { + _heap = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; + } + _end = .; + . = ALIGN(4); + . = 0xFFF0; + .stack : { + /* + _stack_end = .; + . += _STACK_SIZE; + . = ALIGN(8); + _stack = .; + _end = .; + */ + _stack_end = .; + _stack = .; + } + .tdata : { + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + } + .tbss : { + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + } +} diff --git a/firmware/microblaze/usrp2p/bootloader_utils.c b/firmware/microblaze/usrp2p/bootloader_utils.c new file mode 100644 index 000000000..00893db02 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader_utils.c @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +//contains routines for loading programs from Flash. depends on Flash libraries. +#include <string.h> +#include <bootloader_utils.h> +#include <spi_flash.h> + + +int is_valid_fpga_image(uint32_t addr) { + static const uint8_t fpgaheader[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0x99}; //AA 99 is the standard Xilinx sync sequence, and it's always prefixed with 0xFF padding + uint8_t buf[10]; + spi_flash_read(addr, 6, buf); + return memcmp(buf, fpgaheader, 6) == 0; +} + +int is_valid_fw_image(uint32_t addr) { + static const uint8_t fwheader[] = {0xB0, 0x00, 0x00, 0x00, 0xB8, 0x08}; //just lookin for a jump to anywhere located at the reset vector + uint8_t buf[12]; + spi_flash_read(addr, 6, buf); + return memcmp(buf, fwheader, 6) == 0; +} + +void start_program(uint32_t addr) +{ + memcpy(0x00000000, addr+0x00000000, 36); //copy the whole vector table, with the reset vector, into boot RAM + typedef void (*fptr_t)(void); + (*(fptr_t) 0x00000000)(); // most likely no return +} + diff --git a/firmware/microblaze/usrp2p/bootloader_utils.h b/firmware/microblaze/usrp2p/bootloader_utils.h new file mode 100644 index 000000000..c72128f43 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader_utils.h @@ -0,0 +1,21 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <stdint.h> + +//we're working in bytes and byte addresses so we can run the same code with Flash chips of different sector sizes. +#define FPGA_IMAGE_SIZE_BYTES 2097152 +//instead of 32K, we write 31K because we're using the top 1K for stack space! +#define FW_IMAGE_SIZE_BYTES 31744 + +#define SAFE_FPGA_IMAGE_LOCATION_ADDR 0x00000000 +#define SAFE_FW_IMAGE_LOCATION_ADDR 0x007F0000 +#define PROD_FPGA_IMAGE_LOCATION_ADDR 0x00200000 +#define PROD_FW_IMAGE_LOCATION_ADDR 0x00400000 + +int is_valid_fpga_image(uint32_t addr); +int is_valid_fw_image(uint32_t addr); +void start_program(uint32_t addr); diff --git a/firmware/microblaze/usrp2p/clocks.c b/firmware/microblaze/usrp2p/clocks.c new file mode 100644 index 000000000..3488ec468 --- /dev/null +++ b/firmware/microblaze/usrp2p/clocks.c @@ -0,0 +1,259 @@ +/* -*- 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" + +//USRP2PLUS clocks: +//Clock 0: testclk +//Clock 1: FPGA clk +//Clock 2: ADC clk +//Clock 3: DAC clk +//Clock 4: SER clk +//Clock 5: TX dboard clk +//Clock 6: EXP clk +//Clock 7: RX dboard clk + +//TODO: should have enough brains to init the FPGA clock for USRP2+. all others are suspect. +//note that without EEPROM support u2_hw_rev_major is going to be incorrect. + +void +clocks_init(void) +{ + // Set up basic clocking functions in AD9510 + ad9510_write_reg(0x45, 0x01); // 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); //PHY clk is separate now (u2r4, u2p) + + // 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 + +//CHANGED: set to PECL for default behavior +void +clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mode) +{ + int enable_word, div_word, div_en_word; + + switch(mode) { + case CLOCK_MODE_LVDS : + enable_word = enable ? 0x02 : 0x03; + break; + case CLOCK_MODE_CMOS : + enable_word = enable ? 0x08 : 0x09; + break; + case CLOCK_MODE_PECL : + default: + enable_word = enable ? 0x08 : 0x0A; + break; + } + if(enable && (divisor>1)) { + div_word = clocks_gen_div(divisor); + div_en_word = CLOCK_DIV_EN; + } + else { + div_word = 0; + div_en_word = CLOCK_DIV_DIS; + } + + ad9510_write_reg(reg_en,enable_word); // Output en/dis + ad9510_write_reg(reg_div,div_word); // Set divisor + ad9510_write_reg(reg_div+1,div_en_word); // Enable or Bypass Divider + ad9510_write_reg(0x5A, 0x01); // Update Regs +} + +// Clock 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, Clock 6 on USRP2+ +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 if(u2_hw_rev_major == 10) { + ad9510_write_reg(0x34, 0x00); + ad9510_write_reg(0x35, 0x00); + ad9510_write_reg(0x36, 0x1C); + clocks_enable_XXX_clk(enable, divisor, 0x42, 0x52, CLOCK_MODE_LVDS); + } + else + putstr("ERR (clocks_enable_clkexp_out): Invalid hw rev, don't know what to do!\n"); +} + +// Clock 5 on Rev 3, none (was 2) on Rev 4, none on USRP2+ +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("(clocks_enable_eth_phyclk): no eth PHY clock or invalid hw rev\n"); //not really an error +} + +// 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/usrp2p/memory_map.h b/firmware/microblaze/usrp2p/memory_map.h new file mode 100644 index 000000000..fc0094e67 --- /dev/null +++ b/firmware/microblaze/usrp2p/memory_map.h @@ -0,0 +1,838 @@ +/* -*- 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-FFFF 64K RAM space + * + * 0000-1FFF 8K Boot RAM + * 2000-5FFF 16K Buffer pool + * 6000-7FFF 8K Peripherals + * 8000-FFFF 32K Main System RAM + + +From u2plus_core.v: +wb_1master #(.decode_w(8), +.s0_addr(8'b0000_0000),.s0_mask(8'b1110_0000), // 0-8K, Boot RAM +.s1_addr(8'b0100_0000),.s1_mask(8'b1100_0000), // 16K-32K, Buffer Pool +.s2_addr(8'b0011_0000),.s2_mask(8'b1111_1111), // SPI 0x3000 +.s3_addr(8'b0011_0001),.s3_mask(8'b1111_1111), // I2C 0x3100 +.s4_addr(8'b0011_0010),.s4_mask(8'b1111_1111), // GPIO 0x3200 +.s5_addr(8'b0011_0011),.s5_mask(8'b1111_1111), // Readback 0x3300 +.s6_addr(8'b0011_0100),.s6_mask(8'b1111_1111), // Ethernet MAC 0x3400 +.s7_addr(8'b0010_0000),.s7_mask(8'b1111_0000), // 8-12K, Settings Bus (only uses 1K) 0x2000-0x2FFF +.s8_addr(8'b0011_0101),.s8_mask(8'b1111_1111), // PIC 0x3500 +.s9_addr(8'b0011_0110),.s9_mask(8'b1111_1111), // Unused 0x3600 +.sa_addr(8'b0011_0111),.sa_mask(8'b1111_1111), // UART 0x3700 +.sb_addr(8'b0011_1000),.sb_mask(8'b1111_1111), // ATR 0x3800 +.sc_addr(8'b0011_1001),.sc_mask(8'b1111_1111), // Unused 0x3900 +.sd_addr(8'b0011_1010),.sd_mask(8'b1111_1111), // ICAP 0x3A00 +.se_addr(8'b0011_1011),.se_mask(8'b1111_1111), // SPI Flash 0x3B00 +.sf_addr(8'b1000_0000),.sf_mask(8'b1000_0000), // 32-64K, Main RAM 0x8000-0xFFFF + .dw(dw),.aw(aw),.sw(sw)) wb_1master + + */ + + +#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 +// +//////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////// +// Boot RAM, Slave 0 + +#define BOOTRAM_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 0x4000 + +#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 0x3000 // Base address (16-bit) is base peripheral addr + +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 +#define SPI_SS_ADS62P44 256 + +// Masks for different parts of CTRL reg +#define SPI_CTRL_ASS (1<<13) +#define SPI_CTRL_IE (1<<12) +#define SPI_CTRL_LSB (1<<11) +#define SPI_CTRL_TXNEG (1<<10) +#define SPI_CTRL_RXNEG (1<< 9) +#define SPI_CTRL_GO_BSY (1<< 8) +#define SPI_CTRL_CHAR_LEN_MASK 0x7F + +//////////////////////////////////////////////// +// I2C, Slave 3 +// See Wishbone I2C-Master Core Specification. + +#define I2C_BASE 0x3100 + +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 0x3200 + +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 0x3300 + +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) + +#define BUTTON_PUSHED ((buffer_pool_status->irqs & PIC_BUTTON) ? 0 : 1) + +/* + * 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 0x3400 + +#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 0x2000 +#define TX_PROTOCOL_ENGINE_BASE 0x2080 +#define RX_PROTOCOL_ENGINE_BASE 0x20C0 +#define BUFFER_POOL_CTRL_BASE 0x2100 +#define LAST_SETTING_REG 0x23FC // 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 0x3500 + +// Interrupt request lines +// Bit numbers (LSB == 0) that correpond to interrupts into PIC + +#define IRQ_BUFFER 0 // buffer manager +#define IRQ_ONETIME 1 +#define IRQ_SPI 2 +#define IRQ_I2C 3 +#define IRQ_PHY 4 // ethernet PHY +#define IRQ_UNDERRUN 5 +#define IRQ_OVERRUN 6 +#define IRQ_PPS 7 // pulse per second +#define IRQ_UART_RX 8 +#define IRQ_UART_TX 9 +#define IRQ_SERDES 10 +#define IRQ_CLKSTATUS 11 +#define IRQ_PERIODIC 12 +#define IRQ_BUTTON 13 + +#define IRQ_TO_MASK(x) (1 << (x)) + +#define PIC_BUFFER_INT IRQ_TO_MASK(IRQ_BUFFER) +#define PIC_ONETIME_INT IRQ_TO_MASK(IRQ_ONETIME) +#define PIC_SPI_INT IRQ_TO_MASK(IRQ_SPI) +#define PIC_I2C_INT IRQ_TO_MASK(IRQ_I2C) +#define PIC_PHY_INT IRQ_TO_MASK(IRQ_PHY) +#define PIC_UNDERRUN_INT IRQ_TO_MASK(IRQ_UNDERRUN) +#define PIC_OVERRUN_INT IRQ_TO_MASK(IRQ_OVERRUN) +#define PIC_PPS_INT IRQ_TO_MASK(IRQ_PPS) +#define PIC_UART_RX_INT IRQ_TO_MASK(IRQ_UART_RX) +#define PIC_UART_TX_INT IRQ_TO_MASK(IRQ_UART_TX) +#define PIC_SERDES IRQ_TO_MASK(IRQ_SERDES) +#define PIC_CLKSTATUS IRQ_TO_MASK(IRQ_CLKSTATUS) +#define PIC_BUTTON IRQ_TO_MASK(IRQ_BUTTON) + +typedef struct { + volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level + volatile uint32_t polarity; // mask: 1 -> rising edge + volatile uint32_t mask; // mask: 1 -> disabled + volatile uint32_t pending; // mask: 1 -> pending; write 1's to clear pending ints +} pic_regs_t; + +#define pic_regs ((pic_regs_t *) PIC_BASE) + +// ---------------------------------------------------------------- +// WB_CLK_RATE is the time base for this +typedef struct { + volatile uint32_t onetime; // Number of wb clk cycles till the onetime interrupt + volatile uint32_t periodic; // Repeat rate of periodic interrupt +} sr_simple_timer_t; + +#define sr_simple_timer ((sr_simple_timer_t *) _SR_ADDR(SR_SIMTIMER)) + +/////////////////////////////////////////////////// +// UNUSED, Slave 9 + +/////////////////////////////////////////////////// +// UART, Slave 10 + +#define UART_BASE 0x3700 + +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 0x3800 + +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) + +/////////////////////////////////////////////////// +// UNUSED, Slave 12 + +/////////////////////////////////////////////////// +// ICAP, Slave 13 + +#define ICAP_BASE 0x3A00 +typedef struct { + uint32_t icap; //only the lower 8 bits matter +} icap_regs_t; + +#define icap_regs ((icap_regs_t *) ICAP_BASE) + +/////////////////////////////////////////////////// +// SPI Flash interface, Slave 14 +// Control register definitions are the same as SPI, so use SPI_CTRL_ASS, etc. +// Peripheral mask not needed since bus is dedicated (CE held low) + +#define SPIF_BASE 0x3B00 +typedef struct { + volatile uint32_t txrx0; + volatile uint32_t txrx1; + volatile uint32_t txrx2; + volatile uint32_t txrx3; + volatile uint32_t ctrl; + volatile uint32_t div; + volatile uint32_t ss; +} spif_regs_t; + +#define spif_regs ((spif_regs_t *) SPIF_BASE) + +//////////////////////////////////////////////////////////////// +// Main RAM, Slave 15 + +#define RAM_BASE 0x8000 + + + +/////////////////////////////////////////////////// +#endif + diff --git a/firmware/microblaze/usrp2p/spi_flash.c b/firmware/microblaze/usrp2p/spi_flash.c new file mode 100644 index 000000000..09b74a513 --- /dev/null +++ b/firmware/microblaze/usrp2p/spi_flash.c @@ -0,0 +1,194 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * 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 "spi_flash_private.h" +//#include <stdlib.h> +#include <nonstdio.h> + +uint32_t +spi_flash_rdsr(void) +{ + return spif_transact(SPI_TXRX, SPI_SS_FLASH, RDSR_CMD << 8, 16, FLAGS) & 0xff; +} + +static void +spi_flash_write_enable(void) +{ +// spif_transact(SPI_TXONLY, SPI_SS_FLASH, (WRSR_CMD << 8) | 0x00, 16, FLAGS); //disable write protection bits + spif_transact(SPI_TXONLY, SPI_SS_FLASH, WREN_CMD, 8, FLAGS); +} + +bool +spi_flash_done_p(void) +{ + return (spi_flash_rdsr() & SR_WIP) == 0; +} + +void +spi_flash_wait(void) +{ + while (!spi_flash_done_p()) + ; +} + +void +spi_flash_erase_sector_start(uint32_t flash_addr) +{ + //uprintf(UART_DEBUG, "spi_flash_erase_sector_start: addr = 0x%x\n", flash_addr); + + spi_flash_wait(); + spi_flash_write_enable(); + spif_transact(SPI_TXONLY, SPI_SS_FLASH, + (SE_CMD << 24) | (flash_addr & 0x00ffffff), + 32, FLAGS); +} + +bool +spi_flash_page_program_start(uint32_t flash_addr, size_t nbytes, const void *buf) +{ + if (nbytes == 0 || nbytes > SPI_FLASH_PAGE_SIZE) + return false; + + uint32_t local_buf[SPI_FLASH_PAGE_SIZE / sizeof(uint32_t)]; + memset(local_buf, 0xff, sizeof(local_buf)); // init to 0xff (nops when programming) + memcpy(local_buf, buf, nbytes); + + spi_flash_wait(); + spi_flash_write_enable(); + + /* + * We explicitly control the slave select here (/S), so that we can + * do the entire write operation as a single transaction from + * device's point of view. (The most our SPI peripheral can transfer + * in a single shot is 16 bytes.) + */ + spif_wait(); + + spif_regs->ss = 0; + spif_regs->ctrl = FLAGS; // ASS is now clear and no chip select is enabled. + + /* write PP_CMD, ADDR2, ADDR1, ADDR0 */ + + spif_regs->txrx0 = (PP_CMD << 24) | (flash_addr & 0x00ffffff); + spif_regs->ss = SPI_SS_FLASH; // assert chip select + spif_regs->ctrl = FLAGS | LEN(4 * 8); + spif_regs->ctrl = FLAGS | LEN(4 * 8) | SPI_CTRL_GO_BSY; + spif_wait(); + + /* send 256 bytes total, 16 at a time */ + for (size_t i = 0; i < 16; i++){ + spif_regs->txrx3 = local_buf[i * 4 + 0]; + spif_regs->txrx2 = local_buf[i * 4 + 1]; + spif_regs->txrx1 = local_buf[i * 4 + 2]; + spif_regs->txrx0 = local_buf[i * 4 + 3]; + + spif_regs->ctrl = FLAGS | LEN(16 * 8); // xfer 16 bytes + spif_regs->ctrl = FLAGS | LEN(16 * 8) | SPI_CTRL_GO_BSY; + spif_wait(); + } + spif_regs->ss = 0; // desassert chip select + + return true; +} + +void +spi_flash_erase(uint32_t flash_addr, size_t nbytes) +{ + if (nbytes == 0) + return; + + uint32_t first = round_down(flash_addr, spi_flash_sector_size()); + uint32_t last = round_down(flash_addr + nbytes - 1, spi_flash_sector_size()); + + for (uint32_t s = first; s <= last; s += spi_flash_sector_size()){ + spi_flash_erase_sector_start(s); + } + spi_flash_wait(); +} + +bool +spi_flash_program(uint32_t flash_addr, size_t nbytes, const void *buf) +{ + //uprintf(UART_DEBUG, "\nspi_flash_program: addr = 0x%x, nbytes = %d\n", flash_addr, nbytes); + + const unsigned char *p = (const unsigned char *) buf; + size_t n; + + if (nbytes == 0) + return true; + + uint32_t r = flash_addr % SPI_FLASH_PAGE_SIZE; + if (r){ /* do initial non-aligned page */ + n = min(SPI_FLASH_PAGE_SIZE - r, nbytes); + spi_flash_page_program_start(flash_addr, n, p); + flash_addr += n; + p += n; + nbytes -= n; + } + + while (nbytes > 0){ + n = min(SPI_FLASH_PAGE_SIZE, nbytes); + spi_flash_page_program_start(flash_addr, n, p); + flash_addr += n; + p += n; + nbytes -= n; + } + + spi_flash_wait(); + return true; +} + +void +spi_flash_async_erase_start(spi_flash_async_state_t *s, + uint32_t flash_addr, size_t nbytes) +{ + if (nbytes == 0){ + s->first = s->last = s->current = 0; + return; + } + + uint32_t first = round_down(flash_addr, spi_flash_sector_size()); + uint32_t last = round_down(flash_addr + nbytes - 1, spi_flash_sector_size()); + + s->first = first; + s->last = last; + s->current = first; + + spi_flash_erase_sector_start(s->current); +} + +bool +spi_flash_async_erase_poll(spi_flash_async_state_t *s) +{ + if (!spi_flash_done_p()) + return false; + + //printf("%d/%d\n", s->current, s->last); + + // The current sector erase has completed. See if we're finished or + // if there's more to do. + + if (s->current == s->last) // we're done! + return true; + + s->current += spi_flash_sector_size(); + spi_flash_erase_sector_start(s->current); + return false; +} + diff --git a/firmware/microblaze/usrp2p/spi_flash.h b/firmware/microblaze/usrp2p/spi_flash.h new file mode 100644 index 000000000..f65f28477 --- /dev/null +++ b/firmware/microblaze/usrp2p/spi_flash.h @@ -0,0 +1,112 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * 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_SPI_FLASH_H +#define INCLUDED_SPI_FLASH_H + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + + +#define SPI_FLASH_PAGE_SIZE 256 +#define SPI_SS_FLASH 1 + + +uint32_t spi_flash_rdid(void); /* Read ID */ +uint32_t spi_flash_rdsr(void); /* Read Status Register */ +size_t spi_flash_log2_sector_size(void) __attribute__((pure)); /* either 16 or 18 */ + +static inline size_t +spi_flash_sector_size(void) +{ + return ((size_t) 1) << spi_flash_log2_sector_size(); +} + +void spi_flash_read(uint32_t flash_addr, size_t nbytes, void *buf); + +/* + * Erase all sectors that fall within the interval [flash_addr, flash_addr + nbytes). + * Erasing sets the memory to ones. + */ +void spi_flash_erase(uint32_t flash_addr, size_t nbytes); + +/* + * Program the flash. + * The area must have been erased prior to programming. + */ +bool spi_flash_program(uint32_t flash_addr, size_t nbytes, const void *buf); + +/* + * --- asynchronous routines --- + */ + +/* + * Is the erasing or programming done? + */ +bool spi_flash_done_p(void); + +/* + * Wait for erasing or programming to complete + */ +void spi_flash_wait(void); + +/* + * Start the erase process on a single sector. + * (It takes between 1 and 3 seconds to erase a 64KB sector) + */ +void spi_flash_erase_sector_start(uint32_t flash_addr); + +/* + * Start the programming process within a single page. + * nbytes must be between 1 and 256. + * (It takes between 1.4 and 5 ms to program a page -> 640 ms for 64KB) + */ +bool spi_flash_page_program_start(uint32_t flash_addr, size_t nbytes, const void *buf); + + +/* + * --- high-level async erase --- + */ + +typedef struct { + uint32_t first; + uint32_t last; + uint32_t current; +} spi_flash_async_state_t; + +/* + * Start to erase all sectors that fall within the interval [flash_addr, flash_addr + nbytes). + * Erasing sets the memory to ones. + * + * Initializes s and begins the process. Call spi_flash_async_erase_poll + * to test for completion and advance state machine. + */ +void spi_flash_async_erase_start(spi_flash_async_state_t *s, + uint32_t flash_addr, size_t nbytes); + +/* + * Poll for aysnc flash erase completion. + * Returns true when the erase has completed. + * (This should be called at something >= 4 Hz. It takes 1 to 3 seconds to + * erase each 64KB sector). + */ +bool spi_flash_async_erase_poll(spi_flash_async_state_t *s); + + +#endif /* INCLUDED_SPI_FLASH_H */ diff --git a/firmware/microblaze/usrp2p/spi_flash_private.h b/firmware/microblaze/usrp2p/spi_flash_private.h new file mode 100644 index 000000000..9a1b8d3e3 --- /dev/null +++ b/firmware/microblaze/usrp2p/spi_flash_private.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * 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_SPI_FLASH_PRIVATE_H +#define INCLUDED_SPI_FLASH_PRIVATE_H + +#include "spi_flash.h" +#include "spi.h" +#include "memory_map.h" +#include <string.h> + + +/* M25P64 et al. */ + +#define WREN_CMD 0x06 // write enable +#define WRDI_CMD 0x04 // write disable +#define RDID_CMD 0x9f // read identification +#define RDSR_CMD 0x05 // read status register +#define WRSR_CMD 0x01 // write status register +#define READ_CMD 0x03 +#define FAST_READ_CMD 0x0b +#define PP_CMD 0x02 // page program (256 bytes) +#define SE_CMD 0xd8 // sector erase (64KB) +#define BE_CMD 0xc7 // bulk erase (all) +#define RES_CMD 0xab // read electronic sig (deprecated) + +/* Status register bits */ + +#define SR_SRWD 0x80 +#define SR_BP2 0x10 // block protect bit 2 +#define SR_BP1 0x08 // block protect bit 1 +#define SR_BP0 0x04 // block protect bit 0 +#define SR_WEL 0x02 // Write Enable Latch +#define SR_WIP 0x01 // Write in Progress. Set if busy w/ program or erase cycle. + + +#define FLAGS (SPIF_PUSH_FALL | SPIF_LATCH_RISE) + +#define LEN(x) ((x) & SPI_CTRL_CHAR_LEN_MASK) + + +static inline uint32_t +min(uint32_t a, uint32_t b) +{ + return a < b ? a : b; +} + +static inline uint32_t +round_down(uint32_t x, uint32_t power_of_2) +{ + return x & -power_of_2; +} + +#endif /* INCLUDED_SPI_FLASH_PRIVATE_H */ diff --git a/firmware/microblaze/usrp2p/spi_flash_read.c b/firmware/microblaze/usrp2p/spi_flash_read.c new file mode 100644 index 000000000..1c65350f7 --- /dev/null +++ b/firmware/microblaze/usrp2p/spi_flash_read.c @@ -0,0 +1,100 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * 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 "spi_flash_private.h" +#include <stdlib.h> // abort + +uint32_t +spi_flash_rdid(void) +{ + return spif_transact(SPI_TXRX, SPI_SS_FLASH, RDID_CMD << 24, 32, FLAGS) & 0xffffff; +} + +size_t +spi_flash_log2_sector_size(void) +{ + static size_t _spi_flash_log2_sector_size; + + if (_spi_flash_log2_sector_size != 0) + return _spi_flash_log2_sector_size; + + + uint32_t id = spi_flash_rdid(); + int type = (id >> 8) & 0xff; + int size = id & 0xff; + if (type != 0x20 || size < 22 || size > 24) + abort(); + + static unsigned char log2_sector_size[3] = { + 16, /* M25P32 */ + 16, /* M25P64 */ + 18, /* M25P128 */ + }; + + _spi_flash_log2_sector_size = log2_sector_size[size - 22]; + return _spi_flash_log2_sector_size; +} + +void +spi_flash_read(uint32_t flash_addr, size_t nbytes, void *buf) +{ + /* + * We explicitly control the slave select here (/S), so that we can + * do the entire read operation as a single transaction from + * device's point of view. (The most our SPI peripheral can transfer + * in a single shot is 16 bytes.) + */ + spif_wait(); + + spif_regs->ss = 0; + spif_regs->ctrl = FLAGS; // ASS is now clear and no chip select is enabled. + + /* + * Do the 5 byte instruction tranfer: + * FAST_READ_CMD, ADDR2, ADDR1, ADDR0, DUMMY + */ + spif_regs->txrx1 = FAST_READ_CMD; + spif_regs->txrx0 = ((flash_addr & 0x00ffffff) << 8); + spif_regs->ss = SPI_SS_FLASH; // assert chip select + spif_regs->ctrl = FLAGS | LEN(5 * 8); + spif_regs->ctrl = FLAGS | LEN(5 * 8) | SPI_CTRL_GO_BSY; + spif_wait(); + + /* + * Read up to 16 bytes at a time until done + */ + unsigned char *dst = (unsigned char *) buf; + size_t m; + for (size_t n = 0; n < nbytes; n += m, dst += m){ + spif_regs->ctrl = FLAGS | LEN(16 * 8); // xfer 16 bytes + spif_regs->ctrl = FLAGS | LEN(16 * 8) | SPI_CTRL_GO_BSY; + spif_wait(); + + uint32_t w[4]; + w[0] = spif_regs->txrx3; // txrx3 has first bits in it + w[1] = spif_regs->txrx2; + w[2] = spif_regs->txrx1; + w[3] = spif_regs->txrx0; + unsigned char *src = (unsigned char *) &w[0]; + m = min(nbytes - n, 16); + for (size_t i = 0; i < m; i++) + dst[i] = src[i]; + } + spif_regs->ss = 0; // deassert chip select +} diff --git a/firmware/microblaze/usrp2p/spif.c b/firmware/microblaze/usrp2p/spif.c new file mode 100644 index 000000000..1c1a348f4 --- /dev/null +++ b/firmware/microblaze/usrp2p/spif.c @@ -0,0 +1,68 @@ +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * 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/>. + */ + +/* + * Code for the Flash SPI bus + */ + +#include "spi.h" +#include "memory_map.h" + +void +spif_init(void) +{ + /* + * f_sclk = f_wb / ((div + 1) * 2) + */ + spif_regs->div = 1; // 0 = Div by 2 (31.25 MHz); 1 = Div-by-4 (15.625 MHz) + + // run dummy transaction to work around invalid initial clock state + spif_transact(SPI_TXONLY, 0, 0, 8, SPIF_PUSH_FALL | SPIF_LATCH_RISE); +} + +inline void +spif_wait(void) +{ + while (spif_regs->ctrl & SPI_CTRL_GO_BSY) + ; +} + +uint32_t +spif_transact(bool readback_, int slave, uint32_t data, int length, uint32_t flags) +{ + flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); + int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + + spif_wait(); + + // Data we will send + spif_regs->txrx0 = data; + + // Run it -- write once and rewrite with GO set + spif_regs->ctrl = ctrl; + // Tell it which SPI slave device to access + spif_regs->ss = slave & 0xff; + spif_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; + + if(readback_) { + spif_wait(); + return spif_regs->txrx0; + } + else + return 0; +} diff --git a/firmware/microblaze/usrp2p/xilinx_s3_icap.h b/firmware/microblaze/usrp2p/xilinx_s3_icap.h new file mode 100644 index 000000000..7b7e9eccc --- /dev/null +++ b/firmware/microblaze/usrp2p/xilinx_s3_icap.h @@ -0,0 +1,37 @@ +/* -*- 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_XILINX_S3_ICAP_H +#define INCLUDED_XILINX_S3_ICAP_H + +#include <stdint.h> + + +void wr_icap(uint8_t x); +uint8_t rd_icap(void); + +//int icap_read_config_reg(int regno); + +/* + * Attempt to reload the fpga from \p flash_address. + * Shouldn't return, but might. + */ +void icap_reload_fpga(uint32_t flash_address); + + +#endif /* INCLUDED_XILINX_S3_ICAP_H */ diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt index ba1bbc9f0..39f26a5a6 100644 --- a/host/lib/ic_reg_maps/CMakeLists.txt +++ b/host/lib/ic_reg_maps/CMakeLists.txt @@ -63,3 +63,8 @@ LIBUHD_PYTHON_GEN_SOURCE( ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9522_regs.py ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9522_regs.hpp ) + +LIBUHD_PYTHON_GEN_SOURCE( + ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ads62p44_regs.py + ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ads62p44_regs.hpp +) diff --git a/host/lib/ic_reg_maps/gen_ads62p44_regs.py b/host/lib/ic_reg_maps/gen_ads62p44_regs.py new file mode 100755 index 000000000..f0a84d940 --- /dev/null +++ b/host/lib/ic_reg_maps/gen_ads62p44_regs.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# +# 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/>. +# + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_TMPL="""\ +######################################################################## +## address 0 +######################################################################## +reset 0[1] 0 +serial_readout 0[0] 0 +######################################################################## +## address 16 +######################################################################## +clkout_strength 16[6:7] 0 weaker=1, default=0, stronger=3 +######################################################################## +## address 17 +######################################################################## +dataout_strength 17[0:1] 0 weaker=1, default=0, stronger=3, maximum=2 +lvds_current 17[2:3] 0 3_5ma, 2_5ma, 4_5ma, 1_75ma +lvds_current_double 17[4:5] 0 default, dblclk, dbldataclock +######################################################################## +## address 18 +######################################################################## +lvds_clk_term 18[0:2] 0 none, 300, 180, 110, 150, 100, 81, 60 +lvds_data_term 18[3:5] 0 none, 300, 180, 110, 150, 100, 81, 60 +######################################################################## +## address 19 +######################################################################## +offset_freeze 19[4] 0 +######################################################################## +## address 20 +######################################################################## +power_down 20[0:2] 0 normal, a_dis, b_dis, ab_dis, global_pd, a_sby, b_sby, mux +ref_select 20[3] 0 internal, external +coarse_gain 20[4] 0 0db, 3_5db +output_interface 20[5] 0 cmos, lvds +override 20[7] 0 +######################################################################## +## address 22 +######################################################################## +test_patterns 22[0:2] 0 normal, zeros, ones, toggle, ramp, custom +lvds_bytewise 22[3] 0 +data_format 22[4] 0 twos_complement, binary +######################################################################## +## address 23 +######################################################################## +fine_gain 23[0:3] 0 +######################################################################## +## address 24 and 25 +######################################################################## +custom_low 24[0:7] 0 +custom_high 25[0:5] 0 +######################################################################## +## address 26 +######################################################################## +gain_correction 26[0:3] 0 +offset_tc 26[4:6] 0 1_1s, 0_55s, 0_27s, 0_13s, 2_15s, 4_3s +low_latency 26[7] 0 +######################################################################## +## address 27 +######################################################################## +decimation 27[0:2] 0 decimate_2, decimate_4, decimate_1, decimate_8 +odd_tap_enable 27[3] 0 +filter_enable 27[4] 0 +filter_coeff_sel 27[5] 0 predefined, userdefined +offset_enable 27[7] 0 +######################################################################## +## address 29 +######################################################################## +decimation_filter_bands 29[0:1] 0 +""" + +######################################################################## +# Template for methods in the body of the struct +######################################################################## +BODY_TMPL="""\ +boost::uint8_t get_reg(boost::uint8_t addr){ + boost::uint8_t reg = 0; + switch(addr){ + #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) + case $addr: + #for $reg in filter(lambda r: r.get_addr() == addr, $regs) + reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); + #end for + break; + #end for + } + return reg; +} + +boost::uint16_t get_write_reg(boost::uint8_t addr){ + return (boost::uint16_t(addr) << 8) | get_reg(addr); +} + +boost::uint16_t get_read_reg(boost::uint8_t addr){ + return (boost::uint16_t(addr) << 8) | (1 << 7); +} +""" + +if __name__ == '__main__': + import common; common.generate( + name='ads62p44_regs', + regs_tmpl=REGS_TMPL, + body_tmpl=BODY_TMPL, + file=__file__, + ) diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 796126d07..b4a90a6ba 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -35,4 +35,5 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.hpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.cpp ) diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index b9be037c0..5ed8ec079 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -18,6 +18,7 @@ #include "clock_ctrl.hpp" #include "ad9510_regs.hpp" #include "usrp2_regs.hpp" //spi slave constants +#include "usrp2_clk_regs.hpp" #include <uhd/utils/assert.hpp> #include <boost/cstdint.hpp> @@ -29,10 +30,12 @@ using namespace uhd; class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{ public: usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){ - _iface = iface; + _iface = iface; //_iface has get_hw_rev(), which lets us know if it's a USRP2+ (>=0x80) or USRP2 (<0x80). + + clk_regs = usrp2_clk_regs_t(_iface->get_hw_rev()); _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; - this->write_reg(0x09); + this->write_reg(clk_regs.pll_3); // Setup the clock registers to 100MHz: // This was already done by the firmware (or the host couldnt communicate). @@ -42,20 +45,20 @@ public: _ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL; _ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2; - this->write_reg(0x0A); + this->write_reg(clk_regs.pll_4); _ad9510_regs.acounter = 0; - this->write_reg(0x04); + this->write_reg(clk_regs.acounter); _ad9510_regs.bcounter_msb = 0; _ad9510_regs.bcounter_lsb = 5; - this->write_reg(0x05); - this->write_reg(0x06); + this->write_reg(clk_regs.bcounter_msb); + this->write_reg(clk_regs.bcounter_lsb); _ad9510_regs.ref_counter_msb = 0; _ad9510_regs.ref_counter_lsb = 1; // r divider = 1 - this->write_reg(0x0B); - this->write_reg(0x0C); + this->write_reg(clk_regs.ref_counter_msb); + this->write_reg(clk_regs.ref_counter_lsb); /* regs will be updated in commands below */ @@ -76,11 +79,12 @@ public: } //uses output clock 7 (cmos) + //this clock is the same between USRP2 and USRP2+ and so this fn does not get a switch statement void enable_rx_dboard_clock(bool enb){ _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1; _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS; _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; - this->write_reg(0x43); + this->write_reg(clk_regs.output(clk_regs.rx_db)); this->update_regs(); } @@ -96,8 +100,8 @@ public: _ad9510_regs.divider_low_cycles_out7 = low - 1; _ad9510_regs.divider_high_cycles_out7 = high - 1; //write the registers - this->write_reg(0x56); - this->write_reg(0x57); + this->write_reg(clk_regs.div_lo(clk_regs.rx_db)); + this->write_reg(clk_regs.div_hi(clk_regs.rx_db)); this->update_regs(); } @@ -107,29 +111,50 @@ public: return rates; } - //uses output clock 6 (cmos) + //uses output clock 6 (cmos) on USRP2 and output clock 5 (cmos) on USRP2+ void enable_tx_dboard_clock(bool enb){ - _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS; - _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; - this->write_reg(0x42); + switch(clk_regs.tx_db) { + case 5: //USRP2+ + _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1; + _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_CMOS; + _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA; + break; + case 6: //USRP2 + _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1; + _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS; + _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; + break; + } + + this->write_reg(clk_regs.output(clk_regs.tx_db)); this->update_regs(); } void set_rate_tx_dboard_clock(double rate){ assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate"); size_t divider = size_t(rate/get_master_clock_rate()); - //bypass when the divider ratio is one - _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0; //calculate the low and high dividers size_t high = divider/2; size_t low = divider - high; - //set the registers (divider - 1) - _ad9510_regs.divider_low_cycles_out6 = low - 1; - _ad9510_regs.divider_high_cycles_out6 = high - 1; + + switch(clk_regs.tx_db) { + case 5: //USRP2+ + _ad9510_regs.bypass_divider_out5 = (divider == 1)? 1 : 0; + _ad9510_regs.divider_low_cycles_out5 = low - 1; + _ad9510_regs.divider_high_cycles_out5 = high - 1; + break; + case 6: //USRP2 + //bypass when the divider ratio is one + _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0; + //set the registers (divider - 1) + _ad9510_regs.divider_low_cycles_out6 = low - 1; + _ad9510_regs.divider_high_cycles_out6 = high - 1; + break; + } + //write the registers - this->write_reg(0x54); - this->write_reg(0x55); + this->write_reg(clk_regs.div_hi(clk_regs.tx_db)); + this->write_reg(clk_regs.div_lo(clk_regs.tx_db)); this->update_regs(); } @@ -147,7 +172,7 @@ public: ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ; _ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH; _ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS; - this->write_reg(0x08); + this->write_reg(clk_regs.pll_2); this->update_regs(); } @@ -170,32 +195,44 @@ private: */ void update_regs(void){ _ad9510_regs.update_registers = 1; - this->write_reg(0x5a); + this->write_reg(clk_regs.update); } //uses output clock 3 (pecl) + //this is the same between USRP2 and USRP2+ and doesn't get a switch statement void enable_dac_clock(bool enb){ _ad9510_regs.power_down_lvpecl_out3 = (enb)? ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL : ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD; _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV; _ad9510_regs.bypass_divider_out3 = 1; - this->write_reg(0x3F); - this->write_reg(0x4F); + this->write_reg(clk_regs.output(clk_regs.dac)); + this->write_reg(clk_regs.div_hi(clk_regs.dac)); this->update_regs(); } - //uses output clock 4 (lvds) + //uses output clock 4 (lvds) on USRP2 and output clock 2 (lvpecl) on USRP2+ void enable_adc_clock(bool enb){ - _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS; - _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA; - _ad9510_regs.bypass_divider_out4 = 1; - this->write_reg(0x40); - this->write_reg(0x51); + switch(clk_regs.adc) { + case 2: + _ad9510_regs.power_down_lvpecl_out2 = enb? ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL : ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD; + _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_500MV; + _ad9510_regs.bypass_divider_out2 = 1; + break; + case 4: + _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1; + _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS; + _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA; + _ad9510_regs.bypass_divider_out4 = 1; + break; + } + + this->write_reg(clk_regs.output(clk_regs.adc)); + this->write_reg(clk_regs.div_hi(clk_regs.adc)); this->update_regs(); } + usrp2_clk_regs_t clk_regs; usrp2_iface::sptr _iface; ad9510_regs_t _ad9510_regs; }; diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index 32cc13ded..107894d2a 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -17,6 +17,7 @@ #include "codec_ctrl.hpp" #include "ad9777_regs.hpp" +#include "ads62p44_regs.hpp" #include "usrp2_regs.hpp" #include <boost/cstdint.hpp> #include <boost/foreach.hpp> @@ -57,7 +58,16 @@ public: } //power-up adc - _iface->poke32(U2_REG_MISC_CTRL_ADC, U2_FLAG_MISC_CTRL_ADC_ON); + if(_iface->get_hw_rev() < USRP2P_FIRST_HW_REV) { //if we're on a USRP2 + _iface->poke32(_iface->regs.misc_ctrl_adc, U2_FLAG_MISC_CTRL_ADC_ON); + } else { //we're on a USRP2+ + _ads62p44_regs.reset = 1; + this->send_ads62p44_reg(0x00); //issue a reset to the ADC + //everything else should be pretty much default, i think +// _ads62p44_regs.decimation = DECIMATION_DECIMATE_1; + + + } } ~usrp2_codec_ctrl_impl(void){ @@ -66,11 +76,21 @@ public: this->send_ad9777_reg(0); //power-down adc - _iface->poke32(U2_REG_MISC_CTRL_ADC, U2_FLAG_MISC_CTRL_ADC_OFF); + if(_iface->get_hw_rev() < USRP2P_FIRST_HW_REV) { //if we're on a USRP2 + _iface->poke32(_iface->regs.misc_ctrl_adc, U2_FLAG_MISC_CTRL_ADC_OFF); + } else { //we're on a USRP2+ +// _ads62p44_regs.reset = 1; +// this->send_ads62p44_reg(0x00); //issue a reset to the ADC + //everything else should be pretty much default, i think +// _ads62p44_regs.decimation = DECIMATION_DECIMATE_1; + + + } } private: ad9777_regs_t _ad9777_regs; + ads62p44_regs_t _ads62p44_regs; usrp2_iface::sptr _iface; void send_ad9777_reg(boost::uint8_t addr){ @@ -81,6 +101,14 @@ private: reg, 16, false /*no rb*/ ); } + + void send_ads62p44_reg(boost::uint8_t addr) { + boost::uint16_t reg = _ads62p44_regs.get_write_reg(addr); + _iface->transact_spi( + SPI_SS_ADS62P44, spi_config_t::EDGE_RISE, + reg, 16, false /*no rb*/ + ); + } }; /*********************************************************************** diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index 6f2fb9396..5c81856bb 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -168,8 +168,8 @@ void usrp2_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value){ //write the selection mux value to register switch(unit){ - case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return; - case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return; + case UNIT_RX: _iface->poke32(_iface->regs.gpio_rx_sel, new_sels); return; + case UNIT_TX: _iface->poke32(_iface->regs.gpio_tx_sel, new_sels); return; } } @@ -177,18 +177,18 @@ void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){ _ddr_shadow = \ (_ddr_shadow & ~(0xffff << unit_to_shift[unit])) | (boost::uint32_t(value) << unit_to_shift[unit]); - _iface->poke32(U2_REG_GPIO_DDR, _ddr_shadow); + _iface->poke32(_iface->regs.gpio_ddr, _ddr_shadow); } void usrp2_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value){ _gpio_shadow = \ (_gpio_shadow & ~(0xffff << unit_to_shift[unit])) | (boost::uint32_t(value) << unit_to_shift[unit]); - _iface->poke32(U2_REG_GPIO_IO, _gpio_shadow); + _iface->poke32(_iface->regs.gpio_io, _gpio_shadow); } boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){ - return boost::uint16_t(_iface->peek32(U2_REG_GPIO_IO) >> unit_to_shift[unit]); + return boost::uint16_t(_iface->peek32(_iface->regs.gpio_io) >> unit_to_shift[unit]); } void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){ @@ -197,16 +197,16 @@ void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t unit_t, uhd::dict<atr_reg_t, boost::uint32_t> > unit_to_atr_to_addr = map_list_of (UNIT_RX, map_list_of - (ATR_REG_IDLE, U2_REG_ATR_IDLE_RXSIDE) - (ATR_REG_TX_ONLY, U2_REG_ATR_INTX_RXSIDE) - (ATR_REG_RX_ONLY, U2_REG_ATR_INRX_RXSIDE) - (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_RXSIDE) + (ATR_REG_IDLE, _iface->regs.atr_idle_rxside) + (ATR_REG_TX_ONLY, _iface->regs.atr_intx_rxside) + (ATR_REG_RX_ONLY, _iface->regs.atr_inrx_rxside) + (ATR_REG_FULL_DUPLEX, _iface->regs.atr_full_rxside) ) (UNIT_TX, map_list_of - (ATR_REG_IDLE, U2_REG_ATR_IDLE_TXSIDE) - (ATR_REG_TX_ONLY, U2_REG_ATR_INTX_TXSIDE) - (ATR_REG_RX_ONLY, U2_REG_ATR_INRX_TXSIDE) - (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_TXSIDE) + (ATR_REG_IDLE, _iface->regs.atr_idle_txside) + (ATR_REG_TX_ONLY, _iface->regs.atr_intx_txside) + (ATR_REG_RX_ONLY, _iface->regs.atr_inrx_txside) + (ATR_REG_FULL_DUPLEX, _iface->regs.atr_full_txside) ) ; _iface->poke16(unit_to_atr_to_addr[unit][atr], value); diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index e0d6beafc..3a2a53674 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -35,8 +35,8 @@ using namespace uhd::usrp; **********************************************************************/ void usrp2_mboard_impl::dboard_init(void){ //read the dboard eeprom to extract the dboard ids - _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); - _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); + _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); + _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); //create a new dboard interface and manager _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl); @@ -113,7 +113,7 @@ void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ UHD_ASSERT_THROW(_rx_subdevs_in_use.size() == 1); wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0)); std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl; - _iface->poke32(U2_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word( + _iface->poke32(_iface->regs.dsp_rx_mux, dsp_type1::calc_rx_mux_word( rx_subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() )); } @@ -121,7 +121,7 @@ void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ case DBOARD_PROP_DBOARD_ID: _rx_db_eeprom.id = val.as<dboard_id_t>(); - _iface->write_eeprom(I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes()); + _iface->write_eeprom(USRP2_I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes()); return; default: UHD_THROW_PROP_SET_ERROR(); @@ -182,7 +182,7 @@ void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ UHD_ASSERT_THROW(_tx_subdevs_in_use.size() == 1); wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0)); std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl; - _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word( + _iface->poke32(_iface->regs.dsp_tx_mux, dsp_type1::calc_tx_mux_word( tx_subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() )); } @@ -190,7 +190,7 @@ void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ case DBOARD_PROP_DBOARD_ID: _tx_db_eeprom.id = val.as<dboard_id_t>(); - _iface->write_eeprom(I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes()); + _iface->write_eeprom(USRP2_I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes()); return; default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 7d9cdc441..936b1f7a2 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -86,7 +86,7 @@ void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){ case DSP_PROP_FREQ_SHIFT:{ double new_freq = val.as<double>(); - _iface->poke32(U2_REG_DSP_RX_FREQ, + _iface->poke32(_iface->regs.dsp_rx_freq, dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq()) ); _ddc_freq = new_freq; //shadow @@ -98,11 +98,11 @@ void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){ _ddc_decim = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates); //set the decimation - _iface->poke32(U2_REG_DSP_RX_DECIM_RATE, dsp_type1::calc_cic_filter_word(_ddc_decim)); + _iface->poke32(_iface->regs.dsp_rx_decim_rate, dsp_type1::calc_cic_filter_word(_ddc_decim)); //set the scaling static const boost::int16_t default_rx_scale_iq = 1024; - _iface->poke32(U2_REG_DSP_RX_SCALE_IQ, + _iface->poke32(_iface->regs.dsp_rx_scale_iq, dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) ); } @@ -161,7 +161,7 @@ void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){ case DSP_PROP_FREQ_SHIFT:{ double new_freq = val.as<double>(); - _iface->poke32(U2_REG_DSP_TX_FREQ, + _iface->poke32(_iface->regs.dsp_tx_freq, dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq()) ); _duc_freq = new_freq; //shadow @@ -173,10 +173,10 @@ void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){ _duc_interp = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates); //set the interpolation - _iface->poke32(U2_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_duc_interp)); + _iface->poke32(_iface->regs.dsp_tx_interp_rate, dsp_type1::calc_cic_filter_word(_duc_interp)); //set the scaling - _iface->poke32(U2_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_duc_interp)); + _iface->poke32(_iface->regs.dsp_tx_scale_iq, dsp_type1::calc_iq_scale_word(_duc_interp)); } return; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index fd728e393..c4dabf5bc 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -44,6 +44,22 @@ extern "C" { #define USRP2_UDP_CTRL_PORT 49152 #define USRP2_UDP_DATA_PORT 49153 +//////////////////////////////////////////////////////////////////////// +// I2C addresses +//////////////////////////////////////////////////////////////////////// +#define USRP2_I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx +#define USRP2_I2C_ADDR_MBOARD (USRP2_I2C_DEV_EEPROM | 0x0) +#define USRP2_I2C_ADDR_TX_DB (USRP2_I2C_DEV_EEPROM | 0x4) +#define USRP2_I2C_ADDR_RX_DB (USRP2_I2C_DEV_EEPROM | 0x5) + +//////////////////////////////////////////////////////////////////////// +// EEPROM Layout +//////////////////////////////////////////////////////////////////////// +#define USRP2_EE_MBOARD_REV_LSB 0x00 //1 byte +#define USRP2_EE_MBOARD_REV_MSB 0x01 //1 byte +#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes +#define USRP2_EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian + typedef enum{ USRP2_CTRL_ID_HUH_WHAT = ' ', //USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 2f5a51c51..d6a129415 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -45,8 +45,11 @@ usrp2_mboard_impl::usrp2_mboard_impl( _iface = usrp2_iface::make(ctrl_transport); //extract the mboard rev numbers - _rev_lo = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_LSB, 1).at(0); - _rev_hi = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_MSB, 1).at(0); + _rev_lo = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, 1).at(0); + _rev_hi = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, 1).at(0); + + //set the device revision (USRP2 or USRP2+) based on the above + _iface->set_hw_rev((_rev_hi << 8) | _rev_lo); //contruct the interfaces to mboard perifs _clock_ctrl = usrp2_clock_ctrl::make(_iface); @@ -68,18 +71,18 @@ usrp2_mboard_impl::usrp2_mboard_impl( } //setup the vrt rx registers - _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet()); - _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); - _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset - _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 0 + _iface->poke32(_iface->regs.rx_ctrl_nsamps_per_pkt, _io_helper.get_max_recv_samps_per_packet()); + _iface->poke32(_iface->regs.rx_ctrl_nchannels, 1); + _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //reset + _iface->poke32(_iface->regs.rx_ctrl_vrt_header, 0 | (0x1 << 28) //if data with stream id | (0x1 << 26) //has trailer | (0x3 << 22) //integer time other | (0x1 << 20) //fractional time sample count ); - _iface->poke32(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); - _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); - _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq())); + _iface->poke32(_iface->regs.rx_ctrl_vrt_stream_id, 0); + _iface->poke32(_iface->regs.rx_ctrl_vrt_trailer, 0); + _iface->poke32(_iface->regs.time64_tps, size_t(get_master_clock_freq())); //init the ddc init_ddc_config(); @@ -132,13 +135,13 @@ void usrp2_mboard_impl::update_clock_config(void){ } //set the pps flags - _iface->poke32(U2_REG_TIME64_FLAGS, pps_flags); + _iface->poke32(_iface->regs.time64_flags, pps_flags); //clock source ref 10mhz switch(_clock_config.ref_source){ - case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); break; - case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break; - case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break; + case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x10); break; + case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break; + case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break; default: throw std::runtime_error("usrp2: unhandled clock configuration reference source"); } @@ -149,22 +152,22 @@ void usrp2_mboard_impl::update_clock_config(void){ void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ //set the ticks - _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq())); + _iface->poke32(_iface->regs.time64_ticks, time_spec.get_tick_count(get_master_clock_freq())); //set the flags register boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS; - _iface->poke32(U2_REG_TIME64_IMM, imm_flags); + _iface->poke32(_iface->regs.time64_imm, imm_flags); //set the seconds (latches in all 3 registers) - _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); + _iface->poke32(_iface->regs.time64_secs, boost::uint32_t(time_spec.get_full_secs())); } void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ - _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, dsp_type1::calc_stream_cmd_word( + _iface->poke32(_iface->regs.rx_ctrl_stream_cmd, dsp_type1::calc_stream_cmd_word( stream_cmd, _io_helper.get_max_recv_samps_per_packet() )); - _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); - _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); + _iface->poke32(_iface->regs.rx_ctrl_time_secs, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); + _iface->poke32(_iface->regs.rx_ctrl_time_ticks, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); } /*********************************************************************** @@ -177,14 +180,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ if (key.as<std::string>() == "mac-addr"){ - byte_vector_t bytes = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, 6); + byte_vector_t bytes = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, 6); val = mac_addr_t::from_bytes(bytes).to_string(); return; } if (key.as<std::string>() == "ip-addr"){ boost::asio::ip::address_v4::bytes_type bytes; - std::copy(_iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, 4), bytes); + std::copy(_iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, 4), bytes); val = boost::asio::ip::address_v4(bytes).to_string(); return; } @@ -247,7 +250,7 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ case MBOARD_PROP_TIME_NOW:{ usrp2_iface::pair64 time64( - _iface->peek64(U2_REG_TIME64_SECS_RB, U2_REG_TIME64_TICKS_RB) + _iface->peek64(_iface->regs.time64_secs_rb, _iface->regs.time64_ticks_rb) ); val = time_spec_t( time64.first, time64.second, get_master_clock_freq() @@ -267,14 +270,14 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ if (key.type() == typeid(std::string)){ if (key.as<std::string>() == "mac-addr"){ byte_vector_t bytes = mac_addr_t::from_string(val.as<std::string>()).to_bytes(); - _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, bytes); + _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, bytes); return; } if (key.as<std::string>() == "ip-addr"){ byte_vector_t bytes(4); std::copy(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_bytes(), bytes); - _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, bytes); + _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, bytes); return; } } diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp index e83dceb96..1cda22f45 100644 --- a/host/lib/usrp/usrp2/serdes_ctrl.cpp +++ b/host/lib/usrp/usrp2/serdes_ctrl.cpp @@ -27,11 +27,11 @@ class usrp2_serdes_ctrl_impl : public usrp2_serdes_ctrl{ public: usrp2_serdes_ctrl_impl(usrp2_iface::sptr iface){ _iface = iface; - _iface->poke32(U2_REG_MISC_CTRL_SERDES, U2_FLAG_MISC_CTRL_SERDES_ENABLE | U2_FLAG_MISC_CTRL_SERDES_RXEN); + _iface->poke32(_iface->regs.misc_ctrl_serdes, U2_FLAG_MISC_CTRL_SERDES_ENABLE | U2_FLAG_MISC_CTRL_SERDES_RXEN); } ~usrp2_serdes_ctrl_impl(void){ - _iface->poke32(U2_REG_MISC_CTRL_SERDES, 0); //power-down + _iface->poke32(_iface->regs.misc_ctrl_serdes, 0); //power-down } private: diff --git a/host/lib/usrp/usrp2/usrp2_clk_regs.hpp b/host/lib/usrp/usrp2/usrp2_clk_regs.hpp new file mode 100644 index 000000000..d057fb342 --- /dev/null +++ b/host/lib/usrp/usrp2/usrp2_clk_regs.hpp @@ -0,0 +1,63 @@ +// +// 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_USRP2_CLK_REGS_HPP +#define INCLUDED_USRP2_CLK_REGS_HPP + +#include "usrp2_regs.hpp" + +class usrp2_clk_regs_t { +public: + usrp2_clk_regs_t(void) { ; } + usrp2_clk_regs_t(int hw_rev) { + test = 0; + fpga = 1; + adc = (hw_rev>=USRP2P_FIRST_HW_REV) ? 2 : 4; + dac = 3; + serdes = (hw_rev>=USRP2P_FIRST_HW_REV) ? 4 : 2; //only used by usrp2+ + tx_db = (hw_rev>=USRP2P_FIRST_HW_REV) ? 5 : 6; + exp = (hw_rev>=USRP2P_FIRST_HW_REV) ? 6 : 5; + rx_db = 7; + } + + static int output(int clknum) { return 0x3C + clknum; } + static int div_lo(int clknum) { return 0x48 + 2 * clknum; } + static int div_hi(int clknum) { return 0x49 + 2 * clknum; } + + const static int acounter = 0x04; + const static int bcounter_msb = 0x05; + const static int bcounter_lsb = 0x06; + const static int pll_1 = 0x07; + const static int pll_2 = 0x08; + const static int pll_3 = 0x09; + const static int pll_4 = 0x0A; + const static int ref_counter_msb = 0x0B; + const static int ref_counter_lsb = 0x0C; + const static int pll_5 = 0x0D; + const static int update = 0x5A; + + int test; + int fpga; + int adc; + int dac; + int serdes; + int exp; + int tx_db; + int rx_db; +}; + +#endif //INCLUDED_USRP2_CLK_REGS_HPP diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index a21157d76..17ba75d85 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -193,6 +193,19 @@ public: throw std::runtime_error("usrp2 no control response"); } + /*********************************************************************** + * Get/set hardware revision + **********************************************************************/ + void set_hw_rev(int rev) { + hw_rev = rev; + regs = usrp2_get_regs(rev); //might be a better place to do this + } + + int get_hw_rev(void) { + return hw_rev; + } + + private: //this lovely lady makes it all possible udp_simple::sptr _ctrl_transport; diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 9cc32104e..b9f5f0fb8 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -25,22 +25,7 @@ #include <boost/cstdint.hpp> #include <utility> #include "fw_common.h" - -//////////////////////////////////////////////////////////////////////// -// I2C addresses -//////////////////////////////////////////////////////////////////////// -#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx -#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) -#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4) -#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5) - -//////////////////////////////////////////////////////////////////////// -// EEPROM Layout -//////////////////////////////////////////////////////////////////////// -#define EE_MBOARD_REV_LSB 0x00 //1 byte -#define EE_MBOARD_REV_MSB 0x01 //1 byte -#define EE_MBOARD_MAC_ADDR 0x02 //6 bytes -#define EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian +#include "usrp2_regs.hpp" /*! * The usrp2 interface class: @@ -118,6 +103,26 @@ public: size_t num_bits, bool readback ) = 0; + + /*! + * Set the hardware revision number. Also selects the proper register set for the device. + * \param rev the 16-bit revision + */ + virtual void set_hw_rev(int rev) = 0; + + /*! Return the hardware revision number + * \return hardware revision + */ + virtual int get_hw_rev(void) = 0; + + /*! + * Register map selected from USRP2/USRP2+. + */ + usrp2_regs_t regs; + /*! + * Hardware revision as returned by the device. + */ + int hw_rev; }; #endif /* INCLUDED_USRP2_IFACE_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp new file mode 100644 index 000000000..071ba0cd2 --- /dev/null +++ b/host/lib/usrp/usrp2/usrp2_regs.cpp @@ -0,0 +1,94 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp2_regs.hpp" + +int sr_addr(int misc_output_base, int sr) { + return misc_output_base + 4 * sr; +} + +usrp2_regs_t usrp2_get_regs(int hw_rev) { + + //how about you just make this dependent on hw_rev instead of doing the init before main, and give up the const globals, since the application won't ever need both. + const int misc_output_base = (hw_rev>=USRP2P_FIRST_HW_REV) ? USRP2P_MISC_OUTPUT_BASE : USRP2_MISC_OUTPUT_BASE, + gpio_base = (hw_rev>=USRP2P_FIRST_HW_REV) ? USRP2P_GPIO_BASE : USRP2_GPIO_BASE, + atr_base = (hw_rev>=USRP2P_FIRST_HW_REV) ? USRP2P_ATR_BASE : USRP2_ATR_BASE, + bp_base = (hw_rev>=USRP2P_FIRST_HW_REV) ? USRP2P_BP_STATUS_BASE : USRP2_BP_STATUS_BASE; + + usrp2_regs_t x; + x.sr_misc = 0; + x.sr_tx_prot_eng = 32; + x.sr_rx_prot_eng = 48; + x.sr_buffer_pool_ctrl = 64; + x.sr_udp_sm = 96; + x.sr_tx_dsp = 208; + x.sr_tx_ctrl = 224; + x.sr_rx_dsp = 160; + x.sr_rx_ctrl = 176; + x.sr_time64 = 192; + x.sr_simtimer = 198; + x.sr_last = 255; + x.misc_ctrl_clock = sr_addr(misc_output_base, 0); + x.misc_ctrl_serdes = sr_addr(misc_output_base, 1); + x.misc_ctrl_adc = sr_addr(misc_output_base, 2); + x.misc_ctrl_leds = sr_addr(misc_output_base, 3); + x.misc_ctrl_phy = sr_addr(misc_output_base, 4); + x.misc_ctrl_dbg_mux = sr_addr(misc_output_base, 5); + x.misc_ctrl_ram_page = sr_addr(misc_output_base, 6); + x.misc_ctrl_flush_icache = sr_addr(misc_output_base, 7); + x.misc_ctrl_led_src = sr_addr(misc_output_base, 8); + x.time64_secs = sr_addr(misc_output_base, x.sr_time64 + 0); + x.time64_ticks = sr_addr(misc_output_base, x.sr_time64 + 1); + x.time64_flags = sr_addr(misc_output_base, x.sr_time64 + 2); + x.time64_imm = sr_addr(misc_output_base, x.sr_time64 + 3); + x.time64_tps = sr_addr(misc_output_base, x.sr_time64 + 4); + x.time64_secs_rb = bp_base + 4*10; + x.time64_ticks_rb = bp_base + 4*11; + x.dsp_tx_freq = sr_addr(misc_output_base, x.sr_tx_dsp + 0); + x.dsp_tx_scale_iq = sr_addr(misc_output_base, x.sr_tx_dsp + 1); + x.dsp_tx_interp_rate = sr_addr(misc_output_base, x.sr_tx_dsp + 2); + x.dsp_tx_mux = sr_addr(misc_output_base, x.sr_tx_dsp + 4); + x.dsp_rx_freq = sr_addr(misc_output_base, x.sr_rx_dsp + 0); + x.dsp_rx_scale_iq = sr_addr(misc_output_base, x.sr_rx_dsp + 1); + x.dsp_rx_decim_rate = sr_addr(misc_output_base, x.sr_rx_dsp + 2); + x.dsp_rx_dcoffset_i = sr_addr(misc_output_base, x.sr_rx_dsp + 3); + x.dsp_rx_dcoffset_q = sr_addr(misc_output_base, x.sr_rx_dsp + 4); + x.dsp_rx_mux = sr_addr(misc_output_base, x.sr_rx_dsp + 5); + x.gpio_io = gpio_base + 0; + x.gpio_ddr = gpio_base + 4; + x.gpio_tx_sel = gpio_base + 8; + x.gpio_rx_sel = gpio_base + 12; + x.atr_idle_txside = atr_base + 0; + x.atr_idle_rxside = atr_base + 2; + x.atr_intx_txside = atr_base + 4; + x.atr_intx_rxside = atr_base + 6; + x.atr_inrx_txside = atr_base + 8; + x.atr_inrx_rxside = atr_base + 10; + x.atr_full_txside = atr_base + 12; + x.atr_full_rxside = atr_base + 14; + x.rx_ctrl_stream_cmd = sr_addr(misc_output_base, x.sr_rx_ctrl + 0); + x.rx_ctrl_time_secs = sr_addr(misc_output_base, x.sr_rx_ctrl + 1); + x.rx_ctrl_time_ticks = sr_addr(misc_output_base, x.sr_rx_ctrl + 2); + x.rx_ctrl_clear_overrun = sr_addr(misc_output_base, x.sr_rx_ctrl + 3); + x.rx_ctrl_vrt_header = sr_addr(misc_output_base, x.sr_rx_ctrl + 4); + x.rx_ctrl_vrt_stream_id = sr_addr(misc_output_base, x.sr_rx_ctrl + 5); + x.rx_ctrl_vrt_trailer = sr_addr(misc_output_base, x.sr_rx_ctrl + 6); + x.rx_ctrl_nsamps_per_pkt = sr_addr(misc_output_base, x.sr_rx_ctrl + 7); + x.rx_ctrl_nchannels = sr_addr(misc_output_base, x.sr_rx_ctrl + 8); + + return x; +} diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 1a5864c85..0ebce6a85 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -18,6 +18,88 @@ #ifndef INCLUDED_USRP2_REGS_HPP #define INCLUDED_USRP2_REGS_HPP +//these are used to set the + +#define USRP2_MISC_OUTPUT_BASE 0xD400 +#define USRP2_GPIO_BASE 0xC800 +#define USRP2_ATR_BASE 0xE400 +#define USRP2_BP_STATUS_BASE 0xCC00 + +#define USRP2P_MISC_OUTPUT_BASE 0x2000 +#define USRP2P_GPIO_BASE 0x3200 +#define USRP2P_ATR_BASE 0x3800 +#define USRP2P_BP_STATUS_BASE 0x3300 + +#define USRP2P_FIRST_HW_REV 0x0A00 + +typedef struct { + int sr_misc; + int sr_tx_prot_eng; + int sr_rx_prot_eng; + int sr_buffer_pool_ctrl; + int sr_udp_sm; + int sr_tx_dsp; + int sr_tx_ctrl; + int sr_rx_dsp; + int sr_rx_ctrl; + int sr_time64; + int sr_simtimer; + int sr_last; + int misc_ctrl_clock; + int misc_ctrl_serdes; + int misc_ctrl_adc; + int misc_ctrl_leds; + int misc_ctrl_phy; + int misc_ctrl_dbg_mux; + int misc_ctrl_ram_page; + int misc_ctrl_flush_icache; + int misc_ctrl_led_src; + int time64_secs; // value to set absolute secs to on next PPS + int time64_ticks; // value to set absolute ticks to on next PPS + int time64_flags; // flags -- see chart below + int time64_imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0) + int time64_tps; // ticks per second rollover count + int time64_secs_rb; + int time64_ticks_rb; + int dsp_tx_freq; + int dsp_tx_scale_iq; + int dsp_tx_interp_rate; + int dsp_tx_mux; + int dsp_rx_freq; + int dsp_rx_scale_iq; + int dsp_rx_decim_rate; + int dsp_rx_dcoffset_i; + int dsp_rx_dcoffset_q; + int dsp_rx_mux; + int gpio_base; + int gpio_io; + int gpio_ddr; + int gpio_tx_sel; + int gpio_rx_sel; + int atr_base; + int atr_idle_txside; + int atr_idle_rxside; + int atr_intx_txside; + int atr_intx_rxside; + int atr_inrx_txside; + int atr_inrx_rxside; + int atr_full_txside; + int atr_full_rxside; + int rx_ctrl_stream_cmd; + int rx_ctrl_time_secs; + int rx_ctrl_time_ticks; + int rx_ctrl_clear_overrun; + int rx_ctrl_vrt_header; + int rx_ctrl_vrt_stream_id; + int rx_ctrl_vrt_trailer; + int rx_ctrl_nsamps_per_pkt; + int rx_ctrl_nchannels; +} usrp2_regs_t; + +extern const usrp2_regs_t usrp2_regs; //the register definitions, set in usrp2_regs.cpp and usrp2p_regs.cpp + +usrp2_regs_t usrp2_get_regs(int hw_rev); + //////////////////////////////////////////////////// // Settings Bus, Slave #7, Not Byte Addressable! // @@ -25,27 +107,12 @@ // 1KB of address space (== 256 32-bit write-only regs) -#define MISC_OUTPUT_BASE 0xD400 +//#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) + (4*(sr))) - ///////////////////////////////////////////////// // SPI Slave Constants //////////////////////////////////////////////// @@ -58,20 +125,11 @@ #define SPI_SS_TX_DAC 32 #define SPI_SS_TX_ADC 64 #define SPI_SS_TX_DB 128 +#define SPI_SS_ADS62P44 256 //for usrp2p ///////////////////////////////////////////////// // Misc Control //////////////////////////////////////////////// -#define U2_REG_MISC_CTRL_CLOCK _SR_ADDR(0) -#define U2_REG_MISC_CTRL_SERDES _SR_ADDR(1) -#define U2_REG_MISC_CTRL_ADC _SR_ADDR(2) -#define U2_REG_MISC_CTRL_LEDS _SR_ADDR(3) -#define U2_REG_MISC_CTRL_PHY _SR_ADDR(4) // LSB is reset line to eth phy -#define U2_REG_MISC_CTRL_DBG_MUX _SR_ADDR(5) -#define U2_REG_MISC_CTRL_RAM_PAGE _SR_ADDR(6) // FIXME should go somewhere else... -#define U2_REG_MISC_CTRL_FLUSH_ICACHE _SR_ADDR(7) // Flush the icache -#define U2_REG_MISC_CTRL_LED_SRC _SR_ADDR(8) // HW or SW control for LEDs - #define U2_FLAG_MISC_CTRL_SERDES_ENABLE 8 #define U2_FLAG_MISC_CTRL_SERDES_PRBSEN 4 #define U2_FLAG_MISC_CTRL_SERDES_LOOPEN 2 @@ -99,14 +157,6 @@ * * </pre> */ -#define U2_REG_TIME64_SECS _SR_ADDR(SR_TIME64 + 0) // value to set absolute secs to on next PPS -#define U2_REG_TIME64_TICKS _SR_ADDR(SR_TIME64 + 1) // value to set absolute ticks to on next PPS -#define U2_REG_TIME64_FLAGS _SR_ADDR(SR_TIME64 + 2) // flags - see chart above -#define U2_REG_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) -#define U2_REG_TIME64_TPS _SR_ADDR(SR_TIME64 + 4) // the ticks per second rollover count - -#define U2_REG_TIME64_SECS_RB (0xCC00 + 4*10) -#define U2_REG_TIME64_TICKS_RB (0xCC00 + 4*11) //pps flags (see above) #define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0) @@ -120,9 +170,6 @@ ///////////////////////////////////////////////// // DSP TX Regs //////////////////////////////////////////////// -#define U2_REG_DSP_TX_FREQ _SR_ADDR(SR_TX_DSP + 0) -#define U2_REG_DSP_TX_SCALE_IQ _SR_ADDR(SR_TX_DSP + 1) // {scale_i,scale_q} -#define U2_REG_DSP_TX_INTERP_RATE _SR_ADDR(SR_TX_DSP + 2) /*! * \brief output mux configuration. @@ -158,17 +205,11 @@ * The default value is 0x10 * </pre> */ -#define U2_REG_DSP_TX_MUX _SR_ADDR(SR_TX_DSP + 4) ///////////////////////////////////////////////// // DSP RX Regs //////////////////////////////////////////////// -#define U2_REG_DSP_RX_FREQ _SR_ADDR(SR_RX_DSP + 0) -#define U2_REG_DSP_RX_SCALE_IQ _SR_ADDR(SR_RX_DSP + 1) // {scale_i,scale_q} -#define U2_REG_DSP_RX_DECIM_RATE _SR_ADDR(SR_RX_DSP + 2) -#define U2_REG_DSP_RX_DCOFFSET_I _SR_ADDR(SR_RX_DSP + 3) // Bit 31 high sets fixed offset mode, using lower 14 bits, - // otherwise it is automatic -#define U2_REG_DSP_RX_DCOFFSET_Q _SR_ADDR(SR_RX_DSP + 4) // Bit 31 high sets fixed offset mode, using lower 14 bits + /*! * \brief input mux configuration. * @@ -190,20 +231,10 @@ * The default value is 0x4 * </pre> */ -#define U2_REG_DSP_RX_MUX _SR_ADDR(SR_RX_DSP + 5) // called adc_mux in dsp_core_rx.v //////////////////////////////////////////////// // GPIO, Slave 4 //////////////////////////////////////////////// -// -// These go to the daughterboard i/o pins -// -#define U2_REG_GPIO_BASE 0xC800 - -#define U2_REG_GPIO_IO U2_REG_GPIO_BASE + 0 // 32 bits, gpio io pins (tx high 16 bits, rx low 16 bits) -#define U2_REG_GPIO_DDR U2_REG_GPIO_BASE + 4 // 32 bits, gpio ddr, 1 means output (tx high 16 bits, rx low 16 bits) -#define U2_REG_GPIO_TX_SEL U2_REG_GPIO_BASE + 8 // 16 2-bit fields select which source goes to TX DB -#define U2_REG_GPIO_RX_SEL U2_REG_GPIO_BASE + 12 // 16 2-bit fields select which source goes to RX DB // each 2-bit sel field is layed out this way #define U2_FLAG_GPIO_SEL_GPIO 0 // if pin is an output, set by GPIO register @@ -214,31 +245,11 @@ /////////////////////////////////////////////////// // ATR Controller, Slave 11 //////////////////////////////////////////////// -#define U2_REG_ATR_BASE 0xE400 -#define U2_REG_ATR_IDLE_TXSIDE U2_REG_ATR_BASE + 0 -#define U2_REG_ATR_IDLE_RXSIDE U2_REG_ATR_BASE + 2 -#define U2_REG_ATR_INTX_TXSIDE U2_REG_ATR_BASE + 4 -#define U2_REG_ATR_INTX_RXSIDE U2_REG_ATR_BASE + 6 -#define U2_REG_ATR_INRX_TXSIDE U2_REG_ATR_BASE + 8 -#define U2_REG_ATR_INRX_RXSIDE U2_REG_ATR_BASE + 10 -#define U2_REG_ATR_FULL_TXSIDE U2_REG_ATR_BASE + 12 -#define U2_REG_ATR_FULL_RXSIDE U2_REG_ATR_BASE + 14 /////////////////////////////////////////////////// // VITA RX CTRL regs /////////////////////////////////////////////////// -// The following 3 are logically a single command register. -// They are clocked into the underlying fifo when time_ticks is written. -#define U2_REG_RX_CTRL_STREAM_CMD _SR_ADDR(SR_RX_CTRL + 0) // {now, chain, num_samples(30) -#define U2_REG_RX_CTRL_TIME_SECS _SR_ADDR(SR_RX_CTRL + 1) -#define U2_REG_RX_CTRL_TIME_TICKS _SR_ADDR(SR_RX_CTRL + 2) - -#define U2_REG_RX_CTRL_CLEAR_OVERRUN _SR_ADDR(SR_RX_CTRL + 3) // write anything to clear overrun -#define U2_REG_RX_CTRL_VRT_HEADER _SR_ADDR(SR_RX_CTRL + 4) // word 0 of packet. FPGA fills in packet counter -#define U2_REG_RX_CTRL_VRT_STREAM_ID _SR_ADDR(SR_RX_CTRL + 5) // word 1 of packet. -#define U2_REG_RX_CTRL_VRT_TRAILER _SR_ADDR(SR_RX_CTRL + 6) -#define U2_REG_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7) -#define U2_REG_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources + #endif /* INCLUDED_USRP2_REGS_HPP */ |